From d40fed5ce2bc806a91245adb18039634eac13ed0 Mon Sep 17 00:00:00 2001 From: MichaelTheShifter Date: Wed, 20 Jul 2016 09:40:36 -0400 Subject: Move ShiftUI source code to ShiftOS This'll be a lot easier to work on. --- source/ShiftOS.sln | 6 + source/ShiftUI/Application.cs | 1123 +++ source/ShiftUI/ApplicationContext.cs | 119 + source/ShiftUI/Cursor.cs | 663 ++ source/ShiftUI/Design/Behavior/Adorner.cs | 81 + source/ShiftUI/Design/Behavior/Behavior.cs | 155 + .../Design/Behavior/BehaviorDragDropEventArgs.cs | 50 + .../Behavior/BehaviorDragDropEventHandler.cs | 36 + source/ShiftUI/Design/Behavior/BehaviorService.cs | 154 + .../Behavior/BehaviorServiceAdornerCollection.cs | 128 + .../BehaviorServiceAdornerCollectionEnumerator.cs | 90 + source/ShiftUI/Design/Behavior/ComponentGlyph.cs | 73 + source/ShiftUI/Design/Behavior/ControlBodyGlyph.cs | 70 + source/ShiftUI/Design/Behavior/Glyph.cs | 70 + source/ShiftUI/Design/Behavior/GlyphCollection.cs | 111 + .../ShiftUI/Design/Behavior/GlyphSelectionType.cs | 41 + source/ShiftUI/Design/Behavior/SnapLine.cs | 133 + source/ShiftUI/Design/Behavior/SnapLinePriority.cs | 42 + source/ShiftUI/Design/Behavior/SnapLineType.cs | 45 + source/ShiftUI/Design/ComponentDesigner.cs | 438 + source/ShiftUI/Design/ComponentEditorForm.cs | 96 + source/ShiftUI/Design/ComponentEditorPage.cs | 210 + source/ShiftUI/Design/ComponentTray.cs | 247 + source/ShiftUI/Design/Consts.cs | 100 + source/ShiftUI/Design/ControlDataObject.cs | 120 + source/ShiftUI/Design/ControlDesigner.cs | 974 +++ source/ShiftUI/Design/DefaultMenuCommands.cs | 274 + source/ShiftUI/Design/DocumentDesigner.cs | 485 ++ source/ShiftUI/Design/EventsTab.cs | 101 + source/ShiftUI/Design/FormDocumentDesigner.cs | 86 + source/ShiftUI/Design/IMenuEditorService.cs | 34 + source/ShiftUI/Design/IMessageReceiver.cs | 39 + source/ShiftUI/Design/IUISelectionService.cs | 71 + source/ShiftUI/Design/IUIService.cs | 52 + .../ShiftUI/Design/IWindowsFormsEditorService.cs | 35 + source/ShiftUI/Design/Native.cs | 216 + source/ShiftUI/Design/ParentControlDesigner.cs | 726 ++ source/ShiftUI/Design/PropertyTab.cs | 102 + source/ShiftUI/Design/ScrollableControlDesigner.cs | 83 + source/ShiftUI/Design/SelectionFrame.cs | 481 ++ source/ShiftUI/Design/SelectionRules.cs | 47 + .../Design/ToolStripItemDesignerAvailability.cs | 43 + .../ToolStripItemDesignerAvailabilityAttribute.cs | 81 + source/ShiftUI/Design/UISelectionService.cs | 532 ++ .../ShiftUI/Design/WindowsFormsComponentEditor.cs | 65 + source/ShiftUI/Design/WndProcRouter.cs | 117 + source/ShiftUI/Dialogs/StringArrayDialog.cs | 558 ++ source/ShiftUI/Dialogs/ThreadExceptionDialog.cs | 233 + source/ShiftUI/Enums/AccessibleEvents.cs | 74 + source/ShiftUI/Enums/AccessibleNavigation.cs | 39 + source/ShiftUI/Enums/AccessibleObject.cs | 561 ++ source/ShiftUI/Enums/AccessibleRole.cs | 98 + source/ShiftUI/Enums/AccessibleSelection.cs | 40 + source/ShiftUI/Enums/AccessibleStates.cs | 70 + source/ShiftUI/Enums/AmbientProperties.cs | 87 + source/ShiftUI/Enums/AnchorStyles.cs | 41 + source/ShiftUI/Enums/Appearance.cs | 37 + source/ShiftUI/Enums/ArrangeDirection.cs | 41 + source/ShiftUI/Enums/ArrangeStartingPosition.cs | 39 + source/ShiftUI/Enums/ArrowDirection.cs | 39 + source/ShiftUI/Enums/AutoCompleteMode.cs | 38 + source/ShiftUI/Enums/AutoScaleMode.cs | 34 + source/ShiftUI/Enums/AutoSizeMode.cs | 37 + source/ShiftUI/Enums/AutoValidate.cs | 39 + source/ShiftUI/Enums/BatteryChargeStatus.cs | 42 + source/ShiftUI/Enums/BindingCompleteState.cs | 38 + source/ShiftUI/Enums/Border3DSide.cs | 42 + source/ShiftUI/Enums/Border3DStyle.cs | 45 + source/ShiftUI/Enums/BorderStyle.cs | 37 + source/ShiftUI/Enums/ButtonBorderStyle.cs | 38 + source/ShiftUI/Enums/ButtonState.cs | 41 + source/ShiftUI/Enums/CharacterCasing.cs | 35 + source/ShiftUI/Enums/CheckState.cs | 34 + source/ShiftUI/Enums/CloseReason.cs | 42 + source/ShiftUI/Enums/ColorDepth.cs | 37 + source/ShiftUI/Enums/ComboBoxStyle.cs | 37 + source/ShiftUI/Enums/ControlStyles.cs | 58 + source/ShiftUI/Enums/ControlUpdateMode.cs | 37 + source/ShiftUI/Enums/CreateParams.cs | 171 + source/ShiftUI/Enums/DataFormats.cs | 229 + source/ShiftUI/Enums/DataSourceUpdateMode.cs | 38 + source/ShiftUI/Enums/DateTimePickerFormat.cs | 33 + source/ShiftUI/Enums/DialogResult.cs | 46 + source/ShiftUI/Enums/DockStyle.cs | 41 + source/ShiftUI/Enums/DragAction.cs | 39 + source/ShiftUI/Enums/DragDropEffects.cs | 42 + source/ShiftUI/Enums/DrawItemState.cs | 44 + source/ShiftUI/Enums/DrawMode.cs | 36 + source/ShiftUI/Enums/FlatButtonAppearance.cs | 165 + source/ShiftUI/Enums/FlatStyle.cs | 36 + source/ShiftUI/Enums/FlowDirection.cs | 39 + source/ShiftUI/Enums/FormBorderStyle.cs | 42 + source/ShiftUI/Enums/FrameStyle.cs | 34 + source/ShiftUI/Enums/HorizontalAlignment.cs | 37 + source/ShiftUI/Enums/ImageLayout.cs | 37 + source/ShiftUI/Enums/ImeMode.cs | 48 + source/ShiftUI/Enums/ItemActivation.cs | 39 + source/ShiftUI/Enums/ItemBoundsPortion.cs | 36 + source/ShiftUI/Enums/Keys.cs | 235 + source/ShiftUI/Enums/LeftRightAlignment.cs | 37 + source/ShiftUI/Enums/ListViewAlignment.cs | 36 + source/ShiftUI/Enums/MergeAction.cs | 40 + source/ShiftUI/Enums/MessageBoxButtons.cs | 43 + source/ShiftUI/Enums/MouseButtons.cs | 17 + source/ShiftUI/Enums/Orientation.cs | 39 + source/ShiftUI/Enums/PowerLineStatus.cs | 38 + source/ShiftUI/Enums/PowerState.cs | 37 + source/ShiftUI/Enums/PowerStatus.cs | 72 + source/ShiftUI/Enums/PreProcessControlState.cs | 38 + source/ShiftUI/Enums/ProgressBarStyle.cs | 35 + source/ShiftUI/Enums/RichTextBoxLanguageOptions.cs | 43 + source/ShiftUI/Enums/RichTextBoxSelectionTypes.cs | 38 + source/ShiftUI/Enums/RichTextBoxStreamType.cs | 37 + source/ShiftUI/Enums/RightToLeft.cs | 36 + source/ShiftUI/Enums/RowStyle.cs | 71 + source/ShiftUI/Enums/ScreenOrientation.cs | 39 + source/ShiftUI/Enums/ScrollBars.cs | 36 + source/ShiftUI/Enums/ScrollOrientation.cs | 37 + source/ShiftUI/Enums/SearchDirectionHint.cs | 39 + source/ShiftUI/Enums/SelectionMode.cs | 42 + source/ShiftUI/Enums/SelectionRange.cs | 103 + source/ShiftUI/Enums/Shortcut.cs | 191 + source/ShiftUI/Enums/SizeType.cs | 33 + source/ShiftUI/Enums/SortOrder.cs | 37 + source/ShiftUI/Enums/StatusBarPanelAutoSize.cs | 33 + source/ShiftUI/Enums/StatusBarPanelBorderStyle.cs | 33 + source/ShiftUI/Enums/StatusBarPanelStyle.cs | 33 + source/ShiftUI/Enums/TabAlignment.cs | 35 + source/ShiftUI/Enums/TabAppearance.cs | 34 + source/ShiftUI/Enums/TabControlAction.cs | 39 + source/ShiftUI/Enums/TabDrawMode.cs | 33 + source/ShiftUI/Enums/TabSizeMode.cs | 34 + source/ShiftUI/Enums/TextDataFormat.cs | 40 + source/ShiftUI/Enums/TextImageRelation.cs | 40 + source/ShiftUI/Enums/TickStyle.cs | 40 + source/ShiftUI/Enums/TreeNodeStates.cs | 45 + source/ShiftUI/Enums/TreeViewAction.cs | 35 + source/ShiftUI/Enums/TreeViewDrawMode.cs | 38 + source/ShiftUI/Enums/TreeViewHitTestLocations.cs | 50 + source/ShiftUI/Enums/UnhandledExceptionMode.cs | 38 + source/ShiftUI/Enums/ValidationConstraints.cs | 42 + source/ShiftUI/Enums/View.cs | 37 + source/ShiftUI/Events/AccessibleEvents.cs | 74 + source/ShiftUI/Events/BindingCompleteEventArgs.cs | 101 + .../ShiftUI/Events/BindingCompleteEventHandler.cs | 32 + .../Events/BindingManagerDataErrorEventArgs.cs | 50 + .../Events/BindingManagerDataErrorEventHandler.cs | 32 + .../ShiftUI/Events/CacheVirtualItemsEventArgs.cs | 56 + .../Events/CacheVirtualItemsEventHandler.cs | 32 + source/ShiftUI/Events/ContentsResizedEventArgs.cs | 52 + .../ShiftUI/Events/ContentsResizedEventHandler.cs | 31 + source/ShiftUI/Events/ConvertEventArgs.cs | 61 + source/ShiftUI/Events/ConvertEventHandler.cs | 31 + source/ShiftUI/Events/DateBoldEventArgs.cs | 70 + source/ShiftUI/Events/DateBoldEventHandler.cs | 31 + source/ShiftUI/Events/DateRangeEventArgs.cs | 67 + source/ShiftUI/Events/DateRangeEventHandler.cs | 31 + source/ShiftUI/Events/DrawItemEventArgs.cs | 101 + source/ShiftUI/Events/DrawItemEventHandler.cs | 31 + .../Events/DrawListViewColumnHeaderEventArgs.cs | 133 + .../Events/DrawListViewColumnHeaderEventHandler.cs | 31 + source/ShiftUI/Events/DrawListViewItemEventArgs.cs | 116 + .../ShiftUI/Events/DrawListViewItemEventHandler.cs | 31 + .../ShiftUI/Events/DrawListViewSubItemEventArgs.cs | 140 + .../Events/DrawListViewSubItemEventHandler.cs | 31 + source/ShiftUI/Events/DrawTreeNodeEventArgs.cs | 80 + source/ShiftUI/Events/DrawTreeNodeEventHandler.cs | 33 + source/ShiftUI/Events/GiveFeedbackEventArgs.cs | 63 + source/ShiftUI/Events/GiveFeedbackEventHandler.cs | 32 + source/ShiftUI/Events/HelpEventArgs.cs | 65 + source/ShiftUI/Events/HelpEventHandler.cs | 30 + .../Events/InputLanguageChangedEventArgs.cs | 73 + .../Events/InputLanguageChangedEventHandler.cs | 31 + .../Events/InputLanguageChangingEventArgs.cs | 74 + .../Events/InputLanguageChangingEventHandler.cs | 31 + source/ShiftUI/Events/InvalidateEventArgs.cs | 50 + source/ShiftUI/Events/InvalidateEventHandler.cs | 32 + source/ShiftUI/Events/ItemChangedEventArgs.cs | 50 + source/ShiftUI/Events/ItemChangedEventHandler.cs | 33 + source/ShiftUI/Events/ItemCheckEventArgs.cs | 65 + source/ShiftUI/Events/ItemCheckEventHandler.cs | 33 + source/ShiftUI/Events/ItemCheckedEventArgs.cs | 49 + source/ShiftUI/Events/ItemCheckedEventHandler.cs | 32 + source/ShiftUI/Events/ItemDragEventArgs.cs | 63 + source/ShiftUI/Events/ItemDragEventHandler.cs | 33 + source/ShiftUI/Events/LabelEditEventArgs.cs | 73 + source/ShiftUI/Events/LabelEditEventHandler.cs | 34 + source/ShiftUI/Events/LayoutEventArgs.cs | 70 + source/ShiftUI/Events/LayoutEventHandler.cs | 32 + .../ShiftUI/Events/ListControlConvertEventArgs.cs | 50 + .../Events/ListControlConvertEventHandler.cs | 32 + source/ShiftUI/Events/MeasureItemEventArgs.cs | 77 + source/ShiftUI/Events/MeasureItemEventHandler.cs | 30 + source/ShiftUI/Events/NodeLabelEditEventArgs.cs | 71 + source/ShiftUI/Events/NodeLabelEditEventHandler.cs | 33 + source/ShiftUI/Events/PreviewKeyDownEventArgs.cs | 79 + .../ShiftUI/Events/PreviewKeyDownEventHandler.cs | 32 + .../Events/QueryAccessibilityHelpEventArgs.cs | 85 + .../Events/QueryAccessibilityHelpEventHandler.cs | 31 + .../ShiftUI/Events/QueryContinueDragEventArgs.cs | 72 + .../Events/QueryContinueDragEventHandler.cs | 31 + .../ShiftUI/Events/RetrieveVirtualItemEventArgs.cs | 55 + .../Events/RetrieveVirtualItemEventHandler.cs | 32 + source/ShiftUI/Events/ScrollEventArgs.cs | 95 + source/ShiftUI/Events/ScrollEventHandler.cs | 31 + source/ShiftUI/Events/ScrollEventType.cs | 44 + .../Events/SearchForVirtualItemEventArgs.cs | 97 + .../Events/SearchForVirtualItemEventHandler.cs | 32 + source/ShiftUI/Events/SplitterCancelEventArgs.cs | 70 + .../ShiftUI/Events/SplitterCancelEventHandler.cs | 32 + source/ShiftUI/Events/SplitterEventArgs.cs | 79 + source/ShiftUI/Events/SplitterEventHandler.cs | 32 + .../ShiftUI/Events/StatusBarDrawItemEventArgs.cs | 57 + .../Events/StatusBarDrawItemEventHandler.cs | 36 + .../ShiftUI/Events/StatusBarPanelClickEventArgs.cs | 46 + .../Events/StatusBarPanelClickEventHandler.cs | 32 + source/ShiftUI/Events/TabControlCancelEventArgs.cs | 63 + .../ShiftUI/Events/TabControlCancelEventHandler.cs | 32 + source/ShiftUI/Events/TabControlEventArgs.cs | 64 + source/ShiftUI/Events/TabControlEventHandler.cs | 32 + .../Events/TableLayoutCellPaintEventArgs.cs | 64 + .../Events/TableLayoutCellPaintEventHandler.cs | 32 + .../Events/TableLayoutColumnStyleCollection.cs | 75 + .../ShiftUI/Events/TableLayoutControlCollection.cs | 66 + .../Events/TableLayoutPanelCellBorderStyle.cs | 42 + .../ShiftUI/Events/TableLayoutPanelCellPosition.cs | 99 + source/ShiftUI/Events/TableLayoutPanelGrowStyle.cs | 33 + .../Events/TableLayoutRowStyleCollection.cs | 75 + source/ShiftUI/Events/TableLayoutStyle.cs | 62 + .../ShiftUI/Events/TableLayoutStyleCollection.cs | 178 + .../ShiftUI/Events/TreeNodeMouseClickEventArgs.cs | 49 + .../Events/TreeNodeMouseClickEventHandler.cs | 32 + .../ShiftUI/Events/TreeNodeMouseHoverEventArgs.cs | 52 + .../Events/TreeNodeMouseHoverEventHandler.cs | 32 + source/ShiftUI/Events/TreeViewCancelEventArgs.cs | 52 + .../ShiftUI/Events/TreeViewCancelEventHandler.cs | 31 + source/ShiftUI/Events/TreeViewEventArgs.cs | 52 + source/ShiftUI/Events/TreeViewEventHandler.cs | 30 + source/ShiftUI/Events/UICues.cs | 42 + source/ShiftUI/Events/UICuesEventArgs.cs | 88 + source/ShiftUI/Events/UICuesEventHandler.cs | 33 + source/ShiftUI/Form/Form.cs | 3491 ++++++++ source/ShiftUI/Form/FormClosedEventArgs.cs | 49 + source/ShiftUI/Form/FormClosedEventHandler.cs | 32 + source/ShiftUI/Form/FormClosingEventArgs.cs | 51 + source/ShiftUI/Form/FormClosingEventHandler.cs | 32 + source/ShiftUI/Form/FormCollection.cs | 73 + source/ShiftUI/Form/FormStartPosition.cs | 39 + source/ShiftUI/Form/FormWindowManager.cs | 87 + source/ShiftUI/Form/FormWindowState.cs | 38 + source/ShiftUI/Form/MessageBox.cs | 66 + source/ShiftUI/Internal/ApplicationHandler.cs | 78 + .../ShiftUI/Internal/ArrangedElementCollection.cs | 173 + source/ShiftUI/Internal/AsyncMethodData.cs | 41 + source/ShiftUI/Internal/AsyncMethodResult.cs | 108 + source/ShiftUI/Internal/AutoCompleteSource.cs | 44 + .../Internal/AutoCompleteStringCollection.cs | 203 + source/ShiftUI/Internal/BaseCollection.cs | 99 + source/ShiftUI/Internal/Binding.cs | 578 ++ source/ShiftUI/Internal/BindingCompleteContext.cs | 37 + source/ShiftUI/Internal/BindingContext.cs | 257 + source/ShiftUI/Internal/BindingManagerBase.cs | 204 + source/ShiftUI/Internal/BindingMemberInfo.cs | 107 + source/ShiftUI/Internal/BindingsCollection.cs | 136 + source/ShiftUI/Internal/BootMode.cs | 39 + source/ShiftUI/Internal/BoundsSpecified.cs | 43 + source/ShiftUI/Internal/ButtonBase.cs | 747 ++ source/ShiftUI/Internal/ButtonRenderer.cs | 153 + source/ShiftUI/Internal/CheckBoxRenderer.cs | 194 + source/ShiftUI/Internal/Clipboard.cs | 433 + source/ShiftUI/Internal/Consts.cs | 0 source/ShiftUI/Internal/ContextMenuStrip.cs | 80 + .../ShiftUI/Internal/ControlBindingsCollection.cs | 204 + source/ShiftUI/Internal/ControlEventArgs.cs | 49 + source/ShiftUI/Internal/ControlEventHandler.cs | 32 + source/ShiftUI/Internal/ControlHandler.cs | 229 + source/ShiftUI/Internal/ControlPaint.cs | 495 ++ source/ShiftUI/Internal/CurrencyManager.cs | 453 ++ source/ShiftUI/Internal/Cursor.cs | 245 + source/ShiftUI/Internal/CursorConverter.cs | 126 + source/ShiftUI/Internal/Cursors.cs | 365 + source/ShiftUI/Internal/DataObject.cs | 485 ++ source/ShiftUI/Internal/Day.cs | 39 + source/ShiftUI/Internal/DebugHelper.cs | 257 + source/ShiftUI/Internal/DefaultLayout.cs | 290 + source/ShiftUI/Internal/Dnd.cs | 371 + source/ShiftUI/Internal/DockingAttribute.cs | 74 + source/ShiftUI/Internal/DockingBehavior.cs | 38 + source/ShiftUI/Internal/DrawToolTipEventArgs.cs | 113 + source/ShiftUI/Internal/DrawToolTipEventHandler.cs | 31 + source/ShiftUI/Internal/Enums.cs | 108 + source/ShiftUI/Internal/EventHandler.cs | 184 + source/ShiftUI/Internal/EventHandlerBase.cs | 40 + source/ShiftUI/Internal/FixedSizeTextBox.cs | 47 + source/ShiftUI/Internal/FlowLayout.cs | 589 ++ source/ShiftUI/Internal/FlowLayoutSettings.cs | 111 + source/ShiftUI/Internal/GetChildAtPointSkip.cs | 41 + source/ShiftUI/Internal/GridItem.cs | 114 + source/ShiftUI/Internal/GridItemType.cs | 38 + source/ShiftUI/Internal/GroupBoxRenderer.cs | 157 + source/ShiftUI/Internal/HIObjectHandler.cs | 57 + source/ShiftUI/Internal/HScrollProperties.cs | 33 + source/ShiftUI/Internal/Hwnd.cs | 910 +++ source/ShiftUI/Internal/IBindableComponent.cs | 34 + source/ShiftUI/Internal/IBounds.cs | 40 + source/ShiftUI/Internal/IButtonControl.cs | 40 + source/ShiftUI/Internal/ICommandExecutor.cs | 34 + .../ShiftUI/Internal/IComponentEditorPageSite.cs | 34 + source/ShiftUI/Internal/IContainerControl.cs | 39 + .../ShiftUI/Internal/ICurrencyManagerProvider.cs | 32 + ...ataGridColumnStyleEditingNotificationService.cs | 35 + source/ShiftUI/Internal/IDataGridEditingService.cs | 36 + .../ShiftUI/Internal/IDataGridViewEditingCell.cs | 41 + .../Internal/IDataGridViewEditingControl.cs | 53 + source/ShiftUI/Internal/IDataObject.cs | 54 + source/ShiftUI/Internal/IDropTarget.cs | 36 + source/ShiftUI/Internal/IEventHandler.cs | 33 + source/ShiftUI/Internal/IFeatureSupport.cs | 38 + source/ShiftUI/Internal/IFileReaderService.cs | 37 + source/ShiftUI/Internal/IKeyFilter.cs | 32 + source/ShiftUI/Internal/IMessageFilter.cs | 34 + source/ShiftUI/Internal/IToolStripData.cs | 41 + source/ShiftUI/Internal/IWin32Window.cs | 44 + source/ShiftUI/Internal/IWindowTarget.cs | 34 + source/ShiftUI/Internal/ImageIndexConverter.cs | 102 + source/ShiftUI/Internal/ImageKeyConverter.cs | 97 + source/ShiftUI/Internal/ImageList.cs | 1073 +++ source/ShiftUI/Internal/ImageListConverter.cs | 44 + source/ShiftUI/Internal/ImageListStreamer.cs | 338 + source/ShiftUI/Internal/InternalWindowManager.cs | 1211 +++ source/ShiftUI/Internal/KeyboardHandler.cs | 329 + source/ShiftUI/Internal/KeysConverter.cs | 139 + source/ShiftUI/Internal/LayoutEngine.cs | 43 + source/ShiftUI/Internal/LayoutSettings.cs | 40 + source/ShiftUI/Internal/Line.cs | 811 ++ source/ShiftUI/Internal/LineTag.cs | 618 ++ source/ShiftUI/Internal/ListBindingConverter.cs | 60 + source/ShiftUI/Internal/ListBindingHelper.cs | 189 + source/ShiftUI/Internal/MONO-NOTES | 28 + source/ShiftUI/Internal/MONO-TODO | 112 + source/ShiftUI/Internal/MWFCategoryAttribute.cs | 50 + source/ShiftUI/Internal/MWFDescriptionAttribute.cs | 51 + source/ShiftUI/Internal/MainMenu.cs | 216 + source/ShiftUI/Internal/MdiClient.cs | 1003 +++ source/ShiftUI/Internal/MdiControlStrip.cs | 207 + source/ShiftUI/Internal/MdiLayout.cs | 36 + source/ShiftUI/Internal/MdiWindowManager.cs | 624 ++ source/ShiftUI/Internal/Message.cs | 118 + source/ShiftUI/Internal/MethodInvoker.cs | 31 + source/ShiftUI/Internal/MouseHandler.cs | 228 + source/ShiftUI/Internal/NativeWindow.cs | 324 + source/ShiftUI/Internal/OpacityConverter.cs | 74 + source/ShiftUI/Internal/OpenTreeNodeEnumerator.cs | 112 + source/ShiftUI/Internal/OwnerDrawPropertyBag.cs | 101 + source/ShiftUI/Internal/Padding.cs | 170 + source/ShiftUI/Internal/PaddingConverter.cs | 125 + source/ShiftUI/Internal/PaintEventArgs.cs | 98 + source/ShiftUI/Internal/PaintEventHandler.cs | 33 + source/ShiftUI/Internal/Pasteboard.cs | 106 + source/ShiftUI/Internal/PopupEventArgs.cs | 71 + source/ShiftUI/Internal/PopupEventHandler.cs | 32 + source/ShiftUI/Internal/PreProcessControlState.cs | 38 + source/ShiftUI/Internal/ProfessionalColorTable.cs | 654 ++ source/ShiftUI/Internal/PropertyManager.cs | 166 + source/ShiftUI/Internal/PropertySort.cs | 40 + .../Internal/PropertyTabChangedEventArgs.cs | 66 + .../Internal/PropertyTabChangedEventHandler.cs | 33 + .../Internal/PropertyValueChangedEventArgs.cs | 66 + .../Internal/PropertyValueChangedEventHandler.cs | 31 + source/ShiftUI/Internal/RadioButtonRenderer.cs | 182 + source/ShiftUI/Internal/RelatedCurrencyManager.cs | 54 + .../ShiftUI/Internal/RelatedImageListAttribute.cs | 48 + source/ShiftUI/Internal/RelatedPropertyManager.cs | 67 + source/ShiftUI/Internal/RichTextBoxFinds.cs | 39 + source/ShiftUI/Internal/RichTextBoxScrollBars.cs | 39 + source/ShiftUI/Internal/SUI_NOTES.txt | 3 + source/ShiftUI/Internal/Screen.cs | 221 + source/ShiftUI/Internal/ScrollProperties.cs | 97 + .../Internal/SelectedGridItemChangedEventArgs.cs | 65 + .../SelectedGridItemChangedEventHandler.cs | 31 + source/ShiftUI/Internal/SelectionRangeConverter.cs | 110 + source/ShiftUI/Internal/Splitter.cs | 707 ++ source/ShiftUI/Internal/Structs.cs | 157 + source/ShiftUI/Internal/SystemInformation.cs | 611 ++ source/ShiftUI/Internal/SystemParameter.cs | 49 + source/ShiftUI/Internal/TableLayout.cs | 603 ++ source/ShiftUI/Internal/TableLayoutSettings.cs | 362 + .../Internal/TableLayoutSettingsTypeConverter.cs | 233 + source/ShiftUI/Internal/TextBoxTextRenderer.cs | 131 + source/ShiftUI/Internal/TextControl.cs | 4613 +++++++++++ source/ShiftUI/Internal/TextFormatFlags.cs | 62 + source/ShiftUI/Internal/TextRenderer.cs | 527 ++ source/ShiftUI/Internal/Theme.cs | 1063 +++ source/ShiftUI/Internal/Timer.cs | 170 + source/ShiftUI/Internal/ToolBarAppearance.cs | 40 + source/ShiftUI/Internal/ToolBarButtonStyle.cs | 41 + source/ShiftUI/Internal/ToolBarTextAlign.cs | 39 + source/ShiftUI/Internal/ToolTip.cs | 1004 +++ source/ShiftUI/Internal/ToolTipIcon.cs | 39 + source/ShiftUI/Internal/ToolWindowManager.cs | 47 + source/ShiftUI/Internal/TreeNodeCollection.cs | 611 ++ source/ShiftUI/Internal/TreeNodeConverter.cs | 55 + source/ShiftUI/Internal/TreeViewHitTestInfo.cs | 51 + .../Internal/TreeViewImageIndexConverter.cs | 89 + .../ShiftUI/Internal/TreeViewImageKeyConverter.cs | 51 + source/ShiftUI/Internal/VScrollProperties.cs | 33 + source/ShiftUI/Internal/Win32DnD.cs | 1081 +++ source/ShiftUI/Internal/WindowHandler.cs | 235 + .../Internal/WindowsFormsSynchronizationContext.cs | 94 + source/ShiftUI/Internal/X11Atoms.cs | 329 + source/ShiftUI/Internal/X11Clipboard.cs | 105 + source/ShiftUI/Internal/X11DesktopColors.cs | 298 + source/ShiftUI/Internal/X11Display.cs | 2693 +++++++ source/ShiftUI/Internal/X11Dnd.cs | 1421 ++++ source/ShiftUI/Internal/X11Exception.cs | 87 + source/ShiftUI/Internal/X11Hwnd.cs | 1750 ++++ source/ShiftUI/Internal/X11Keyboard.cs | 1478 ++++ source/ShiftUI/Internal/X11RootHwnd.cs | 87 + source/ShiftUI/Internal/X11Structs.cs | 1824 +++++ source/ShiftUI/Internal/X11ThreadQueue.cs | 502 ++ source/ShiftUI/Internal/XEventQueue.cs | 261 + source/ShiftUI/Internal/Xlib.cs | 350 + source/ShiftUI/Internal/XplatUI.cs | 1235 +++ source/ShiftUI/Internal/XplatUICarbon.cs | 2432 ++++++ source/ShiftUI/Internal/XplatUICosmos.cs | 2916 +++++++ source/ShiftUI/Internal/XplatUIDriver.cs | 532 ++ source/ShiftUI/Internal/XplatUIStructs.cs | 1042 +++ source/ShiftUI/Internal/XplatUIWin32.cs | 3751 +++++++++ source/ShiftUI/Internal/XplatUIX11-new.cs | 1079 +++ source/ShiftUI/Internal/XplatUIX11.cs | 7687 ++++++++++++++++++ source/ShiftUI/Internal/XplatUIX11GTK.cs | 4634 +++++++++++ source/ShiftUI/Keyboard/InputLanguage.cs | 134 + source/ShiftUI/Keyboard/InputLanguageCollection.cs | 77 + source/ShiftUI/Keyboard/KeyEventArgs.cs | 123 + source/ShiftUI/Keyboard/KeyEventHandler.cs | 33 + source/ShiftUI/Keyboard/KeyPressEventArgs.cs | 68 + source/ShiftUI/Keyboard/KeyPressEventHandler.cs | 31 + source/ShiftUI/Keyboard/KeyboardLayouts.cs | 149 + source/ShiftUI/Keyboard/ResXResourceWriter.cs | 667 ++ source/ShiftUI/Keyboard/create-keyboards.cs | 2079 +++++ source/ShiftUI/Link/LinkArea.cs | 183 + source/ShiftUI/Link/LinkBehavior.cs | 39 + source/ShiftUI/Link/LinkClickedEventArgs.cs | 49 + source/ShiftUI/Link/LinkClickedEventHandler.cs | 33 + source/ShiftUI/Link/LinkConverter.cs | 86 + .../ShiftUI/Link/LinkLabelLinkClickedEventArgs.cs | 58 + .../Link/LinkLabelLinkClickedEventHandler.cs | 38 + source/ShiftUI/Link/LinkState.cs | 41 + source/ShiftUI/ListView/ColumnClickEventArgs.cs | 52 + source/ShiftUI/ListView/ColumnClickEventHandler.cs | 29 + source/ShiftUI/ListView/ColumnHeader.cs | 398 + .../ListView/ColumnHeaderAutoResizeStyle.cs | 38 + source/ShiftUI/ListView/ColumnHeaderConverter.cs | 96 + source/ShiftUI/ListView/ColumnHeaderStyle.cs | 36 + .../ShiftUI/ListView/ColumnReorderedEventArgs.cs | 64 + .../ListView/ColumnReorderedEventHandler.cs | 32 + source/ShiftUI/ListView/ColumnStyle.cs | 72 + .../ListView/ColumnWidthChangedEventArgs.cs | 50 + .../ListView/ColumnWidthChangedEventHandler.cs | 32 + .../ListView/ColumnWidthChangingEventArgs.cs | 61 + .../ListView/ColumnWidthChangingEventHandler.cs | 32 + source/ShiftUI/ListView/ListViewAlignment.cs | 36 + source/ShiftUI/ListView/ListViewGroup.cs | 265 + source/ShiftUI/ListView/ListViewGroupCollection.cs | 332 + source/ShiftUI/ListView/ListViewHitTestInfo.cs | 62 + .../ShiftUI/ListView/ListViewHitTestLocations.cs | 44 + source/ShiftUI/ListView/ListViewInsertionMark.cs | 152 + source/ShiftUI/ListView/ListViewItemConverter.cs | 97 + .../ListView/ListViewItemMouseHoverEventArgs.cs | 53 + .../ListView/ListViewItemMouseHoverEventHandler.cs | 32 + .../ListViewItemSelectionChangedEventArgs.cs | 61 + .../ListViewItemSelectionChangedEventHandler.cs | 32 + source/ShiftUI/ListView/ListViewItemStates.cs | 45 + ...ewVirtualItemsSelectionRangeChangedEventArgs.cs | 61 + ...irtualItemsSelectionRangeChangedEventHandler.cs | 32 + source/ShiftUI/Menu/Menu.cs | 621 ++ source/ShiftUI/Menu/MenuAPI.cs | 836 ++ source/ShiftUI/Menu/MenuGlyph.cs | 36 + source/ShiftUI/Menu/MenuItem.cs | 912 +++ source/ShiftUI/Menu/MenuMerge.cs | 38 + source/ShiftUI/Menu/MenuStrip.cs | 349 + source/ShiftUI/MonoTODOAttribute.cs | 120 + source/ShiftUI/Mouse/DragAction.cs | 39 + source/ShiftUI/Mouse/DragDropEffects.cs | 41 + source/ShiftUI/Mouse/DragEventArgs.cs | 96 + source/ShiftUI/Mouse/DragEventHandler.cs | 31 + source/ShiftUI/Mouse/MouseEventArgs.cs | 90 + source/ShiftUI/Mouse/MouseEventHandler.cs | 32 + source/ShiftUI/Properties/AssemblyInfo.cs | 30 + source/ShiftUI/Properties/Resources.Designer.cs | 143 + source/ShiftUI/Properties/Resources.resx | 145 + source/ShiftUI/RTF/Charcode.cs | 413 + source/ShiftUI/RTF/Charset.cs | 157 + source/ShiftUI/RTF/CharsetFlags.cs | 42 + source/ShiftUI/RTF/CharsetType.cs | 40 + source/ShiftUI/RTF/ClassDelegate.cs | 61 + source/ShiftUI/RTF/Color.cs | 133 + source/ShiftUI/RTF/DestinationDelegate.cs | 61 + source/ShiftUI/RTF/Font.cs | 209 + source/ShiftUI/RTF/KeyStruct.cs | 46 + source/ShiftUI/RTF/KeysInit.cs | 720 ++ source/ShiftUI/RTF/Major.cs | 73 + source/ShiftUI/RTF/Minor.cs | 769 ++ source/ShiftUI/RTF/Picture.cs | 149 + source/ShiftUI/RTF/README | 7 + source/ShiftUI/RTF/RTF.cs | 1056 +++ source/ShiftUI/RTF/RTFException.cs | 87 + source/ShiftUI/RTF/StandardCharCode.cs | 392 + source/ShiftUI/RTF/StandardCharName.cs | 411 + source/ShiftUI/RTF/Style.cs | 211 + source/ShiftUI/RTF/StyleElement.cs | 122 + source/ShiftUI/RTF/StyleType.cs | 41 + source/ShiftUI/RTF/TextMap.cs | 440 ++ source/ShiftUI/RTF/TokenClass.cs | 45 + source/ShiftUI/RTF/rtf.csproj | 200 + source/ShiftUI/RTF/test.cs | 285 + source/ShiftUI/Resources/DnDCopy.cur | Bin 0 -> 326 bytes source/ShiftUI/Resources/DnDLink.cur | Bin 0 -> 326 bytes source/ShiftUI/Resources/DnDMove.cur | Bin 0 -> 326 bytes source/ShiftUI/Resources/DnDNo.cur | Bin 0 -> 326 bytes source/ShiftUI/Resources/NESW.cur | Bin 0 -> 326 bytes source/ShiftUI/Resources/NWSE.cur | Bin 0 -> 326 bytes source/ShiftUI/Resources/SplitterNS.cur | Bin 0 -> 326 bytes source/ShiftUI/Resources/SplitterWE.cur | Bin 0 -> 326 bytes source/ShiftUI/Resources/keyboard_table.bin | 1 + source/ShiftUI/Resources/scan_table.bin | 10 + source/ShiftUI/Resources/vkey_table.txt | 33 + source/ShiftUI/ScrollableControl.cs | 1024 +++ source/ShiftUI/ShiftUI.csproj | 978 +++ .../BackgroundType.cs | 37 + .../BooleanProperty.cs | 47 + .../BorderType.cs | 37 + .../CheckBoxState.cs | 46 + .../ColorProperty.cs | 57 + .../ComboBoxState.cs | 38 + .../ContentAlignment.cs | 37 + .../EdgeEffects.cs | 41 + .../System.Windows.Forms.VisualStyles/EdgeStyle.cs | 38 + .../System.Windows.Forms.VisualStyles/Edges.cs | 41 + .../EnumProperty.cs | 49 + .../FilenameProperty.cs | 42 + .../System.Windows.Forms.VisualStyles/FillType.cs | 39 + .../FontProperty.cs | 35 + .../GlyphFontSizingType.cs | 37 + .../System.Windows.Forms.VisualStyles/GlyphType.cs | 37 + .../GroupBoxState.cs | 36 + .../System.Windows.Forms.VisualStyles/GtkPlus.cs | 1774 +++++ .../HitTestCode.cs | 44 + .../HitTestOptions.cs | 46 + .../HorizontalAlign.cs | 37 + .../IVisualStyles.cs | 90 + .../IconEffect.cs | 39 + .../ImageOrientation.cs | 36 + .../ImageSelectType.cs | 37 + .../IntegerProperty.cs | 58 + .../MarginProperty.cs | 37 + .../OffsetType.cs | 48 + .../PointProperty.cs | 42 + .../PushButtonState.cs | 39 + .../RadioButtonState.cs | 42 + .../ScrollBarArrowButtonState.cs | 50 + .../ScrollBarSizeBoxState.cs | 36 + .../ScrollBarState.cs | 38 + .../SizingType.cs | 37 + .../StringProperty.cs | 35 + .../TabItemState.cs | 38 + .../TextBoxState.cs | 40 + .../TextMetrics.cs | 158 + .../TextMetricsCharacterSet.cs | 53 + .../TextMetricsPitchAndFamilyValues.cs | 40 + .../TextShadowType.cs | 37 + .../ThemeSizeType.cs | 37 + .../ToolBarState.cs | 40 + .../TrackBarThumbState.cs | 38 + .../TrueSizeScalingType.cs | 37 + .../System.Windows.Forms.VisualStyles/UXTheme.cs | 216 + .../VerticalAlignment.cs | 37 + .../VisualStyleElement.cs | 2714 +++++++ .../VisualStyleInformation.cs | 180 + .../VisualStyleRenderer.cs | 447 ++ .../VisualStyleState.cs | 38 + .../VisualStylesEngine.cs | 52 + .../VisualStylesGtkPlus.cs | 1177 +++ .../VisualStylesNative.cs | 455 ++ source/ShiftUI/Theming/Default/.gitattributes | 5 + source/ShiftUI/Theming/Default/ButtonPainter.cs | 189 + source/ShiftUI/Theming/Default/CheckBoxPainter.cs | 357 + source/ShiftUI/Theming/Default/LabelPainter.cs | 57 + source/ShiftUI/Theming/Default/LinkLabelPainter.cs | 120 + .../ShiftUI/Theming/Default/RadioButtonPainter.cs | 239 + .../ShiftUI/Theming/Default/TabControlPainter.cs | 507 ++ source/ShiftUI/Theming/Default/ToolStripPainter.cs | 189 + source/ShiftUI/Theming/Nice/.gitattributes | 1 + source/ShiftUI/Theming/Nice/TabControlPainter.cs | 38 + source/ShiftUI/Theming/ShiftOS.cs | 118 + source/ShiftUI/Theming/ThemeElements.cs | 223 + source/ShiftUI/Theming/ThemeElementsClearlooks.cs | 35 + source/ShiftUI/Theming/ThemeElementsDefault.cs | 95 + source/ShiftUI/Theming/ThemeElementsGtk.cs | 35 + source/ShiftUI/Theming/ThemeElementsMemphis.cs | 86 + source/ShiftUI/Theming/ThemeElementsNice.cs | 43 + .../ShiftUI/Theming/ThemeElementsVisualStyles.cs | 59 + source/ShiftUI/Theming/ThemeEngine.cs | 62 + source/ShiftUI/Theming/ThemeSkinnable.cs | 8351 ++++++++++++++++++++ source/ShiftUI/Theming/ThemeVisualStyles.cs | 2162 +++++ source/ShiftUI/Theming/ThemeWin32Classic.cs | 7815 ++++++++++++++++++ .../Theming/VisualStyles/CheckBoxPainter.cs | 104 + .../Theming/VisualStyles/RadioButtonPainter.cs | 56 + .../Theming/VisualStyles/TabControlPainter.cs | 267 + .../Theming/VisualStyles/ToolStripPainter.cs | 213 + source/ShiftUI/ToolStrip/ToolStrip.cs | 1778 +++++ .../ToolStrip/ToolStripArrowRenderEventArgs.cs | 79 + .../ToolStrip/ToolStripArrowRenderEventHandler.cs | 32 + source/ShiftUI/ToolStrip/ToolStripButton.cs | 250 + source/ShiftUI/ToolStrip/ToolStripComboBox.cs | 421 + source/ShiftUI/ToolStrip/ToolStripContainer.cs | 310 + source/ShiftUI/ToolStrip/ToolStripContentPanel.cs | 304 + .../ToolStripContentPanelRenderEventArgs.cs | 62 + .../ToolStripContentPanelRenderEventHandler.cs | 32 + source/ShiftUI/ToolStrip/ToolStripControlHost.cs | 577 ++ source/ShiftUI/ToolStrip/ToolStripDropDown.cs | 1051 +++ .../ShiftUI/ToolStrip/ToolStripDropDownButton.cs | 185 + .../ToolStrip/ToolStripDropDownCloseReason.cs | 40 + .../ToolStrip/ToolStripDropDownClosedEventArgs.cs | 49 + .../ToolStripDropDownClosedEventHandler.cs | 32 + .../ToolStrip/ToolStripDropDownClosingEventArgs.cs | 50 + .../ToolStripDropDownClosingEventHandler.cs | 32 + .../ToolStrip/ToolStripDropDownDirection.cs | 42 + source/ShiftUI/ToolStrip/ToolStripDropDownItem.cs | 348 + .../ToolStripDropDownItemAccessibleObject.cs | 66 + source/ShiftUI/ToolStrip/ToolStripDropDownMenu.cs | 196 + .../ShiftUI/ToolStrip/ToolStripGripDisplayStyle.cs | 37 + .../ToolStrip/ToolStripGripRenderEventArgs.cs | 70 + .../ToolStrip/ToolStripGripRenderEventHandler.cs | 32 + source/ShiftUI/ToolStrip/ToolStripGripStyle.cs | 37 + source/ShiftUI/ToolStrip/ToolStripItem.cs | 2077 +++++ source/ShiftUI/ToolStrip/ToolStripItemAlignment.cs | 37 + .../ToolStrip/ToolStripItemClickedEventArgs.cs | 47 + .../ToolStrip/ToolStripItemClickedEventHandler.cs | 32 + .../ShiftUI/ToolStrip/ToolStripItemCollection.cs | 385 + .../ShiftUI/ToolStrip/ToolStripItemDisplayStyle.cs | 39 + source/ShiftUI/ToolStrip/ToolStripItemEventArgs.cs | 50 + .../ShiftUI/ToolStrip/ToolStripItemEventHandler.cs | 32 + source/ShiftUI/ToolStrip/ToolStripItemEventType.cs | 42 + .../ToolStrip/ToolStripItemImageRenderEventArgs.cs | 60 + .../ToolStripItemImageRenderEventHandler.cs | 32 + .../ShiftUI/ToolStrip/ToolStripItemImageScaling.cs | 37 + source/ShiftUI/ToolStrip/ToolStripItemOverflow.cs | 38 + source/ShiftUI/ToolStrip/ToolStripItemPlacement.cs | 38 + .../ToolStrip/ToolStripItemRenderEventArgs.cs | 59 + .../ToolStrip/ToolStripItemRenderEventHandler.cs | 32 + .../ToolStrip/ToolStripItemTextRenderEventArgs.cs | 131 + .../ToolStripItemTextRenderEventHandler.cs | 32 + source/ShiftUI/ToolStrip/ToolStripLabel.cs | 288 + source/ShiftUI/ToolStrip/ToolStripLayoutStyle.cs | 40 + source/ShiftUI/ToolStrip/ToolStripManager.cs | 634 ++ .../ToolStrip/ToolStripManagerRenderMode.cs | 41 + source/ShiftUI/ToolStrip/ToolStripMenuItem.cs | 548 ++ source/ShiftUI/ToolStrip/ToolStripOverflow.cs | 151 + .../ShiftUI/ToolStrip/ToolStripOverflowButton.cs | 113 + source/ShiftUI/ToolStrip/ToolStripPanel.cs | 618 ++ .../ToolStrip/ToolStripPanelRenderEventArgs.cs | 62 + .../ToolStrip/ToolStripPanelRenderEventHandler.cs | 32 + source/ShiftUI/ToolStrip/ToolStripPanelRow.cs | 227 + .../ToolStrip/ToolStripProfessionalRenderer.cs | 470 ++ source/ShiftUI/ToolStrip/ToolStripProgressBar.cs | 223 + .../ShiftUI/ToolStrip/ToolStripRenderEventArgs.cs | 85 + .../ToolStrip/ToolStripRenderEventHandler.cs | 32 + source/ShiftUI/ToolStrip/ToolStripRenderMode.cs | 43 + source/ShiftUI/ToolStrip/ToolStripRenderer.cs | 572 ++ source/ShiftUI/ToolStrip/ToolStripSeparator.cs | 278 + .../ToolStrip/ToolStripSeparatorRenderEventArgs.cs | 49 + .../ToolStripSeparatorRenderEventHandler.cs | 32 + source/ShiftUI/ToolStrip/ToolStripSplitButton.cs | 372 + .../ShiftUI/ToolStrip/ToolStripSplitStackLayout.cs | 264 + source/ShiftUI/ToolStrip/ToolStripStatusLabel.cs | 129 + .../ToolStrip/ToolStripStatusLabelBorderSides.cs | 49 + .../ShiftUI/ToolStrip/ToolStripSystemRenderer.cs | 130 + source/ShiftUI/ToolStrip/ToolStripTextBox.cs | 590 ++ source/ShiftUI/ToolStrip/ToolStripTextDirection.cs | 39 + source/ShiftUI/Widget.cs | 6728 ++++++++++++++++ source/ShiftUI/Widgets/Button.cs | 200 + source/ShiftUI/Widgets/CaptionButton.cs | 37 + source/ShiftUI/Widgets/CategoryGridEntry.cs | 67 + source/ShiftUI/Widgets/CheckBox.cs | 404 + source/ShiftUI/Widgets/CheckedListBox.cs | 655 ++ source/ShiftUI/Widgets/CollectionEditor.cs | 738 ++ source/ShiftUI/Widgets/ComboBox.cs | 2825 +++++++ source/ShiftUI/Widgets/ContainerControl.cs | 850 ++ source/ShiftUI/Widgets/DateTimePicker.cs | 2018 +++++ source/ShiftUI/Widgets/FlowLayoutPanel.cs | 197 + source/ShiftUI/Widgets/GridEntry.cs | 860 ++ source/ShiftUI/Widgets/GridItemCollection.cs | 158 + source/ShiftUI/Widgets/GroupBox.cs | 344 + source/ShiftUI/Widgets/HScrollBar.cs | 52 + source/ShiftUI/Widgets/IRootGridEntry.cs | 40 + source/ShiftUI/Widgets/ImplicitHScrollBar.cs | 48 + source/ShiftUI/Widgets/ImplicitVScrollBar.cs | 48 + source/ShiftUI/Widgets/Label.cs | 729 ++ source/ShiftUI/Widgets/LabelEditTextBox.cs | 108 + source/ShiftUI/Widgets/LinkLabel.cs | 1120 +++ source/ShiftUI/Widgets/ListBox.cs | 3093 ++++++++ source/ShiftUI/Widgets/ListControl.cs | 509 ++ source/ShiftUI/Widgets/ListView.cs | 6155 +++++++++++++++ source/ShiftUI/Widgets/ListViewItem.cs | 1638 ++++ source/ShiftUI/Widgets/MonthCalendar.cs | 2430 ++++++ source/ShiftUI/Widgets/NotifyIcon.cs | 753 ++ source/ShiftUI/Widgets/Panel.cs | 187 + source/ShiftUI/Widgets/PictureBox.cs | 618 ++ source/ShiftUI/Widgets/PictureBoxSizeMode.cs | 38 + source/ShiftUI/Widgets/ProgressBar.cs | 533 ++ source/ShiftUI/Widgets/PropertiesTab.cs | 76 + source/ShiftUI/Widgets/PropertyGrid.cs | 1626 ++++ source/ShiftUI/Widgets/PropertyGridCommands.cs | 47 + source/ShiftUI/Widgets/PropertyGridTextBox.cs | 320 + source/ShiftUI/Widgets/PropertyGridView.cs | 1101 +++ source/ShiftUI/Widgets/RadioButton.cs | 391 + source/ShiftUI/Widgets/RichTextBox.cs | 2089 +++++ source/ShiftUI/Widgets/RootGridEntry.cs | 88 + source/ShiftUI/Widgets/ScrollBar.cs | 1624 ++++ source/ShiftUI/Widgets/ScrollBarRenderer.cs | 326 + source/ShiftUI/Widgets/ScrollButton.cs | 39 + source/ShiftUI/Widgets/SizeGrip.cs | 293 + source/ShiftUI/Widgets/SizeGripStyle.cs | 37 + source/ShiftUI/Widgets/StatusBar.cs | 806 ++ source/ShiftUI/Widgets/StatusBarPanel.cs | 272 + source/ShiftUI/Widgets/StatusStrip.cs | 313 + source/ShiftUI/Widgets/TabControl.cs | 2008 +++++ source/ShiftUI/Widgets/TabPage.cs | 399 + source/ShiftUI/Widgets/TableLayoutPanel.cs | 788 ++ source/ShiftUI/Widgets/TextBox.cs | 1025 +++ source/ShiftUI/Widgets/TextBoxBase.cs | 2493 ++++++ source/ShiftUI/Widgets/TrackBar.cs | 907 +++ source/ShiftUI/Widgets/TreeNode.cs | 1087 +++ source/ShiftUI/Widgets/TreeView.cs | 2438 ++++++ source/ShiftUI/Widgets/UserWidget.cs | 236 + source/ShiftUI/Widgets/VScrollBar.cs | 79 + source/ShiftUI/keyboards.resources | Bin 0 -> 86172 bytes .../Controls/WinFormsHost.cs | 86 + source/WindowsFormsApplication1/ShiftOS.csproj | 3 + 740 files changed, 214703 insertions(+) create mode 100644 source/ShiftUI/Application.cs create mode 100644 source/ShiftUI/ApplicationContext.cs create mode 100644 source/ShiftUI/Cursor.cs create mode 100644 source/ShiftUI/Design/Behavior/Adorner.cs create mode 100644 source/ShiftUI/Design/Behavior/Behavior.cs create mode 100644 source/ShiftUI/Design/Behavior/BehaviorDragDropEventArgs.cs create mode 100644 source/ShiftUI/Design/Behavior/BehaviorDragDropEventHandler.cs create mode 100644 source/ShiftUI/Design/Behavior/BehaviorService.cs create mode 100644 source/ShiftUI/Design/Behavior/BehaviorServiceAdornerCollection.cs create mode 100644 source/ShiftUI/Design/Behavior/BehaviorServiceAdornerCollectionEnumerator.cs create mode 100644 source/ShiftUI/Design/Behavior/ComponentGlyph.cs create mode 100644 source/ShiftUI/Design/Behavior/ControlBodyGlyph.cs create mode 100644 source/ShiftUI/Design/Behavior/Glyph.cs create mode 100644 source/ShiftUI/Design/Behavior/GlyphCollection.cs create mode 100644 source/ShiftUI/Design/Behavior/GlyphSelectionType.cs create mode 100644 source/ShiftUI/Design/Behavior/SnapLine.cs create mode 100644 source/ShiftUI/Design/Behavior/SnapLinePriority.cs create mode 100644 source/ShiftUI/Design/Behavior/SnapLineType.cs create mode 100644 source/ShiftUI/Design/ComponentDesigner.cs create mode 100644 source/ShiftUI/Design/ComponentEditorForm.cs create mode 100644 source/ShiftUI/Design/ComponentEditorPage.cs create mode 100644 source/ShiftUI/Design/ComponentTray.cs create mode 100644 source/ShiftUI/Design/Consts.cs create mode 100644 source/ShiftUI/Design/ControlDataObject.cs create mode 100644 source/ShiftUI/Design/ControlDesigner.cs create mode 100644 source/ShiftUI/Design/DefaultMenuCommands.cs create mode 100644 source/ShiftUI/Design/DocumentDesigner.cs create mode 100644 source/ShiftUI/Design/EventsTab.cs create mode 100644 source/ShiftUI/Design/FormDocumentDesigner.cs create mode 100644 source/ShiftUI/Design/IMenuEditorService.cs create mode 100644 source/ShiftUI/Design/IMessageReceiver.cs create mode 100644 source/ShiftUI/Design/IUISelectionService.cs create mode 100644 source/ShiftUI/Design/IUIService.cs create mode 100644 source/ShiftUI/Design/IWindowsFormsEditorService.cs create mode 100644 source/ShiftUI/Design/Native.cs create mode 100644 source/ShiftUI/Design/ParentControlDesigner.cs create mode 100644 source/ShiftUI/Design/PropertyTab.cs create mode 100644 source/ShiftUI/Design/ScrollableControlDesigner.cs create mode 100644 source/ShiftUI/Design/SelectionFrame.cs create mode 100644 source/ShiftUI/Design/SelectionRules.cs create mode 100644 source/ShiftUI/Design/ToolStripItemDesignerAvailability.cs create mode 100644 source/ShiftUI/Design/ToolStripItemDesignerAvailabilityAttribute.cs create mode 100644 source/ShiftUI/Design/UISelectionService.cs create mode 100644 source/ShiftUI/Design/WindowsFormsComponentEditor.cs create mode 100644 source/ShiftUI/Design/WndProcRouter.cs create mode 100644 source/ShiftUI/Dialogs/StringArrayDialog.cs create mode 100644 source/ShiftUI/Dialogs/ThreadExceptionDialog.cs create mode 100644 source/ShiftUI/Enums/AccessibleEvents.cs create mode 100644 source/ShiftUI/Enums/AccessibleNavigation.cs create mode 100644 source/ShiftUI/Enums/AccessibleObject.cs create mode 100644 source/ShiftUI/Enums/AccessibleRole.cs create mode 100644 source/ShiftUI/Enums/AccessibleSelection.cs create mode 100644 source/ShiftUI/Enums/AccessibleStates.cs create mode 100644 source/ShiftUI/Enums/AmbientProperties.cs create mode 100644 source/ShiftUI/Enums/AnchorStyles.cs create mode 100644 source/ShiftUI/Enums/Appearance.cs create mode 100644 source/ShiftUI/Enums/ArrangeDirection.cs create mode 100644 source/ShiftUI/Enums/ArrangeStartingPosition.cs create mode 100644 source/ShiftUI/Enums/ArrowDirection.cs create mode 100644 source/ShiftUI/Enums/AutoCompleteMode.cs create mode 100644 source/ShiftUI/Enums/AutoScaleMode.cs create mode 100644 source/ShiftUI/Enums/AutoSizeMode.cs create mode 100644 source/ShiftUI/Enums/AutoValidate.cs create mode 100644 source/ShiftUI/Enums/BatteryChargeStatus.cs create mode 100644 source/ShiftUI/Enums/BindingCompleteState.cs create mode 100644 source/ShiftUI/Enums/Border3DSide.cs create mode 100644 source/ShiftUI/Enums/Border3DStyle.cs create mode 100644 source/ShiftUI/Enums/BorderStyle.cs create mode 100644 source/ShiftUI/Enums/ButtonBorderStyle.cs create mode 100644 source/ShiftUI/Enums/ButtonState.cs create mode 100644 source/ShiftUI/Enums/CharacterCasing.cs create mode 100644 source/ShiftUI/Enums/CheckState.cs create mode 100644 source/ShiftUI/Enums/CloseReason.cs create mode 100644 source/ShiftUI/Enums/ColorDepth.cs create mode 100644 source/ShiftUI/Enums/ComboBoxStyle.cs create mode 100644 source/ShiftUI/Enums/ControlStyles.cs create mode 100644 source/ShiftUI/Enums/ControlUpdateMode.cs create mode 100644 source/ShiftUI/Enums/CreateParams.cs create mode 100644 source/ShiftUI/Enums/DataFormats.cs create mode 100644 source/ShiftUI/Enums/DataSourceUpdateMode.cs create mode 100644 source/ShiftUI/Enums/DateTimePickerFormat.cs create mode 100644 source/ShiftUI/Enums/DialogResult.cs create mode 100644 source/ShiftUI/Enums/DockStyle.cs create mode 100644 source/ShiftUI/Enums/DragAction.cs create mode 100644 source/ShiftUI/Enums/DragDropEffects.cs create mode 100644 source/ShiftUI/Enums/DrawItemState.cs create mode 100644 source/ShiftUI/Enums/DrawMode.cs create mode 100644 source/ShiftUI/Enums/FlatButtonAppearance.cs create mode 100644 source/ShiftUI/Enums/FlatStyle.cs create mode 100644 source/ShiftUI/Enums/FlowDirection.cs create mode 100644 source/ShiftUI/Enums/FormBorderStyle.cs create mode 100644 source/ShiftUI/Enums/FrameStyle.cs create mode 100644 source/ShiftUI/Enums/HorizontalAlignment.cs create mode 100644 source/ShiftUI/Enums/ImageLayout.cs create mode 100644 source/ShiftUI/Enums/ImeMode.cs create mode 100644 source/ShiftUI/Enums/ItemActivation.cs create mode 100644 source/ShiftUI/Enums/ItemBoundsPortion.cs create mode 100644 source/ShiftUI/Enums/Keys.cs create mode 100644 source/ShiftUI/Enums/LeftRightAlignment.cs create mode 100644 source/ShiftUI/Enums/ListViewAlignment.cs create mode 100644 source/ShiftUI/Enums/MergeAction.cs create mode 100644 source/ShiftUI/Enums/MessageBoxButtons.cs create mode 100644 source/ShiftUI/Enums/MouseButtons.cs create mode 100644 source/ShiftUI/Enums/Orientation.cs create mode 100644 source/ShiftUI/Enums/PowerLineStatus.cs create mode 100644 source/ShiftUI/Enums/PowerState.cs create mode 100644 source/ShiftUI/Enums/PowerStatus.cs create mode 100644 source/ShiftUI/Enums/PreProcessControlState.cs create mode 100644 source/ShiftUI/Enums/ProgressBarStyle.cs create mode 100644 source/ShiftUI/Enums/RichTextBoxLanguageOptions.cs create mode 100644 source/ShiftUI/Enums/RichTextBoxSelectionTypes.cs create mode 100644 source/ShiftUI/Enums/RichTextBoxStreamType.cs create mode 100644 source/ShiftUI/Enums/RightToLeft.cs create mode 100644 source/ShiftUI/Enums/RowStyle.cs create mode 100644 source/ShiftUI/Enums/ScreenOrientation.cs create mode 100644 source/ShiftUI/Enums/ScrollBars.cs create mode 100644 source/ShiftUI/Enums/ScrollOrientation.cs create mode 100644 source/ShiftUI/Enums/SearchDirectionHint.cs create mode 100644 source/ShiftUI/Enums/SelectionMode.cs create mode 100644 source/ShiftUI/Enums/SelectionRange.cs create mode 100644 source/ShiftUI/Enums/Shortcut.cs create mode 100644 source/ShiftUI/Enums/SizeType.cs create mode 100644 source/ShiftUI/Enums/SortOrder.cs create mode 100644 source/ShiftUI/Enums/StatusBarPanelAutoSize.cs create mode 100644 source/ShiftUI/Enums/StatusBarPanelBorderStyle.cs create mode 100644 source/ShiftUI/Enums/StatusBarPanelStyle.cs create mode 100644 source/ShiftUI/Enums/TabAlignment.cs create mode 100644 source/ShiftUI/Enums/TabAppearance.cs create mode 100644 source/ShiftUI/Enums/TabControlAction.cs create mode 100644 source/ShiftUI/Enums/TabDrawMode.cs create mode 100644 source/ShiftUI/Enums/TabSizeMode.cs create mode 100644 source/ShiftUI/Enums/TextDataFormat.cs create mode 100644 source/ShiftUI/Enums/TextImageRelation.cs create mode 100644 source/ShiftUI/Enums/TickStyle.cs create mode 100644 source/ShiftUI/Enums/TreeNodeStates.cs create mode 100644 source/ShiftUI/Enums/TreeViewAction.cs create mode 100644 source/ShiftUI/Enums/TreeViewDrawMode.cs create mode 100644 source/ShiftUI/Enums/TreeViewHitTestLocations.cs create mode 100644 source/ShiftUI/Enums/UnhandledExceptionMode.cs create mode 100644 source/ShiftUI/Enums/ValidationConstraints.cs create mode 100644 source/ShiftUI/Enums/View.cs create mode 100644 source/ShiftUI/Events/AccessibleEvents.cs create mode 100644 source/ShiftUI/Events/BindingCompleteEventArgs.cs create mode 100644 source/ShiftUI/Events/BindingCompleteEventHandler.cs create mode 100644 source/ShiftUI/Events/BindingManagerDataErrorEventArgs.cs create mode 100644 source/ShiftUI/Events/BindingManagerDataErrorEventHandler.cs create mode 100644 source/ShiftUI/Events/CacheVirtualItemsEventArgs.cs create mode 100644 source/ShiftUI/Events/CacheVirtualItemsEventHandler.cs create mode 100644 source/ShiftUI/Events/ContentsResizedEventArgs.cs create mode 100644 source/ShiftUI/Events/ContentsResizedEventHandler.cs create mode 100644 source/ShiftUI/Events/ConvertEventArgs.cs create mode 100644 source/ShiftUI/Events/ConvertEventHandler.cs create mode 100644 source/ShiftUI/Events/DateBoldEventArgs.cs create mode 100644 source/ShiftUI/Events/DateBoldEventHandler.cs create mode 100644 source/ShiftUI/Events/DateRangeEventArgs.cs create mode 100644 source/ShiftUI/Events/DateRangeEventHandler.cs create mode 100644 source/ShiftUI/Events/DrawItemEventArgs.cs create mode 100644 source/ShiftUI/Events/DrawItemEventHandler.cs create mode 100644 source/ShiftUI/Events/DrawListViewColumnHeaderEventArgs.cs create mode 100644 source/ShiftUI/Events/DrawListViewColumnHeaderEventHandler.cs create mode 100644 source/ShiftUI/Events/DrawListViewItemEventArgs.cs create mode 100644 source/ShiftUI/Events/DrawListViewItemEventHandler.cs create mode 100644 source/ShiftUI/Events/DrawListViewSubItemEventArgs.cs create mode 100644 source/ShiftUI/Events/DrawListViewSubItemEventHandler.cs create mode 100644 source/ShiftUI/Events/DrawTreeNodeEventArgs.cs create mode 100644 source/ShiftUI/Events/DrawTreeNodeEventHandler.cs create mode 100644 source/ShiftUI/Events/GiveFeedbackEventArgs.cs create mode 100644 source/ShiftUI/Events/GiveFeedbackEventHandler.cs create mode 100644 source/ShiftUI/Events/HelpEventArgs.cs create mode 100644 source/ShiftUI/Events/HelpEventHandler.cs create mode 100644 source/ShiftUI/Events/InputLanguageChangedEventArgs.cs create mode 100644 source/ShiftUI/Events/InputLanguageChangedEventHandler.cs create mode 100644 source/ShiftUI/Events/InputLanguageChangingEventArgs.cs create mode 100644 source/ShiftUI/Events/InputLanguageChangingEventHandler.cs create mode 100644 source/ShiftUI/Events/InvalidateEventArgs.cs create mode 100644 source/ShiftUI/Events/InvalidateEventHandler.cs create mode 100644 source/ShiftUI/Events/ItemChangedEventArgs.cs create mode 100644 source/ShiftUI/Events/ItemChangedEventHandler.cs create mode 100644 source/ShiftUI/Events/ItemCheckEventArgs.cs create mode 100644 source/ShiftUI/Events/ItemCheckEventHandler.cs create mode 100644 source/ShiftUI/Events/ItemCheckedEventArgs.cs create mode 100644 source/ShiftUI/Events/ItemCheckedEventHandler.cs create mode 100644 source/ShiftUI/Events/ItemDragEventArgs.cs create mode 100644 source/ShiftUI/Events/ItemDragEventHandler.cs create mode 100644 source/ShiftUI/Events/LabelEditEventArgs.cs create mode 100644 source/ShiftUI/Events/LabelEditEventHandler.cs create mode 100644 source/ShiftUI/Events/LayoutEventArgs.cs create mode 100644 source/ShiftUI/Events/LayoutEventHandler.cs create mode 100644 source/ShiftUI/Events/ListControlConvertEventArgs.cs create mode 100644 source/ShiftUI/Events/ListControlConvertEventHandler.cs create mode 100644 source/ShiftUI/Events/MeasureItemEventArgs.cs create mode 100644 source/ShiftUI/Events/MeasureItemEventHandler.cs create mode 100644 source/ShiftUI/Events/NodeLabelEditEventArgs.cs create mode 100644 source/ShiftUI/Events/NodeLabelEditEventHandler.cs create mode 100644 source/ShiftUI/Events/PreviewKeyDownEventArgs.cs create mode 100644 source/ShiftUI/Events/PreviewKeyDownEventHandler.cs create mode 100644 source/ShiftUI/Events/QueryAccessibilityHelpEventArgs.cs create mode 100644 source/ShiftUI/Events/QueryAccessibilityHelpEventHandler.cs create mode 100644 source/ShiftUI/Events/QueryContinueDragEventArgs.cs create mode 100644 source/ShiftUI/Events/QueryContinueDragEventHandler.cs create mode 100644 source/ShiftUI/Events/RetrieveVirtualItemEventArgs.cs create mode 100644 source/ShiftUI/Events/RetrieveVirtualItemEventHandler.cs create mode 100644 source/ShiftUI/Events/ScrollEventArgs.cs create mode 100644 source/ShiftUI/Events/ScrollEventHandler.cs create mode 100644 source/ShiftUI/Events/ScrollEventType.cs create mode 100644 source/ShiftUI/Events/SearchForVirtualItemEventArgs.cs create mode 100644 source/ShiftUI/Events/SearchForVirtualItemEventHandler.cs create mode 100644 source/ShiftUI/Events/SplitterCancelEventArgs.cs create mode 100644 source/ShiftUI/Events/SplitterCancelEventHandler.cs create mode 100644 source/ShiftUI/Events/SplitterEventArgs.cs create mode 100644 source/ShiftUI/Events/SplitterEventHandler.cs create mode 100644 source/ShiftUI/Events/StatusBarDrawItemEventArgs.cs create mode 100644 source/ShiftUI/Events/StatusBarDrawItemEventHandler.cs create mode 100644 source/ShiftUI/Events/StatusBarPanelClickEventArgs.cs create mode 100644 source/ShiftUI/Events/StatusBarPanelClickEventHandler.cs create mode 100644 source/ShiftUI/Events/TabControlCancelEventArgs.cs create mode 100644 source/ShiftUI/Events/TabControlCancelEventHandler.cs create mode 100644 source/ShiftUI/Events/TabControlEventArgs.cs create mode 100644 source/ShiftUI/Events/TabControlEventHandler.cs create mode 100644 source/ShiftUI/Events/TableLayoutCellPaintEventArgs.cs create mode 100644 source/ShiftUI/Events/TableLayoutCellPaintEventHandler.cs create mode 100644 source/ShiftUI/Events/TableLayoutColumnStyleCollection.cs create mode 100644 source/ShiftUI/Events/TableLayoutControlCollection.cs create mode 100644 source/ShiftUI/Events/TableLayoutPanelCellBorderStyle.cs create mode 100644 source/ShiftUI/Events/TableLayoutPanelCellPosition.cs create mode 100644 source/ShiftUI/Events/TableLayoutPanelGrowStyle.cs create mode 100644 source/ShiftUI/Events/TableLayoutRowStyleCollection.cs create mode 100644 source/ShiftUI/Events/TableLayoutStyle.cs create mode 100644 source/ShiftUI/Events/TableLayoutStyleCollection.cs create mode 100644 source/ShiftUI/Events/TreeNodeMouseClickEventArgs.cs create mode 100644 source/ShiftUI/Events/TreeNodeMouseClickEventHandler.cs create mode 100644 source/ShiftUI/Events/TreeNodeMouseHoverEventArgs.cs create mode 100644 source/ShiftUI/Events/TreeNodeMouseHoverEventHandler.cs create mode 100644 source/ShiftUI/Events/TreeViewCancelEventArgs.cs create mode 100644 source/ShiftUI/Events/TreeViewCancelEventHandler.cs create mode 100644 source/ShiftUI/Events/TreeViewEventArgs.cs create mode 100644 source/ShiftUI/Events/TreeViewEventHandler.cs create mode 100644 source/ShiftUI/Events/UICues.cs create mode 100644 source/ShiftUI/Events/UICuesEventArgs.cs create mode 100644 source/ShiftUI/Events/UICuesEventHandler.cs create mode 100644 source/ShiftUI/Form/Form.cs create mode 100644 source/ShiftUI/Form/FormClosedEventArgs.cs create mode 100644 source/ShiftUI/Form/FormClosedEventHandler.cs create mode 100644 source/ShiftUI/Form/FormClosingEventArgs.cs create mode 100644 source/ShiftUI/Form/FormClosingEventHandler.cs create mode 100644 source/ShiftUI/Form/FormCollection.cs create mode 100644 source/ShiftUI/Form/FormStartPosition.cs create mode 100644 source/ShiftUI/Form/FormWindowManager.cs create mode 100644 source/ShiftUI/Form/FormWindowState.cs create mode 100644 source/ShiftUI/Form/MessageBox.cs create mode 100644 source/ShiftUI/Internal/ApplicationHandler.cs create mode 100644 source/ShiftUI/Internal/ArrangedElementCollection.cs create mode 100644 source/ShiftUI/Internal/AsyncMethodData.cs create mode 100644 source/ShiftUI/Internal/AsyncMethodResult.cs create mode 100644 source/ShiftUI/Internal/AutoCompleteSource.cs create mode 100644 source/ShiftUI/Internal/AutoCompleteStringCollection.cs create mode 100644 source/ShiftUI/Internal/BaseCollection.cs create mode 100644 source/ShiftUI/Internal/Binding.cs create mode 100644 source/ShiftUI/Internal/BindingCompleteContext.cs create mode 100644 source/ShiftUI/Internal/BindingContext.cs create mode 100644 source/ShiftUI/Internal/BindingManagerBase.cs create mode 100644 source/ShiftUI/Internal/BindingMemberInfo.cs create mode 100644 source/ShiftUI/Internal/BindingsCollection.cs create mode 100644 source/ShiftUI/Internal/BootMode.cs create mode 100644 source/ShiftUI/Internal/BoundsSpecified.cs create mode 100644 source/ShiftUI/Internal/ButtonBase.cs create mode 100644 source/ShiftUI/Internal/ButtonRenderer.cs create mode 100644 source/ShiftUI/Internal/CheckBoxRenderer.cs create mode 100644 source/ShiftUI/Internal/Clipboard.cs create mode 100644 source/ShiftUI/Internal/Consts.cs create mode 100644 source/ShiftUI/Internal/ContextMenuStrip.cs create mode 100644 source/ShiftUI/Internal/ControlBindingsCollection.cs create mode 100644 source/ShiftUI/Internal/ControlEventArgs.cs create mode 100644 source/ShiftUI/Internal/ControlEventHandler.cs create mode 100644 source/ShiftUI/Internal/ControlHandler.cs create mode 100644 source/ShiftUI/Internal/ControlPaint.cs create mode 100644 source/ShiftUI/Internal/CurrencyManager.cs create mode 100644 source/ShiftUI/Internal/Cursor.cs create mode 100644 source/ShiftUI/Internal/CursorConverter.cs create mode 100644 source/ShiftUI/Internal/Cursors.cs create mode 100644 source/ShiftUI/Internal/DataObject.cs create mode 100644 source/ShiftUI/Internal/Day.cs create mode 100644 source/ShiftUI/Internal/DebugHelper.cs create mode 100644 source/ShiftUI/Internal/DefaultLayout.cs create mode 100644 source/ShiftUI/Internal/Dnd.cs create mode 100644 source/ShiftUI/Internal/DockingAttribute.cs create mode 100644 source/ShiftUI/Internal/DockingBehavior.cs create mode 100644 source/ShiftUI/Internal/DrawToolTipEventArgs.cs create mode 100644 source/ShiftUI/Internal/DrawToolTipEventHandler.cs create mode 100644 source/ShiftUI/Internal/Enums.cs create mode 100644 source/ShiftUI/Internal/EventHandler.cs create mode 100644 source/ShiftUI/Internal/EventHandlerBase.cs create mode 100644 source/ShiftUI/Internal/FixedSizeTextBox.cs create mode 100644 source/ShiftUI/Internal/FlowLayout.cs create mode 100644 source/ShiftUI/Internal/FlowLayoutSettings.cs create mode 100644 source/ShiftUI/Internal/GetChildAtPointSkip.cs create mode 100644 source/ShiftUI/Internal/GridItem.cs create mode 100644 source/ShiftUI/Internal/GridItemType.cs create mode 100644 source/ShiftUI/Internal/GroupBoxRenderer.cs create mode 100644 source/ShiftUI/Internal/HIObjectHandler.cs create mode 100644 source/ShiftUI/Internal/HScrollProperties.cs create mode 100644 source/ShiftUI/Internal/Hwnd.cs create mode 100644 source/ShiftUI/Internal/IBindableComponent.cs create mode 100644 source/ShiftUI/Internal/IBounds.cs create mode 100644 source/ShiftUI/Internal/IButtonControl.cs create mode 100644 source/ShiftUI/Internal/ICommandExecutor.cs create mode 100644 source/ShiftUI/Internal/IComponentEditorPageSite.cs create mode 100644 source/ShiftUI/Internal/IContainerControl.cs create mode 100644 source/ShiftUI/Internal/ICurrencyManagerProvider.cs create mode 100644 source/ShiftUI/Internal/IDataGridColumnStyleEditingNotificationService.cs create mode 100644 source/ShiftUI/Internal/IDataGridEditingService.cs create mode 100644 source/ShiftUI/Internal/IDataGridViewEditingCell.cs create mode 100644 source/ShiftUI/Internal/IDataGridViewEditingControl.cs create mode 100644 source/ShiftUI/Internal/IDataObject.cs create mode 100644 source/ShiftUI/Internal/IDropTarget.cs create mode 100644 source/ShiftUI/Internal/IEventHandler.cs create mode 100644 source/ShiftUI/Internal/IFeatureSupport.cs create mode 100644 source/ShiftUI/Internal/IFileReaderService.cs create mode 100644 source/ShiftUI/Internal/IKeyFilter.cs create mode 100644 source/ShiftUI/Internal/IMessageFilter.cs create mode 100644 source/ShiftUI/Internal/IToolStripData.cs create mode 100644 source/ShiftUI/Internal/IWin32Window.cs create mode 100644 source/ShiftUI/Internal/IWindowTarget.cs create mode 100644 source/ShiftUI/Internal/ImageIndexConverter.cs create mode 100644 source/ShiftUI/Internal/ImageKeyConverter.cs create mode 100644 source/ShiftUI/Internal/ImageList.cs create mode 100644 source/ShiftUI/Internal/ImageListConverter.cs create mode 100644 source/ShiftUI/Internal/ImageListStreamer.cs create mode 100644 source/ShiftUI/Internal/InternalWindowManager.cs create mode 100644 source/ShiftUI/Internal/KeyboardHandler.cs create mode 100644 source/ShiftUI/Internal/KeysConverter.cs create mode 100644 source/ShiftUI/Internal/LayoutEngine.cs create mode 100644 source/ShiftUI/Internal/LayoutSettings.cs create mode 100644 source/ShiftUI/Internal/Line.cs create mode 100644 source/ShiftUI/Internal/LineTag.cs create mode 100644 source/ShiftUI/Internal/ListBindingConverter.cs create mode 100644 source/ShiftUI/Internal/ListBindingHelper.cs create mode 100644 source/ShiftUI/Internal/MONO-NOTES create mode 100644 source/ShiftUI/Internal/MONO-TODO create mode 100644 source/ShiftUI/Internal/MWFCategoryAttribute.cs create mode 100644 source/ShiftUI/Internal/MWFDescriptionAttribute.cs create mode 100644 source/ShiftUI/Internal/MainMenu.cs create mode 100644 source/ShiftUI/Internal/MdiClient.cs create mode 100644 source/ShiftUI/Internal/MdiControlStrip.cs create mode 100644 source/ShiftUI/Internal/MdiLayout.cs create mode 100644 source/ShiftUI/Internal/MdiWindowManager.cs create mode 100644 source/ShiftUI/Internal/Message.cs create mode 100644 source/ShiftUI/Internal/MethodInvoker.cs create mode 100644 source/ShiftUI/Internal/MouseHandler.cs create mode 100644 source/ShiftUI/Internal/NativeWindow.cs create mode 100644 source/ShiftUI/Internal/OpacityConverter.cs create mode 100644 source/ShiftUI/Internal/OpenTreeNodeEnumerator.cs create mode 100644 source/ShiftUI/Internal/OwnerDrawPropertyBag.cs create mode 100644 source/ShiftUI/Internal/Padding.cs create mode 100644 source/ShiftUI/Internal/PaddingConverter.cs create mode 100644 source/ShiftUI/Internal/PaintEventArgs.cs create mode 100644 source/ShiftUI/Internal/PaintEventHandler.cs create mode 100644 source/ShiftUI/Internal/Pasteboard.cs create mode 100644 source/ShiftUI/Internal/PopupEventArgs.cs create mode 100644 source/ShiftUI/Internal/PopupEventHandler.cs create mode 100644 source/ShiftUI/Internal/PreProcessControlState.cs create mode 100644 source/ShiftUI/Internal/ProfessionalColorTable.cs create mode 100644 source/ShiftUI/Internal/PropertyManager.cs create mode 100644 source/ShiftUI/Internal/PropertySort.cs create mode 100644 source/ShiftUI/Internal/PropertyTabChangedEventArgs.cs create mode 100644 source/ShiftUI/Internal/PropertyTabChangedEventHandler.cs create mode 100644 source/ShiftUI/Internal/PropertyValueChangedEventArgs.cs create mode 100644 source/ShiftUI/Internal/PropertyValueChangedEventHandler.cs create mode 100644 source/ShiftUI/Internal/RadioButtonRenderer.cs create mode 100644 source/ShiftUI/Internal/RelatedCurrencyManager.cs create mode 100644 source/ShiftUI/Internal/RelatedImageListAttribute.cs create mode 100644 source/ShiftUI/Internal/RelatedPropertyManager.cs create mode 100644 source/ShiftUI/Internal/RichTextBoxFinds.cs create mode 100644 source/ShiftUI/Internal/RichTextBoxScrollBars.cs create mode 100644 source/ShiftUI/Internal/SUI_NOTES.txt create mode 100644 source/ShiftUI/Internal/Screen.cs create mode 100644 source/ShiftUI/Internal/ScrollProperties.cs create mode 100644 source/ShiftUI/Internal/SelectedGridItemChangedEventArgs.cs create mode 100644 source/ShiftUI/Internal/SelectedGridItemChangedEventHandler.cs create mode 100644 source/ShiftUI/Internal/SelectionRangeConverter.cs create mode 100644 source/ShiftUI/Internal/Splitter.cs create mode 100644 source/ShiftUI/Internal/Structs.cs create mode 100644 source/ShiftUI/Internal/SystemInformation.cs create mode 100644 source/ShiftUI/Internal/SystemParameter.cs create mode 100644 source/ShiftUI/Internal/TableLayout.cs create mode 100644 source/ShiftUI/Internal/TableLayoutSettings.cs create mode 100644 source/ShiftUI/Internal/TableLayoutSettingsTypeConverter.cs create mode 100644 source/ShiftUI/Internal/TextBoxTextRenderer.cs create mode 100644 source/ShiftUI/Internal/TextControl.cs create mode 100644 source/ShiftUI/Internal/TextFormatFlags.cs create mode 100644 source/ShiftUI/Internal/TextRenderer.cs create mode 100644 source/ShiftUI/Internal/Theme.cs create mode 100644 source/ShiftUI/Internal/Timer.cs create mode 100644 source/ShiftUI/Internal/ToolBarAppearance.cs create mode 100644 source/ShiftUI/Internal/ToolBarButtonStyle.cs create mode 100644 source/ShiftUI/Internal/ToolBarTextAlign.cs create mode 100644 source/ShiftUI/Internal/ToolTip.cs create mode 100644 source/ShiftUI/Internal/ToolTipIcon.cs create mode 100644 source/ShiftUI/Internal/ToolWindowManager.cs create mode 100644 source/ShiftUI/Internal/TreeNodeCollection.cs create mode 100644 source/ShiftUI/Internal/TreeNodeConverter.cs create mode 100644 source/ShiftUI/Internal/TreeViewHitTestInfo.cs create mode 100644 source/ShiftUI/Internal/TreeViewImageIndexConverter.cs create mode 100644 source/ShiftUI/Internal/TreeViewImageKeyConverter.cs create mode 100644 source/ShiftUI/Internal/VScrollProperties.cs create mode 100644 source/ShiftUI/Internal/Win32DnD.cs create mode 100644 source/ShiftUI/Internal/WindowHandler.cs create mode 100644 source/ShiftUI/Internal/WindowsFormsSynchronizationContext.cs create mode 100644 source/ShiftUI/Internal/X11Atoms.cs create mode 100644 source/ShiftUI/Internal/X11Clipboard.cs create mode 100644 source/ShiftUI/Internal/X11DesktopColors.cs create mode 100644 source/ShiftUI/Internal/X11Display.cs create mode 100644 source/ShiftUI/Internal/X11Dnd.cs create mode 100644 source/ShiftUI/Internal/X11Exception.cs create mode 100644 source/ShiftUI/Internal/X11Hwnd.cs create mode 100644 source/ShiftUI/Internal/X11Keyboard.cs create mode 100644 source/ShiftUI/Internal/X11RootHwnd.cs create mode 100644 source/ShiftUI/Internal/X11Structs.cs create mode 100644 source/ShiftUI/Internal/X11ThreadQueue.cs create mode 100644 source/ShiftUI/Internal/XEventQueue.cs create mode 100644 source/ShiftUI/Internal/Xlib.cs create mode 100644 source/ShiftUI/Internal/XplatUI.cs create mode 100644 source/ShiftUI/Internal/XplatUICarbon.cs create mode 100644 source/ShiftUI/Internal/XplatUICosmos.cs create mode 100644 source/ShiftUI/Internal/XplatUIDriver.cs create mode 100644 source/ShiftUI/Internal/XplatUIStructs.cs create mode 100644 source/ShiftUI/Internal/XplatUIWin32.cs create mode 100644 source/ShiftUI/Internal/XplatUIX11-new.cs create mode 100644 source/ShiftUI/Internal/XplatUIX11.cs create mode 100644 source/ShiftUI/Internal/XplatUIX11GTK.cs create mode 100644 source/ShiftUI/Keyboard/InputLanguage.cs create mode 100644 source/ShiftUI/Keyboard/InputLanguageCollection.cs create mode 100644 source/ShiftUI/Keyboard/KeyEventArgs.cs create mode 100644 source/ShiftUI/Keyboard/KeyEventHandler.cs create mode 100644 source/ShiftUI/Keyboard/KeyPressEventArgs.cs create mode 100644 source/ShiftUI/Keyboard/KeyPressEventHandler.cs create mode 100644 source/ShiftUI/Keyboard/KeyboardLayouts.cs create mode 100644 source/ShiftUI/Keyboard/ResXResourceWriter.cs create mode 100644 source/ShiftUI/Keyboard/create-keyboards.cs create mode 100644 source/ShiftUI/Link/LinkArea.cs create mode 100644 source/ShiftUI/Link/LinkBehavior.cs create mode 100644 source/ShiftUI/Link/LinkClickedEventArgs.cs create mode 100644 source/ShiftUI/Link/LinkClickedEventHandler.cs create mode 100644 source/ShiftUI/Link/LinkConverter.cs create mode 100644 source/ShiftUI/Link/LinkLabelLinkClickedEventArgs.cs create mode 100644 source/ShiftUI/Link/LinkLabelLinkClickedEventHandler.cs create mode 100644 source/ShiftUI/Link/LinkState.cs create mode 100644 source/ShiftUI/ListView/ColumnClickEventArgs.cs create mode 100644 source/ShiftUI/ListView/ColumnClickEventHandler.cs create mode 100644 source/ShiftUI/ListView/ColumnHeader.cs create mode 100644 source/ShiftUI/ListView/ColumnHeaderAutoResizeStyle.cs create mode 100644 source/ShiftUI/ListView/ColumnHeaderConverter.cs create mode 100644 source/ShiftUI/ListView/ColumnHeaderStyle.cs create mode 100644 source/ShiftUI/ListView/ColumnReorderedEventArgs.cs create mode 100644 source/ShiftUI/ListView/ColumnReorderedEventHandler.cs create mode 100644 source/ShiftUI/ListView/ColumnStyle.cs create mode 100644 source/ShiftUI/ListView/ColumnWidthChangedEventArgs.cs create mode 100644 source/ShiftUI/ListView/ColumnWidthChangedEventHandler.cs create mode 100644 source/ShiftUI/ListView/ColumnWidthChangingEventArgs.cs create mode 100644 source/ShiftUI/ListView/ColumnWidthChangingEventHandler.cs create mode 100644 source/ShiftUI/ListView/ListViewAlignment.cs create mode 100644 source/ShiftUI/ListView/ListViewGroup.cs create mode 100644 source/ShiftUI/ListView/ListViewGroupCollection.cs create mode 100644 source/ShiftUI/ListView/ListViewHitTestInfo.cs create mode 100644 source/ShiftUI/ListView/ListViewHitTestLocations.cs create mode 100644 source/ShiftUI/ListView/ListViewInsertionMark.cs create mode 100644 source/ShiftUI/ListView/ListViewItemConverter.cs create mode 100644 source/ShiftUI/ListView/ListViewItemMouseHoverEventArgs.cs create mode 100644 source/ShiftUI/ListView/ListViewItemMouseHoverEventHandler.cs create mode 100644 source/ShiftUI/ListView/ListViewItemSelectionChangedEventArgs.cs create mode 100644 source/ShiftUI/ListView/ListViewItemSelectionChangedEventHandler.cs create mode 100644 source/ShiftUI/ListView/ListViewItemStates.cs create mode 100644 source/ShiftUI/ListView/ListViewVirtualItemsSelectionRangeChangedEventArgs.cs create mode 100644 source/ShiftUI/ListView/ListViewVirtualItemsSelectionRangeChangedEventHandler.cs create mode 100644 source/ShiftUI/Menu/Menu.cs create mode 100644 source/ShiftUI/Menu/MenuAPI.cs create mode 100644 source/ShiftUI/Menu/MenuGlyph.cs create mode 100644 source/ShiftUI/Menu/MenuItem.cs create mode 100644 source/ShiftUI/Menu/MenuMerge.cs create mode 100644 source/ShiftUI/Menu/MenuStrip.cs create mode 100644 source/ShiftUI/MonoTODOAttribute.cs create mode 100644 source/ShiftUI/Mouse/DragAction.cs create mode 100644 source/ShiftUI/Mouse/DragDropEffects.cs create mode 100644 source/ShiftUI/Mouse/DragEventArgs.cs create mode 100644 source/ShiftUI/Mouse/DragEventHandler.cs create mode 100644 source/ShiftUI/Mouse/MouseEventArgs.cs create mode 100644 source/ShiftUI/Mouse/MouseEventHandler.cs create mode 100644 source/ShiftUI/Properties/AssemblyInfo.cs create mode 100644 source/ShiftUI/Properties/Resources.Designer.cs create mode 100644 source/ShiftUI/Properties/Resources.resx create mode 100644 source/ShiftUI/RTF/Charcode.cs create mode 100644 source/ShiftUI/RTF/Charset.cs create mode 100644 source/ShiftUI/RTF/CharsetFlags.cs create mode 100644 source/ShiftUI/RTF/CharsetType.cs create mode 100644 source/ShiftUI/RTF/ClassDelegate.cs create mode 100644 source/ShiftUI/RTF/Color.cs create mode 100644 source/ShiftUI/RTF/DestinationDelegate.cs create mode 100644 source/ShiftUI/RTF/Font.cs create mode 100644 source/ShiftUI/RTF/KeyStruct.cs create mode 100644 source/ShiftUI/RTF/KeysInit.cs create mode 100644 source/ShiftUI/RTF/Major.cs create mode 100644 source/ShiftUI/RTF/Minor.cs create mode 100644 source/ShiftUI/RTF/Picture.cs create mode 100644 source/ShiftUI/RTF/README create mode 100644 source/ShiftUI/RTF/RTF.cs create mode 100644 source/ShiftUI/RTF/RTFException.cs create mode 100644 source/ShiftUI/RTF/StandardCharCode.cs create mode 100644 source/ShiftUI/RTF/StandardCharName.cs create mode 100644 source/ShiftUI/RTF/Style.cs create mode 100644 source/ShiftUI/RTF/StyleElement.cs create mode 100644 source/ShiftUI/RTF/StyleType.cs create mode 100644 source/ShiftUI/RTF/TextMap.cs create mode 100644 source/ShiftUI/RTF/TokenClass.cs create mode 100644 source/ShiftUI/RTF/rtf.csproj create mode 100644 source/ShiftUI/RTF/test.cs create mode 100644 source/ShiftUI/Resources/DnDCopy.cur create mode 100644 source/ShiftUI/Resources/DnDLink.cur create mode 100644 source/ShiftUI/Resources/DnDMove.cur create mode 100644 source/ShiftUI/Resources/DnDNo.cur create mode 100644 source/ShiftUI/Resources/NESW.cur create mode 100644 source/ShiftUI/Resources/NWSE.cur create mode 100644 source/ShiftUI/Resources/SplitterNS.cur create mode 100644 source/ShiftUI/Resources/SplitterWE.cur create mode 100644 source/ShiftUI/Resources/keyboard_table.bin create mode 100644 source/ShiftUI/Resources/scan_table.bin create mode 100644 source/ShiftUI/Resources/vkey_table.txt create mode 100644 source/ShiftUI/ScrollableControl.cs create mode 100644 source/ShiftUI/ShiftUI.csproj create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/BackgroundType.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/BooleanProperty.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/BorderType.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/CheckBoxState.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/ColorProperty.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/ComboBoxState.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/ContentAlignment.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/EdgeEffects.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/EdgeStyle.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/Edges.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/EnumProperty.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/FilenameProperty.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/FillType.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/FontProperty.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/GlyphFontSizingType.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/GlyphType.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/GroupBoxState.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/GtkPlus.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/HitTestCode.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/HitTestOptions.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/HorizontalAlign.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/IVisualStyles.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/IconEffect.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/ImageOrientation.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/ImageSelectType.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/IntegerProperty.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/MarginProperty.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/OffsetType.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/PointProperty.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/PushButtonState.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/RadioButtonState.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/ScrollBarArrowButtonState.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/ScrollBarSizeBoxState.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/ScrollBarState.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/SizingType.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/StringProperty.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/TabItemState.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/TextBoxState.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/TextMetrics.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/TextMetricsCharacterSet.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/TextMetricsPitchAndFamilyValues.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/TextShadowType.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/ThemeSizeType.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/ToolBarState.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/TrackBarThumbState.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/TrueSizeScalingType.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/UXTheme.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/VerticalAlignment.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStyleElement.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStyleInformation.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStyleRenderer.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStyleState.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStylesEngine.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStylesGtkPlus.cs create mode 100644 source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStylesNative.cs create mode 100644 source/ShiftUI/Theming/Default/.gitattributes create mode 100644 source/ShiftUI/Theming/Default/ButtonPainter.cs create mode 100644 source/ShiftUI/Theming/Default/CheckBoxPainter.cs create mode 100644 source/ShiftUI/Theming/Default/LabelPainter.cs create mode 100644 source/ShiftUI/Theming/Default/LinkLabelPainter.cs create mode 100644 source/ShiftUI/Theming/Default/RadioButtonPainter.cs create mode 100644 source/ShiftUI/Theming/Default/TabControlPainter.cs create mode 100644 source/ShiftUI/Theming/Default/ToolStripPainter.cs create mode 100644 source/ShiftUI/Theming/Nice/.gitattributes create mode 100644 source/ShiftUI/Theming/Nice/TabControlPainter.cs create mode 100644 source/ShiftUI/Theming/ShiftOS.cs create mode 100644 source/ShiftUI/Theming/ThemeElements.cs create mode 100644 source/ShiftUI/Theming/ThemeElementsClearlooks.cs create mode 100644 source/ShiftUI/Theming/ThemeElementsDefault.cs create mode 100644 source/ShiftUI/Theming/ThemeElementsGtk.cs create mode 100644 source/ShiftUI/Theming/ThemeElementsMemphis.cs create mode 100644 source/ShiftUI/Theming/ThemeElementsNice.cs create mode 100644 source/ShiftUI/Theming/ThemeElementsVisualStyles.cs create mode 100644 source/ShiftUI/Theming/ThemeEngine.cs create mode 100644 source/ShiftUI/Theming/ThemeSkinnable.cs create mode 100644 source/ShiftUI/Theming/ThemeVisualStyles.cs create mode 100644 source/ShiftUI/Theming/ThemeWin32Classic.cs create mode 100644 source/ShiftUI/Theming/VisualStyles/CheckBoxPainter.cs create mode 100644 source/ShiftUI/Theming/VisualStyles/RadioButtonPainter.cs create mode 100644 source/ShiftUI/Theming/VisualStyles/TabControlPainter.cs create mode 100644 source/ShiftUI/Theming/VisualStyles/ToolStripPainter.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStrip.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripArrowRenderEventArgs.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripArrowRenderEventHandler.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripButton.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripComboBox.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripContainer.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripContentPanel.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripContentPanelRenderEventArgs.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripContentPanelRenderEventHandler.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripControlHost.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripDropDown.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripDropDownButton.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripDropDownCloseReason.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripDropDownClosedEventArgs.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripDropDownClosedEventHandler.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripDropDownClosingEventArgs.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripDropDownClosingEventHandler.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripDropDownDirection.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripDropDownItem.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripDropDownItemAccessibleObject.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripDropDownMenu.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripGripDisplayStyle.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripGripRenderEventArgs.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripGripRenderEventHandler.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripGripStyle.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItem.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItemAlignment.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItemClickedEventArgs.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItemClickedEventHandler.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItemCollection.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItemDisplayStyle.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItemEventArgs.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItemEventHandler.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItemEventType.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItemImageRenderEventArgs.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItemImageRenderEventHandler.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItemImageScaling.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItemOverflow.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItemPlacement.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItemRenderEventArgs.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItemRenderEventHandler.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItemTextRenderEventArgs.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripItemTextRenderEventHandler.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripLabel.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripLayoutStyle.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripManager.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripManagerRenderMode.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripMenuItem.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripOverflow.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripOverflowButton.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripPanel.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripPanelRenderEventArgs.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripPanelRenderEventHandler.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripPanelRow.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripProfessionalRenderer.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripProgressBar.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripRenderEventArgs.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripRenderEventHandler.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripRenderMode.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripRenderer.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripSeparator.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripSeparatorRenderEventArgs.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripSeparatorRenderEventHandler.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripSplitButton.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripSplitStackLayout.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripStatusLabel.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripStatusLabelBorderSides.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripSystemRenderer.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripTextBox.cs create mode 100644 source/ShiftUI/ToolStrip/ToolStripTextDirection.cs create mode 100644 source/ShiftUI/Widget.cs create mode 100644 source/ShiftUI/Widgets/Button.cs create mode 100644 source/ShiftUI/Widgets/CaptionButton.cs create mode 100644 source/ShiftUI/Widgets/CategoryGridEntry.cs create mode 100644 source/ShiftUI/Widgets/CheckBox.cs create mode 100644 source/ShiftUI/Widgets/CheckedListBox.cs create mode 100644 source/ShiftUI/Widgets/CollectionEditor.cs create mode 100644 source/ShiftUI/Widgets/ComboBox.cs create mode 100644 source/ShiftUI/Widgets/ContainerControl.cs create mode 100644 source/ShiftUI/Widgets/DateTimePicker.cs create mode 100644 source/ShiftUI/Widgets/FlowLayoutPanel.cs create mode 100644 source/ShiftUI/Widgets/GridEntry.cs create mode 100644 source/ShiftUI/Widgets/GridItemCollection.cs create mode 100644 source/ShiftUI/Widgets/GroupBox.cs create mode 100644 source/ShiftUI/Widgets/HScrollBar.cs create mode 100644 source/ShiftUI/Widgets/IRootGridEntry.cs create mode 100644 source/ShiftUI/Widgets/ImplicitHScrollBar.cs create mode 100644 source/ShiftUI/Widgets/ImplicitVScrollBar.cs create mode 100644 source/ShiftUI/Widgets/Label.cs create mode 100644 source/ShiftUI/Widgets/LabelEditTextBox.cs create mode 100644 source/ShiftUI/Widgets/LinkLabel.cs create mode 100644 source/ShiftUI/Widgets/ListBox.cs create mode 100644 source/ShiftUI/Widgets/ListControl.cs create mode 100644 source/ShiftUI/Widgets/ListView.cs create mode 100644 source/ShiftUI/Widgets/ListViewItem.cs create mode 100644 source/ShiftUI/Widgets/MonthCalendar.cs create mode 100644 source/ShiftUI/Widgets/NotifyIcon.cs create mode 100644 source/ShiftUI/Widgets/Panel.cs create mode 100644 source/ShiftUI/Widgets/PictureBox.cs create mode 100644 source/ShiftUI/Widgets/PictureBoxSizeMode.cs create mode 100644 source/ShiftUI/Widgets/ProgressBar.cs create mode 100644 source/ShiftUI/Widgets/PropertiesTab.cs create mode 100644 source/ShiftUI/Widgets/PropertyGrid.cs create mode 100644 source/ShiftUI/Widgets/PropertyGridCommands.cs create mode 100644 source/ShiftUI/Widgets/PropertyGridTextBox.cs create mode 100644 source/ShiftUI/Widgets/PropertyGridView.cs create mode 100644 source/ShiftUI/Widgets/RadioButton.cs create mode 100644 source/ShiftUI/Widgets/RichTextBox.cs create mode 100644 source/ShiftUI/Widgets/RootGridEntry.cs create mode 100644 source/ShiftUI/Widgets/ScrollBar.cs create mode 100644 source/ShiftUI/Widgets/ScrollBarRenderer.cs create mode 100644 source/ShiftUI/Widgets/ScrollButton.cs create mode 100644 source/ShiftUI/Widgets/SizeGrip.cs create mode 100644 source/ShiftUI/Widgets/SizeGripStyle.cs create mode 100644 source/ShiftUI/Widgets/StatusBar.cs create mode 100644 source/ShiftUI/Widgets/StatusBarPanel.cs create mode 100644 source/ShiftUI/Widgets/StatusStrip.cs create mode 100644 source/ShiftUI/Widgets/TabControl.cs create mode 100644 source/ShiftUI/Widgets/TabPage.cs create mode 100644 source/ShiftUI/Widgets/TableLayoutPanel.cs create mode 100644 source/ShiftUI/Widgets/TextBox.cs create mode 100644 source/ShiftUI/Widgets/TextBoxBase.cs create mode 100644 source/ShiftUI/Widgets/TrackBar.cs create mode 100644 source/ShiftUI/Widgets/TreeNode.cs create mode 100644 source/ShiftUI/Widgets/TreeView.cs create mode 100644 source/ShiftUI/Widgets/UserWidget.cs create mode 100644 source/ShiftUI/Widgets/VScrollBar.cs create mode 100644 source/ShiftUI/keyboards.resources create mode 100644 source/WindowsFormsApplication1/Controls/WinFormsHost.cs diff --git a/source/ShiftOS.sln b/source/ShiftOS.sln index b45576c..ccf69a3 100644 --- a/source/ShiftOS.sln +++ b/source/ShiftOS.sln @@ -10,6 +10,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution README.md = README.md EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShiftUI", "ShiftUI\ShiftUI.csproj", "{C56E34D0-4749-4A73-9469-BCCD063569CD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -20,6 +22,10 @@ Global {00BE72D0-B744-48BA-9C60-BC429757FC32}.Debug|Any CPU.Build.0 = Debug|Any CPU {00BE72D0-B744-48BA-9C60-BC429757FC32}.Release|Any CPU.ActiveCfg = Release|Any CPU {00BE72D0-B744-48BA-9C60-BC429757FC32}.Release|Any CPU.Build.0 = Release|Any CPU + {C56E34D0-4749-4A73-9469-BCCD063569CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C56E34D0-4749-4A73-9469-BCCD063569CD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C56E34D0-4749-4A73-9469-BCCD063569CD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C56E34D0-4749-4A73-9469-BCCD063569CD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/source/ShiftUI/Application.cs b/source/ShiftUI/Application.cs new file mode 100644 index 0000000..5630512 --- /dev/null +++ b/source/ShiftUI/Application.cs @@ -0,0 +1,1123 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 - 2006 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// Daniel Nauck (dna(at)mono-project(dot)de) +// + +// COMPLETE + +#undef DebugRunLoop + +using Microsoft.Win32; +using System; +using System.Drawing; +using System.ComponentModel; +using System.Collections; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Threading; +using System.Text; +using ShiftUI.VisualStyles; +using ShiftUI.ShiftOS; + +namespace ShiftUI +{ + public sealed class Application + { + internal class MWFThread + { + #region Fields + + private ApplicationContext context; + private bool messageloop_started; + private bool handling_exception; + private int thread_id; + + private static readonly Hashtable threads = new Hashtable(); + + #endregion // Fields + + #region Constructors + + private MWFThread() + { + } + + #endregion // Constructors + + #region Properties + + public ApplicationContext Context { + get { return context; } + set { context = value; } + } + + public bool MessageLoop { + get { return messageloop_started; } + set { messageloop_started = value; } + } + + public bool HandlingException { + get { return handling_exception; } + set { handling_exception = value; } + } + + public static int LoopCount { + get { + lock (threads) { + int loops = 0; + + foreach (MWFThread thread in threads.Values) { + if (thread.messageloop_started) + loops++; + } + + return loops; + } + } + } + + public static MWFThread Current { + get { + MWFThread thread = null; + + lock (threads) { + thread = (MWFThread) threads [Thread.CurrentThread.GetHashCode ()]; + if (thread == null) { + thread = new MWFThread(); + thread.thread_id = Thread.CurrentThread.GetHashCode (); + threads [thread.thread_id] = thread; + } + } + + return thread; + } + } + + #endregion // Properties + + #region Methods + + public void Exit () + { + if (context != null) + context.ExitThread(); + context = null; + + if (Application.ThreadExit != null) + Application.ThreadExit(null, EventArgs.Empty); + + if (LoopCount == 0) { + if (Application.ApplicationExit != null) + Application.ApplicationExit (null, EventArgs.Empty); + } + + ((MWFThread) threads [thread_id]).MessageLoop = false; + } + + #endregion // Methods + } + + public static void LoadSkin(Skin skin) + { + if (skin == null) + throw new Exception("Skin can't be null."); + _loadedSkin = skin; + } + + private static ShiftOS.Skin _loadedSkin = null; + private static bool browser_embedded; + private static InputLanguage input_language = InputLanguage.CurrentInputLanguage; + private static string safe_caption_format = "{1} - {0} - {2}"; + private static readonly ArrayList message_filters = new ArrayList(); + private static readonly FormCollection forms = new FormCollection (); + + private static bool use_wait_cursor; + private static ToolStrip keyboard_capture; + private static VisualStyleState visual_style_state = VisualStyleState.ClientAndNonClientAreasEnabled; + static bool visual_styles_enabled; + + private Application () + { + browser_embedded = false; + } + + static Application () + { + // Attempt to load UIA support for winforms + // UIA support requires .NET 2.0 + InitializeUIAutomation (); + } + + #region Private Methods + + private static void InitializeUIAutomation () + { + // Initialize the UIAutomationWinforms Global class, + // which create some listeners which subscribe to internal + // MWF events so that it can provide a11y support for MWF + const string UIA_WINFORMS_ASSEMBLY = + "UIAutomationWinforms, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f4ceacb585d99812"; + MethodInfo init_method; + Assembly mwf_providers = null; + try { + mwf_providers = Assembly.Load (UIA_WINFORMS_ASSEMBLY); + } catch { } + + if (mwf_providers == null) + return; + + const string UIA_WINFORMS_TYPE = "Mono.UIAutomation.Winforms.Global"; + const string UIA_WINFORMS_METHOD = "Initialize"; + try { + Type global_type = mwf_providers.GetType (UIA_WINFORMS_TYPE, false); + if (global_type != null) { + init_method = global_type.GetMethod (UIA_WINFORMS_METHOD, + BindingFlags.Static | + BindingFlags.Public); + if (init_method != null) + init_method.Invoke (null, new object [] {}); + else + throw new Exception (String.Format ("Method {0} not found in type {1}.", + UIA_WINFORMS_METHOD, UIA_WINFORMS_TYPE)); + } + else + throw new Exception (String.Format ("Type {0} not found in assembly {1}.", + UIA_WINFORMS_TYPE, UIA_WINFORMS_ASSEMBLY)); + } catch (Exception ex) { + Console.Error.WriteLine ("Error setting up UIA: " + ex); + } + } + + internal static void CloseForms (Thread thread) + { + #if DebugRunLoop + Console.WriteLine(" CloseForms({0}) called", thread); + #endif + + ArrayList forms_to_close = new ArrayList (); + + lock (forms) { + foreach (Form f in forms) { + if (thread == null || thread == f.creator_thread) + forms_to_close.Add (f); + } + + foreach (Form f in forms_to_close) { + #if DebugRunLoop + Console.WriteLine(" Closing form {0}", f); + #endif + f.Dispose (); + } + } + } + + #endregion // Private methods + + #region Public Static Properties + + public static bool AllowQuit { + get { + return !browser_embedded; + } + } + + public static ShiftOS.Skin CurrentSkin + { + get + { + return _loadedSkin; + } + } + + public static string CommonAppDataPath { + get { + return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.CommonApplicationData)); + } + } + + public static RegistryKey CommonAppDataRegistry { + get { + string key = string.Format ("Software\\{0}\\{1}\\{2}", CompanyName, ProductName, ProductVersion); + + return Registry.LocalMachine.CreateSubKey (key); + } + } + + public static string CompanyName { + get { + string company = string.Empty; + + Assembly assembly = Assembly.GetEntryAssembly (); + + if (assembly == null) + assembly = Assembly.GetCallingAssembly (); + + AssemblyCompanyAttribute[] attrs = (AssemblyCompanyAttribute[]) + assembly.GetCustomAttributes (typeof(AssemblyCompanyAttribute), true); + if (attrs != null && attrs.Length > 0) + company = attrs [0].Company; + + // If there is no [AssemblyCompany], return the outermost namespace + // on Main () + if (company == null || company.Length == 0) + if (assembly.EntryPoint != null) { + company = assembly.EntryPoint.DeclaringType.Namespace; + + if (company != null) { + int firstDot = company.IndexOf ('.'); + if (firstDot >= 0) + company = company.Substring (0, firstDot); + } + } + + // If that doesn't work, return the name of class containing Main () + if (company == null || company.Length == 0) + if (assembly.EntryPoint != null) + company = assembly.EntryPoint.DeclaringType.FullName; + + return company; + } + } + + public static CultureInfo CurrentCulture { + get { + return Thread.CurrentThread.CurrentUICulture; + } + set { + Thread.CurrentThread.CurrentUICulture = value; + } + } + + public static InputLanguage CurrentInputLanguage { + get { + return input_language; + } + set { + input_language=value; + } + } + + public static string ExecutablePath { + get { + return Path.GetFullPath (Environment.GetCommandLineArgs ()[0]); + } + } + + public static string LocalUserAppDataPath { + get { + return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData)); + } + } + + public static bool MessageLoop { + get { + return MWFThread.Current.MessageLoop; + } + } + + public static string ProductName { + get { + string name = string.Empty; + + Assembly assembly = Assembly.GetEntryAssembly (); + + if (assembly == null) + assembly = Assembly.GetCallingAssembly (); + + AssemblyProductAttribute[] attrs = (AssemblyProductAttribute[]) + assembly.GetCustomAttributes (typeof(AssemblyProductAttribute), true); + + if (attrs != null && attrs.Length > 0) + name = attrs [0].Product; + + // If there is no [AssemblyProduct], .NET returns the name of + // the innermost namespace and if that fails, resorts to the + // name of the class containing Main () + if (name == null || name.Length == 0) + if (assembly.EntryPoint != null) { + name = assembly.EntryPoint.DeclaringType.Namespace; + + if (name != null) { + int lastDot = name.LastIndexOf ('.'); + if (lastDot >= 0 && lastDot < name.Length - 1) + name = name.Substring (lastDot + 1); + } + + if (name == null || name.Length == 0) + name = assembly.EntryPoint.DeclaringType.FullName; + } + + return name; + } + } + + public static string ProductVersion { + get { + String version = string.Empty; + + Assembly assembly = Assembly.GetEntryAssembly (); + + if (assembly == null) + assembly = Assembly.GetCallingAssembly (); + + AssemblyInformationalVersionAttribute infoVersion = + Attribute.GetCustomAttribute (assembly, + typeof (AssemblyInformationalVersionAttribute)) + as AssemblyInformationalVersionAttribute; + + if (infoVersion != null) + version = infoVersion.InformationalVersion; + + // If [AssemblyFileVersion] is present it is used + // before resorting to assembly version + if (version == null || version.Length == 0) { + AssemblyFileVersionAttribute fileVersion = + Attribute.GetCustomAttribute (assembly, + typeof (AssemblyFileVersionAttribute)) + as AssemblyFileVersionAttribute; + if (fileVersion != null) + version = fileVersion.Version; + } + + // If neither [AssemblyInformationalVersionAttribute] + // nor [AssemblyFileVersion] are present, then use + // the assembly version + if (version == null || version.Length == 0) + version = assembly.GetName ().Version.ToString (); + + return version; + } + } + + public static string SafeTopLevelCaptionFormat { + get { + return safe_caption_format; + } + set { + safe_caption_format = value; + } + } + + public static string StartupPath { + get { + return Path.GetDirectoryName (Application.ExecutablePath); + } + } + + public static string UserAppDataPath { + get { + return CreateDataPath (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData)); + } + } + + public static RegistryKey UserAppDataRegistry { + get { + string key = string.Format ("Software\\{0}\\{1}\\{2}", CompanyName, ProductName, ProductVersion); + + return Registry.CurrentUser.CreateSubKey (key); + } + } + + public static bool UseWaitCursor { + get { + return use_wait_cursor; + } + set { + use_wait_cursor = value; + if (use_wait_cursor) { + foreach (Form form in OpenForms) { + form.Cursor = Cursors.WaitCursor; + } + } + } + } + + public static bool RenderWithVisualStyles { + get { + if (VisualStyleInformation.IsSupportedByOS) { + if (!VisualStyleInformation.IsEnabledByUser) + return false; + if (!XplatUI.ThemesEnabled) + return false; + if (Application.VisualStyleState == VisualStyleState.ClientAndNonClientAreasEnabled) + return true; + if (Application.VisualStyleState == VisualStyleState.ClientAreaEnabled) + return true; + } + return false; + } + } + + public static VisualStyleState VisualStyleState { + get { return Application.visual_style_state; } + set { Application.visual_style_state = value; } + } + + #endregion + + #region Public Static Methods + + public static void AddMessageFilter (IMessageFilter value) + { + lock (message_filters) { + message_filters.Add (value); + } + } + + internal static void AddKeyFilter (IKeyFilter value) + { + XplatUI.AddKeyFilter (value); + } + + public static void DoEvents () + { + XplatUI.DoEvents (); + } + + public static void EnableVisualStyles () + { + try { + visual_styles_enabled = true; + XplatUI.EnableThemes (); + } + catch { + visual_styles_enabled = false; + } + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public static bool FilterMessage (ref Message message) + { + lock (message_filters) { + for (int i = 0; i < message_filters.Count; i++) { + IMessageFilter filter = (IMessageFilter) message_filters[i]; + if (filter.PreFilterMessage (ref message)) + return true; + } + } + return false; + } + + // + // If true, it uses GDI+, performance reasons were quoted + // + static internal bool use_compatible_text_rendering = true; + + public static void SetCompatibleTextRenderingDefault (bool defaultValue) + { + use_compatible_text_rendering = defaultValue; + } + + public static FormCollection OpenForms { + get { + return forms; + } + } + + [MonoNotSupported ("Only applies when Winforms is being hosted by an unmanaged app.")] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public static void RegisterMessageLoop (MessageLoopCallback callback) + { + } + + [MonoNotSupported ("Empty stub.")] + public static bool SetSuspendState (PowerState state, bool force, bool disableWakeEvent) + { + return false; + } + + [MonoNotSupported ("Empty stub.")] + public static void SetUnhandledExceptionMode (UnhandledExceptionMode mode) + { + //FIXME: a stub to fill + } + + [MonoNotSupported ("Empty stub.")] + public static void SetUnhandledExceptionMode (UnhandledExceptionMode mode, bool threadScope) + { + //FIXME: a stub to fill + } + + [MonoNotSupported ("Only applies when Winforms is being hosted by an unmanaged app.")] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public static void UnregisterMessageLoop () + { + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public static void RaiseIdle (EventArgs e) + { + XplatUI.RaiseIdle (e); + } + + public static void Restart () + { + //FIXME: ClickOnce stuff using the Update or UpdateAsync methods. + //FIXME: SecurityPermission: Restart () requires IsUnrestricted permission. + + if (Assembly.GetEntryAssembly () == null) + throw new NotSupportedException ("The method 'Restart' is not supported by this application type."); + + string mono_path = null; + + //Get mono path + PropertyInfo gac = typeof (Environment).GetProperty ("GacPath", BindingFlags.Static | BindingFlags.NonPublic); + MethodInfo get_gac = null; + if (gac != null) + get_gac = gac.GetGetMethod (true); + + if (get_gac != null) { + string gac_path = Path.GetDirectoryName ((string)get_gac.Invoke (null, null)); + string mono_prefix = Path.GetDirectoryName (Path.GetDirectoryName (gac_path)); + + if (XplatUI.RunningOnUnix) { + mono_path = Path.Combine (mono_prefix, "bin/mono"); + if (!File.Exists (mono_path)) + mono_path = "mono"; + } else { + mono_path = Path.Combine (mono_prefix, "bin\\mono.bat"); + + if (!File.Exists (mono_path)) + mono_path = Path.Combine (mono_prefix, "bin\\mono.exe"); + + if (!File.Exists (mono_path)) + mono_path = Path.Combine (mono_prefix, "mono\\mono\\mini\\mono.exe"); + + if (!File.Exists (mono_path)) + throw new FileNotFoundException (string.Format ("Windows mono path not found: '{0}'", mono_path)); + } + } + + //Get command line arguments + StringBuilder argsBuilder = new StringBuilder (); + string[] args = Environment.GetCommandLineArgs (); + for (int i = 0; i < args.Length; i++) + { + argsBuilder.Append (string.Format ("\"{0}\" ", args[i])); + } + string arguments = argsBuilder.ToString (); + ProcessStartInfo procInfo = Process.GetCurrentProcess ().StartInfo; + + if (mono_path == null) { //it is .NET on Windows + procInfo.FileName = args[0]; + procInfo.Arguments = arguments.Remove (0, args[0].Length + 3); //1 space and 2 quotes + } + else { + procInfo.Arguments = arguments; + procInfo.FileName = mono_path; + } + + procInfo.WorkingDirectory = Environment.CurrentDirectory; + + Application.Exit (); + Process.Start (procInfo); + } + + public static void Exit () + { + Exit (new CancelEventArgs ()); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public static void Exit (CancelEventArgs e) + { + ArrayList forms_to_close; + + lock (forms) { + forms_to_close = new ArrayList (forms); + + foreach (Form f in forms_to_close) { + // Give each form a chance to cancel the Application.Exit + e.Cancel = f.FireClosingEvents (CloseReason.ApplicationExitCall, false); + + if (e.Cancel) + return; + + f.suppress_closing_events = true; + f.Close (); + f.Dispose (); + } + } + + XplatUI.PostQuitMessage (0); + } + + public static void ExitThread() + { + CloseForms(Thread.CurrentThread); + // this might not be right - need to investigate (somehow) if a WM_QUIT message is generated here + XplatUI.PostQuitMessage(0); + } + + public static ApartmentState OleRequired () + { + //throw new NotImplementedException("OLE Not supported by this ShiftUI implementation"); + return ApartmentState.Unknown; + } + + public static void OnThreadException (Exception t) + { + if (MWFThread.Current.HandlingException) { + /* we're already handling an exception and we got + another one? print it out and exit, this means + we've got a runtime/SWF bug. */ + Console.WriteLine (t); + // Don't use Application.Exit here, since it may cause a stack overflow + // in certain cases. It's however hard to reproduce since it seems to + // be depending on when the GC kicks in. + Environment.Exit(1); + } + + try { + MWFThread.Current.HandlingException = true; + + if (Application.ThreadException != null) { + Application.ThreadException(null, new ThreadExceptionEventArgs(t)); + return; + } + + if (SystemInformation.UserInteractive) { + Form form = new ThreadExceptionDialog (t); + form.ShowDialog (); + } else { + Console.WriteLine (t.ToString ()); + Application.Exit (); + } + } finally { + MWFThread.Current.HandlingException = false; + } + } + + public static void RemoveMessageFilter (IMessageFilter value) + { + lock (message_filters) { + message_filters.Remove (value); + } + } + + public static void Run () + { + Run (new ApplicationContext ()); + } + + public static void Run (Form mainForm) + { + Run (new ApplicationContext (mainForm)); + } + + internal static void FirePreRun () + { + EventHandler handler = PreRun; + if (handler != null) + handler (null, EventArgs.Empty); + } + + public static void Run (ApplicationContext context) + { + // If a sync context hasn't been created by now, create + // a default one + if (SynchronizationContext.Current == null) + SynchronizationContext.SetSynchronizationContext (new SynchronizationContext ()); + + RunLoop (false, context); + + // Reset the sync context back to the default + if (SynchronizationContext.Current is WindowsFormsSynchronizationContext) + WindowsFormsSynchronizationContext.Uninstall (); + } + + private static void DisableFormsForModalLoop (Queue toplevels, ApplicationContext context) + { + Form f; + + lock (forms) { + IEnumerator control = forms.GetEnumerator (); + + while (control.MoveNext ()) { + f = (Form)control.Current; + + // Don't disable the main form. + if (f == context.MainForm) { + continue; + } + + // Don't disable any children of the main form. + // These do not have to be MDI children. + Widget current = f; + bool is_child_of_main = false; ; + + do { + if (current.Parent == context.MainForm) { + is_child_of_main = true; + break; + } + current = current.Parent; + } while (current != null); + + if (is_child_of_main) + continue; + + // Disable the rest + if (f.IsHandleCreated && XplatUI.IsEnabled (f.Handle)) { +#if DebugRunLoop + Console.WriteLine(" Disabling form {0}", f); +#endif + XplatUI.EnableWindow (f.Handle, false); + toplevels.Enqueue (f); + } + } + } + + } + + + private static void EnableFormsForModalLoop (Queue toplevels, ApplicationContext context) + { + while (toplevels.Count > 0) { +#if DebugRunLoop + Console.WriteLine(" Re-Enabling form form {0}", toplevels.Peek()); +#endif + Form c = (Form) toplevels.Dequeue (); + if (c.IsHandleCreated) { + XplatUI.EnableWindow (c.window.Handle, true); + context.MainForm = c; + } + } +#if DebugRunLoop + Console.WriteLine(" Done with the re-enable"); +#endif + } + + internal static void RunLoop (bool Modal, ApplicationContext context) + { + Queue toplevels; + MSG msg; + Object queue_id; + MWFThread thread; + ApplicationContext previous_thread_context; + + thread = MWFThread.Current; + + /* + * There is a NotWorking test for this, but since we are using this method both for Form.ShowDialog as for ApplicationContexts we'll + * fail on nested ShowDialogs, so disable the check for the moment. + */ + //if (thread.MessageLoop) { + // throw new InvalidOperationException ("Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead."); + //} + + msg = new MSG(); + + if (context == null) + context = new ApplicationContext(); + + previous_thread_context = thread.Context; + thread.Context = context; + + if (context.MainForm != null) { + context.MainForm.is_modal = Modal; + context.MainForm.context = context; + context.MainForm.closing = false; + context.MainForm.Visible = true; // Cannot use Show() or scaling gets confused by menus + // XXX the above line can be used to close the form. another problem with our handling of Show/Activate. + if (context.MainForm != null) + context.MainForm.Activate(); + } + + #if DebugRunLoop + Console.WriteLine("Entering RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL"); + #endif + + if (Modal) { + toplevels = new Queue (); + DisableFormsForModalLoop (toplevels, context); + + // FIXME - need activate? + /* make sure the MainForm is enabled */ + if (context.MainForm != null) { + XplatUI.EnableWindow (context.MainForm.Handle, true); + XplatUI.SetModal(context.MainForm.Handle, true); + } + } else { + toplevels = null; + } + + queue_id = XplatUI.StartLoop(Thread.CurrentThread); + thread.MessageLoop = true; + + bool quit = false; + + while (!quit && XplatUI.GetMessage(queue_id, ref msg, IntPtr.Zero, 0, 0)) { + Message m = Message.Create(msg.hwnd, (int)msg.message, msg.wParam, msg.lParam); + + if (Application.FilterMessage (ref m)) + continue; + + switch((Msg)msg.message) { + case Msg.WM_KEYDOWN: + case Msg.WM_SYSKEYDOWN: + case Msg.WM_CHAR: + case Msg.WM_SYSCHAR: + case Msg.WM_KEYUP: + case Msg.WM_SYSKEYUP: + Widget c; + c = Widget.FromHandle(msg.hwnd); + + // If we have a control with keyboard capture (usually a *Strip) + // give it the message, and then drop the message + if (keyboard_capture != null) { + // WM_SYSKEYUP does not make it into ProcessCmdKey, so do it here + if ((Msg)m.Msg == Msg.WM_SYSKEYDOWN) + if (m.WParam.ToInt32() == (int)Keys.Menu) { + keyboard_capture.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.Keyboard); + continue; + } + + m.HWnd = keyboard_capture.Handle; + + switch (keyboard_capture.PreProcessWidgetMessageInternal (ref m)) { + case PreProcessWidgetstate.MessageProcessed: + continue; + case PreProcessWidgetstate.MessageNeeded: + case PreProcessWidgetstate.MessageNotNeeded: + if (((m.Msg == (int)Msg.WM_KEYDOWN || m.Msg == (int)Msg.WM_CHAR) && !keyboard_capture.ProcessWidgetMnemonic ((char)m.WParam))) { + if (c == null || !ControlOnToolStrip (c)) + continue; + else + m.HWnd = msg.hwnd; + } else + continue; + + break; + } + } + + if (((c != null) && c.PreProcessWidgetMessageInternal (ref m) != PreProcessWidgetstate.MessageProcessed) || + (c == null)) { + goto default; + } + break; + + case Msg.WM_LBUTTONDOWN: + case Msg.WM_MBUTTONDOWN: + case Msg.WM_RBUTTONDOWN: + if (keyboard_capture != null) { + Widget c2 = Widget.FromHandle (msg.hwnd); + + // the target is not a winforms control (an embedded control, perhaps), so + // release everything + if (c2 == null) { + ToolStripManager.FireAppClicked (); + goto default; + } + + // If we clicked a ToolStrip, we have to make sure it isn't + // the one we are on, or any of its parents or children + // If we clicked off the dropped down menu, release everything + if (c2 is ToolStrip) { + if ((c2 as ToolStrip).GetTopLevelToolStrip () != keyboard_capture.GetTopLevelToolStrip ()) + ToolStripManager.FireAppClicked (); + } else { + if (c2.Parent != null) + if (c2.Parent is ToolStripDropDownMenu) + if ((c2.Parent as ToolStripDropDownMenu).GetTopLevelToolStrip () == keyboard_capture.GetTopLevelToolStrip ()) + goto default; + if (c2.TopLevelWidget == null) + goto default; + + ToolStripManager.FireAppClicked (); + } + } + + goto default; + + case Msg.WM_QUIT: + quit = true; // make sure we exit + break; + default: + XplatUI.TranslateMessage (ref msg); + XplatUI.DispatchMessage (ref msg); + break; + } + + // If our Form doesn't have a handle anymore, it means it was destroyed and we need to *wait* for WM_QUIT. + if ((context.MainForm != null) && (!context.MainForm.IsHandleCreated)) + continue; + + // Handle exit, Form might have received WM_CLOSE and set 'closing' in response. + if ((context.MainForm != null) && (context.MainForm.closing || (Modal && !context.MainForm.Visible))) { + if (!Modal) { + XplatUI.PostQuitMessage (0); + } else { + break; + } + } + } + #if DebugRunLoop + Console.WriteLine (" RunLoop loop left"); + #endif + + thread.MessageLoop = false; + XplatUI.EndLoop (Thread.CurrentThread); + + if (Modal) { + Form old = context.MainForm; + + context.MainForm = null; + + EnableFormsForModalLoop (toplevels, context); + + if (context.MainForm != null && context.MainForm.IsHandleCreated) { + XplatUI.SetModal (context.MainForm.Handle, false); + } + #if DebugRunLoop + Console.WriteLine (" Done with the SetModal"); + #endif + old.RaiseCloseEvents (true, false); + old.is_modal = false; + } + + #if DebugRunLoop + Console.WriteLine ("Leaving RunLoop(Modal={0}, Form={1})", Modal, context.MainForm != null ? context.MainForm.ToString() : "NULL"); + #endif + + if (context.MainForm != null) { + context.MainForm.context = null; + context.MainForm = null; + } + + thread.Context = previous_thread_context; + + if (!Modal) + thread.Exit(); + } + + #endregion // Public Static Methods + + #region Events + + public static event EventHandler ApplicationExit; + + public static event EventHandler Idle { + add { + XplatUI.Idle += value; + } + remove { + XplatUI.Idle -= value; + } + } + + public static event EventHandler ThreadExit; + public static event ThreadExceptionEventHandler ThreadException; + + // These are used externally by the UIA framework + internal static event EventHandler FormAdded; + internal static event EventHandler PreRun; + +#pragma warning disable 0067 + [MonoTODO] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public static event EventHandler EnterThreadModal; + + [MonoTODO] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public static event EventHandler LeaveThreadModal; +#pragma warning restore 0067 + + #endregion // Events + + #region Public Delegates + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public delegate bool MessageLoopCallback (); + + #endregion + + #region Internal Properties + internal static ToolStrip KeyboardCapture { + get { return keyboard_capture; } + set { keyboard_capture = value; } + } + + internal static bool VisualStylesEnabled { + get { return visual_styles_enabled; } + } + #endregion + + #region Internal Methods + + internal static void AddForm (Form f) + { + lock (forms) + forms.Add (f); + // Signal that a Form has been added to this + // Application. Used by UIA to detect new Forms that + // need a11y support. This event may be fired even if + // the form has already been added, so clients should + // account for that when handling this signal. + if (FormAdded != null) + FormAdded (f, null); + } + + internal static void RemoveForm (Form f) + { + lock (forms) + forms.Remove (f); + } + + private static bool ControlOnToolStrip (Widget c) + { + Widget p = c.Parent; + + while (p != null) { + if (p is ToolStrip) + return true; + + p = p.Parent; + } + + return false; + } + + // Takes a starting path, appends company name, product name, and + // product version. If the directory doesn't exist, create it + private static string CreateDataPath (string basePath) + { + string path; + + path = Path.Combine (basePath, CompanyName); + path = Path.Combine (path, ProductName); + path = Path.Combine (path, ProductVersion); + + if (!Directory.Exists (path)) + Directory.CreateDirectory (path); + + return path; + } + #endregion + } +} diff --git a/source/ShiftUI/ApplicationContext.cs b/source/ShiftUI/ApplicationContext.cs new file mode 100644 index 0000000..34499f0 --- /dev/null +++ b/source/ShiftUI/ApplicationContext.cs @@ -0,0 +1,119 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + +using System.ComponentModel; +using System; + +namespace ShiftUI { + public class ApplicationContext : IDisposable + { + #region Local Variables + Form main_form; + object tag; + bool thread_exit_raised; + + #endregion // Local Variables + + #region Public Constructors & Destructors + public ApplicationContext() : this(null) { + } + + public ApplicationContext(Form mainForm) { + MainForm = mainForm; // Use property to get event handling setup + } + + ~ApplicationContext() { + this.Dispose(false); + } + #endregion // Public Constructors & Destructors + + #region Public Instance Properties + public Form MainForm { + get { + return main_form; + } + + set { + if (main_form != value) { + // Catch when the form is destroyed so we can fire OnMainFormClosed + + if (main_form != null) { + main_form.HandleDestroyed -= new EventHandler(OnMainFormClosed); + } + main_form = value; + if (main_form != null) { + main_form.HandleDestroyed += new EventHandler(OnMainFormClosed); + } + } + } + } + + [BindableAttribute (true)] + [DefaultValue (null)] + [LocalizableAttribute (false)] + [TypeConverterAttribute (typeof(StringConverter))] + public Object Tag { + get { return tag; } + set { tag = value; } + } + #endregion // Public Instance Properties + + #region Public Instance Methods + public void Dispose() { + Dispose(true); + GC.SuppressFinalize(this); + } + + public void ExitThread() { + ExitThreadCore(); + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + protected virtual void Dispose(bool disposing) { + MainForm = null; + tag = null; + } + + protected virtual void ExitThreadCore() { + if (Application.MWFThread.Current.Context == this) + XplatUI.PostQuitMessage(0); + if (!thread_exit_raised && ThreadExit != null) { + thread_exit_raised = true; + ThreadExit(this, EventArgs.Empty); + } + } + + protected virtual void OnMainFormClosed(object sender, EventArgs e) { + if (!MainForm.RecreatingHandle) + ExitThreadCore(); + } + #endregion // Public Instance Methods + + #region Events + public event EventHandler ThreadExit; + #endregion // Events + } +} diff --git a/source/ShiftUI/Cursor.cs b/source/ShiftUI/Cursor.cs new file mode 100644 index 0000000..a598e04 --- /dev/null +++ b/source/ShiftUI/Cursor.cs @@ -0,0 +1,663 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2010 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Reflection; + +namespace ShiftUI { + //[Editor(//"System.Drawing.Design.CursorEditor, " + Consts.AssemblySystem_Drawing_Design, typeof(System.Drawing.Design.UITypeEditor))] + [Serializable] + [TypeConverter(typeof(CursorConverter))] + public sealed class Cursor : IDisposable, ISerializable { + #region Internal Structs + [StructLayout (LayoutKind.Sequential)] + private struct CursorDir { + internal ushort idReserved; // Reserved + internal ushort idType; // resource type (2 for cursors) + internal ushort idCount; // how many cursors + internal CursorEntry[] idEntries; // the entries for each cursor + }; + + [StructLayout (LayoutKind.Sequential)] + private struct CursorEntry { + internal byte width; // Width of cursor + internal byte height; // Height of cursor + internal byte colorCount; // colors in cursor + internal byte reserved; // Reserved + internal ushort xHotspot; // Hotspot X + internal ushort yHotspot; // Hotspot Y + internal ushort bitCount; // Bits per pixel + internal uint sizeInBytes; // size of (CursorInfoHeader + ANDBitmap + ORBitmap) + internal uint fileOffset; // position in file + }; + + [StructLayout(LayoutKind.Sequential)] + private struct CursorInfoHeader { + internal uint biSize; + internal int biWidth; + internal int biHeight; + internal ushort biPlanes; + internal ushort biBitCount; + internal uint biCompression; + internal uint biSizeImage; + internal int biXPelsPerMeter; + internal int biYPelsPerMeter; + internal uint biClrUsed; + internal uint biClrImportant; + }; + + [StructLayout(LayoutKind.Sequential)] + private struct CursorImage { + internal CursorInfoHeader cursorHeader; // image header + internal uint[] cursorColors; // colors table + internal byte[] cursorXOR; // bits for XOR mask + internal byte[] cursorAND; // bits for AND mask + }; + #endregion // Internal structs + + #region Local Variables + private static Cursor current; + private CursorDir cursor_dir; + private CursorImage[] cursor_data; + private int id; + + internal IntPtr handle; + private Size size; + private Bitmap shape; + private Bitmap mask; + private Bitmap cursor; + internal string name; + private StdCursor std_cursor = (StdCursor) (-1); + + private object tag; + + #endregion // Local Variables + + #region Public Constructors + private void CreateCursor (Stream stream) + { + InitFromStream(stream); + this.shape = ToBitmap(true, false); + this.mask = ToBitmap(false, false); + handle = XplatUI.DefineCursor(shape, mask, Color.FromArgb(255, 255, 255), Color.FromArgb(255, 255, 255), cursor_dir.idEntries[id].xHotspot, cursor_dir.idEntries[id].yHotspot); + this.shape.Dispose(); + this.shape = null; + this.mask.Dispose(); + this.mask = null; + + if (handle != IntPtr.Zero) { + this.cursor = ToBitmap(true, true); + } + } + + internal Cursor (StdCursor cursor) : this (XplatUI.DefineStdCursor (cursor)) + { + std_cursor = cursor; + } + + private Cursor(SerializationInfo info, StreamingContext context) + { + } + + private Cursor() + { + } + + ~Cursor() + { + Dispose(); + } + + // This is supposed to take a Win32 handle + public Cursor (IntPtr handle) + { + this.handle = handle; + } + + public Cursor (Stream stream) + { + CreateCursor(stream); + } + + public Cursor (string fileName) + { + using (FileStream fs = File.OpenRead (fileName)) { + CreateCursor (fs); + } + } + + public Cursor(byte[] cursor) { + using (Stream s = new MemoryStream(cursor)) { + if (s != null) { + CreateCursor (s); + return; + } + } + + + throw new ArgumentException ("byte[] array isn't a proper cursor."); + } + #endregion // Public Constructors + + #region Public Static Properties + public static Rectangle Clip { + get { + IntPtr handle; + bool confined; + Rectangle rect; + Size size; + + XplatUI.GrabInfo (out handle, out confined, out rect); + if (handle != IntPtr.Zero) { + return rect; + } + + XplatUI.GetDisplaySize (out size); + rect.X = 0; + rect.Y = 0; + rect.Width = size.Width; + rect.Height = size.Height; + return rect; + } + + [MonoTODO ("Stub, does nothing")] + [MonoInternalNote ("First need to add ability to set cursor clip rectangle to XplatUI drivers to implement this property")] + set { + ; + } + } + + public static Cursor Current { + get { + if (current != null) + return current; + return Cursors.Default; + } + + set { + if (current == value) + return; + + current = value; + if (current == null){ + // FIXME - define and set empty cursor + XplatUI.OverrideCursor(IntPtr.Zero); + } else + XplatUI.OverrideCursor(current.handle); + } + } + + public static Point Position { + get { + int x; + int y; + + XplatUI.GetCursorPos (IntPtr.Zero, out x, out y); + return new Point (x, y); + } + + set { + XplatUI.SetCursorPos(IntPtr.Zero, value.X, value.Y); + } + } + #endregion // Public Static Properties + + #region Public Instance Properties + public IntPtr Handle { + get { + return handle; + } + } + + [MonoTODO ("Implemented for Win32, X11 always returns 0,0")] + public Point HotSpot { + get { + int cursor_w, cursor_h, hot_x, hot_y; + XplatUI.GetCursorInfo (Handle, out cursor_w, out cursor_h, out hot_x, out hot_y); + + return new Point (hot_x, hot_y); + } + } + + public Size Size { + get { + return size; + } + } + + [Localizable (false)] + [Bindable (true)] + [TypeConverter (typeof (StringConverter))] + [DefaultValue (null)] + [MWFCategory ("Data")] + public object Tag { + get { return this.tag; } + set { this.tag = value; } + } + + #endregion // Public Instance Properties + + #region Public Static Methods + public static void Hide () + { + XplatUI.ShowCursor(false); + } + + public static void Show () + { + XplatUI.ShowCursor(true); + } + + public static bool operator != (Cursor left, Cursor right) { + if ((object)left == (object)right) + return false; + + if ((object)left == null || (object)right == null) + return true; + + if (left.handle == right.handle) + return false; + return true; + } + + + public static bool operator ==(Cursor left, Cursor right) + { + if ((object)left == (object)right) + return true; + + if ((object)left == null || (object)right == null) + return false; + + if (left.handle == right.handle) + return true; + + return false; + } + #endregion // Public Static Methods + + #region Public Instance Methods + public IntPtr CopyHandle() { + return handle; + } + + public void Dispose () + { + if (cursor != null) { + cursor.Dispose (); + cursor = null; + } + + if (shape != null) { + shape.Dispose (); + shape = null; + } + + if (mask != null) { + mask.Dispose (); + mask = null; + } + + GC.SuppressFinalize (this); + } + + public void Draw (Graphics g, Rectangle targetRect) + { + if (cursor == null && std_cursor != (StdCursor) (-1)) + cursor = XplatUI.DefineStdCursorBitmap (std_cursor); + + if (cursor != null) { + // Size of the targetRect is not considered at all + g.DrawImage (cursor, targetRect.X, targetRect.Y); + } + } + + public void DrawStretched (Graphics g, Rectangle targetRect) + { + if (cursor == null && std_cursor != (StdCursor)(-1)) + cursor = XplatUI.DefineStdCursorBitmap (std_cursor); + + if (cursor != null) { + g.DrawImage (cursor, targetRect, new Rectangle(0, 0, cursor.Width, cursor.Height), GraphicsUnit.Pixel); + } + } + + public override bool Equals (object obj) + { + if (!(obj is Cursor)) + return false; + + if (((Cursor)obj).handle == handle) + return true; + + return false; + } + + public override int GetHashCode() + { + return base.GetHashCode (); + } + + public override string ToString() + { + if (name != null) { + return "[Cursor:" + name + "]"; + } + + throw new FormatException("Cannot convert custom cursors to string."); + } + + void ISerializable.GetObjectData (SerializationInfo si, StreamingContext context) + { + MemoryStream ms; + BinaryWriter wr; + CursorImage ci; + + ms = new MemoryStream (); + wr = new BinaryWriter (ms); + ci = cursor_data [this.id]; + + // Build the headers, first the CursorDir + wr.Write ((ushort) 0); // Reserved + wr.Write ((ushort) 2); // Resource type + wr.Write ((ushort) 1); // Count + + // Next the CursorEntry + wr.Write ((byte)cursor_dir.idEntries [this.id].width); + wr.Write ((byte)cursor_dir.idEntries [this.id].height); + wr.Write ((byte)cursor_dir.idEntries [this.id].colorCount); + wr.Write ((byte)cursor_dir.idEntries [this.id].reserved); + wr.Write ((ushort)cursor_dir.idEntries [this.id].xHotspot); + wr.Write ((ushort)cursor_dir.idEntries [this.id].yHotspot); + wr.Write ((uint)(40 + (ci.cursorColors.Length * 4) + ci.cursorXOR.Length + ci.cursorAND.Length)); + wr.Write ((uint)(6 + 16)); // CursorDir + CursorEntry size + + // Then the CursorInfoHeader + wr.Write (ci.cursorHeader.biSize); + wr.Write (ci.cursorHeader.biWidth); + wr.Write (ci.cursorHeader.biHeight); + wr.Write (ci.cursorHeader.biPlanes); + wr.Write (ci.cursorHeader.biBitCount); + wr.Write (ci.cursorHeader.biCompression); + wr.Write (ci.cursorHeader.biSizeImage); + wr.Write (ci.cursorHeader.biXPelsPerMeter); + wr.Write (ci.cursorHeader.biYPelsPerMeter); + wr.Write (ci.cursorHeader.biClrUsed); + wr.Write (ci.cursorHeader.biClrImportant); + + for (int i = 0; i < ci.cursorColors.Length; i++) + wr.Write(ci.cursorColors[i]); + + wr.Write (ci.cursorXOR); + wr.Write (ci.cursorAND); + wr.Flush (); + + si.AddValue ("CursorData", ms.ToArray ()); + } + #endregion // Public Instance Methods + + #region Private Methods + private void InitFromStream (Stream stream) + { + ushort entry_count; + CursorEntry ce; + uint largest; + + //read the cursor header + if (stream == null || stream.Length == 0) + throw new ArgumentException ("The argument 'stream' must be a picture that can be used as a cursor", "stream"); + + BinaryReader reader = new BinaryReader (stream); + + cursor_dir = new CursorDir (); + cursor_dir.idReserved = reader.ReadUInt16(); + cursor_dir.idType = reader.ReadUInt16(); + if (cursor_dir.idReserved != 0 || !(cursor_dir.idType == 2 || cursor_dir.idType == 1)) + throw new ArgumentException ("Invalid Argument, format error", "stream"); + + entry_count = reader.ReadUInt16(); + cursor_dir.idCount = entry_count; + cursor_dir.idEntries = new CursorEntry[entry_count]; + cursor_data = new CursorImage[entry_count]; + + //now read in the CursorEntry structures + for (int i=0; i < entry_count; i++){ + ce = new CursorEntry(); + + ce.width = reader.ReadByte(); + ce.height = reader.ReadByte(); + ce.colorCount = reader.ReadByte(); + ce.reserved = reader.ReadByte(); + ce.xHotspot = reader.ReadUInt16(); + ce.yHotspot = reader.ReadUInt16(); + if (cursor_dir.idType == 1) { + ce.xHotspot = (ushort)(ce.width / 2); + ce.yHotspot = (ushort)(ce.height / 2); + } + ce.sizeInBytes = reader.ReadUInt32(); + ce.fileOffset = reader.ReadUInt32(); + + cursor_dir.idEntries[i] = ce; + } + + // If we have more than one pick the largest cursor + largest = 0; + for (int j = 0; j < entry_count; j++){ + if (cursor_dir.idEntries[j].sizeInBytes >= largest) { + largest = cursor_dir.idEntries[j].sizeInBytes; + this.id = (ushort)j; + this.size.Height = cursor_dir.idEntries[j].height; + this.size.Width = cursor_dir.idEntries[j].width; + } + } + + //now read in the cursor data + for (int j = 0; j < entry_count; j++) { + CursorImage curdata; + CursorInfoHeader cih; + byte[] buffer; + BinaryReader cih_reader; + int num_colors; + int cursor_height; + int bytes_per_line; + int xor_size; + int and_size; + + curdata = new CursorImage(); + cih = new CursorInfoHeader(); + + stream.Seek (cursor_dir.idEntries[j].fileOffset, SeekOrigin.Begin); + buffer = new byte [cursor_dir.idEntries[j].sizeInBytes]; + stream.Read (buffer, 0, buffer.Length); + + cih_reader = new BinaryReader(new MemoryStream(buffer)); + + cih.biSize = cih_reader.ReadUInt32 (); + if (cih.biSize != 40) { + throw new ArgumentException ("Invalid cursor file", "stream"); + } + cih.biWidth = cih_reader.ReadInt32 (); + cih.biHeight = cih_reader.ReadInt32 (); + cih.biPlanes = cih_reader.ReadUInt16 (); + cih.biBitCount = cih_reader.ReadUInt16 (); + cih.biCompression = cih_reader.ReadUInt32 (); + cih.biSizeImage = cih_reader.ReadUInt32 (); + cih.biXPelsPerMeter = cih_reader.ReadInt32 (); + cih.biYPelsPerMeter = cih_reader.ReadInt32 (); + cih.biClrUsed = cih_reader.ReadUInt32 (); + cih.biClrImportant = cih_reader.ReadUInt32 (); + + curdata.cursorHeader = cih; + + //Read the number of colors used and corresponding memory occupied by + //color table. Fill this memory chunk into rgbquad[] + switch (cih.biBitCount){ + case 1: num_colors = 2; break; + case 4: num_colors = 16; break; + case 8: num_colors = 256; break; + default: num_colors = 0; break; + } + + curdata.cursorColors = new uint[num_colors]; + for (int i = 0; i < num_colors; i++) { + curdata.cursorColors[i] = cih_reader.ReadUInt32 (); + } + + //XOR mask is immediately after ColorTable and its size is + //icon height* no. of bytes per line + + //cursor height is half of BITMAPINFOHEADER.biHeight, since it contains + //both XOR as well as AND mask bytes + cursor_height = cih.biHeight/2; + + //bytes per line should should be uint aligned + bytes_per_line = ((((cih.biWidth * cih.biPlanes * cih.biBitCount)+ 31)>>5)<<2); + + //Determine the XOR array Size + xor_size = bytes_per_line * cursor_height; + curdata.cursorXOR = new byte[xor_size]; + for (int i = 0; i < xor_size; i++) { + curdata.cursorXOR[i] = cih_reader.ReadByte(); + } + + //Determine the AND array size + and_size = (int)(cih_reader.BaseStream.Length - cih_reader.BaseStream.Position); + curdata.cursorAND = new byte[and_size]; + for (int i = 0; i < and_size; i++) { + curdata.cursorAND[i] = cih_reader.ReadByte(); + } + + cursor_data[j] = curdata; + cih_reader.Close(); + } + + reader.Close(); + } + + private Bitmap ToBitmap(bool xor, bool transparent) + { + CursorImage ci; + CursorInfoHeader cih; + int ncolors; + Bitmap bmp; + BitmapData bits; + ColorPalette pal; + int biHeight; + int bytesPerLine; + + if (cursor_data == null) + return new Bitmap(32, 32); + + ci = cursor_data[this.id]; + cih = ci.cursorHeader; + biHeight = cih.biHeight / 2; + + if (!xor) { + // The AND mask is 1bit - very straightforward + bmp = new Bitmap(cih.biWidth, biHeight, PixelFormat.Format1bppIndexed); + pal = bmp.Palette; + pal.Entries[0] = Color.FromArgb(0, 0, 0); + pal.Entries[1] = Color.FromArgb(unchecked((int)0xffffffffff)); + bits = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat); + + for (int y = 0; y < biHeight; y++) { + Marshal.Copy(ci.cursorAND, bits.Stride * y, (IntPtr)(bits.Scan0.ToInt64() + bits.Stride * (biHeight - 1 - y)), bits.Stride); + } + + bmp.UnlockBits(bits); + } else { + ncolors = (int)cih.biClrUsed; + if (ncolors == 0) { + if (cih.biBitCount < 24) { + ncolors = (int)(1 << cih.biBitCount); + } + } + + switch(cih.biBitCount) { + case 1: { // Monochrome + bmp = new Bitmap (cih.biWidth, biHeight, PixelFormat.Format1bppIndexed); + break; + } + + case 4: { // 4bpp + bmp = new Bitmap (cih.biWidth, biHeight, PixelFormat.Format4bppIndexed); + break; + } + + case 8: { // 8bpp + bmp = new Bitmap (cih.biWidth, biHeight, PixelFormat.Format8bppIndexed); + break; + } + + case 24: + case 32: { // 32bpp + bmp = new Bitmap (cih.biWidth, biHeight, PixelFormat.Format32bppArgb); + break; + } + + default: + throw new Exception("Unexpected number of bits:" + cih.biBitCount.ToString()); + } + + if (cih.biBitCount < 24) { + pal = bmp.Palette; // Managed palette + for (int i = 0; i < ci.cursorColors.Length; i++) + pal.Entries[i] = Color.FromArgb((int)ci.cursorColors[i] | unchecked((int)0xff000000)); + bmp.Palette = pal; + } + + bytesPerLine = (int)((((cih.biWidth * cih.biBitCount) + 31) & ~31) >> 3); + bits = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat); + + for (int y = 0; y < biHeight; y++) + Marshal.Copy(ci.cursorXOR, bytesPerLine * y, (IntPtr)(bits.Scan0.ToInt64() + bits.Stride * (biHeight - 1 - y)), bytesPerLine); + + bmp.UnlockBits(bits); + } + + if (transparent) { + bmp = new Bitmap(bmp); // This makes a 32bpp image out of an indexed one + // Apply the mask to make properly transparent + for (int y = 0; y < biHeight; y++) { + for (int x = 0; x < cih.biWidth / 8; x++) { + for (int bit = 7; bit >= 0; bit--) { + if (((ci.cursorAND[y * cih.biWidth / 8 +x] >> bit) & 1) != 0) + bmp.SetPixel(x*8 + 7-bit, biHeight - y - 1, Color.Transparent); + } + } + } + } + + return bmp; + } + #endregion // Private Methods + } +} diff --git a/source/ShiftUI/Design/Behavior/Adorner.cs b/source/ShiftUI/Design/Behavior/Adorner.cs new file mode 100644 index 0000000..f67c6af --- /dev/null +++ b/source/ShiftUI/Design/Behavior/Adorner.cs @@ -0,0 +1,81 @@ +// +// ShiftUI.Design.Behavior.Adorner +// +// Author: +// Atsushi Enomoto (atsushi@ximian.com) +// +// Copyright (C) 2007 Novell, Inc. +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +using System; +using System.Drawing; +using System.Drawing.Design; +using System.Drawing.Drawing2D; + +namespace ShiftUI.Design.Behavior +{ + public sealed class Adorner + { + public Adorner () + { + } + + [MonoTODO] + public void Invalidate () + { + throw new NotImplementedException (); + } + + [MonoTODO] + public void Invalidate (Rectangle rectangle) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public void Invalidate (Region region) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public BehaviorService BehaviorService { + get { throw new NotImplementedException (); } + set { throw new NotImplementedException (); } + } + + [MonoTODO] + public bool Enabled { + get { throw new NotImplementedException (); } + set { throw new NotImplementedException (); } + } + + [MonoTODO] + public GlyphCollection Glyphs { + get { throw new NotImplementedException (); } + } + } +} + diff --git a/source/ShiftUI/Design/Behavior/Behavior.cs b/source/ShiftUI/Design/Behavior/Behavior.cs new file mode 100644 index 0000000..df6185a --- /dev/null +++ b/source/ShiftUI/Design/Behavior/Behavior.cs @@ -0,0 +1,155 @@ +// +// ShiftUI.Design.Behavior.Behavior +// +// Author: +// Atsushi Enomoto (atsushi@ximian.com) +// +// Copyright (C) 2007 Novell, Inc. +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +using System; +using System.ComponentModel.Design; +using System.Drawing; +using System.Drawing.Design; +using System.Drawing.Drawing2D; + +namespace ShiftUI.Design.Behavior +{ + public abstract class Behavior + { + [MonoTODO] + protected Behavior () + { + throw new NotImplementedException (); + } + + [MonoTODO] + protected Behavior (bool callParentBehavior, BehaviorService behaviorService) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual Cursor Cursor { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public virtual bool DisableAllCommands { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public virtual MenuCommand FindCommand (CommandID commandId) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual void OnDragDrop (Glyph g, DragEventArgs e) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual void OnDragEnter (Glyph g, DragEventArgs e) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual void OnDragLeave (Glyph g, EventArgs e) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual void OnDragOver (Glyph g, DragEventArgs e) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual void OnGiveFeedback (Glyph g, GiveFeedbackEventArgs e) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual void OnLoseCapture (Glyph g, EventArgs e) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual bool OnMouseDoubleClick (Glyph g, MouseButtons button, Point mouseLoc) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual bool OnMouseDown (Glyph g, MouseButtons button, Point mouseLoc) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual bool OnMouseEnter (Glyph g) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual bool OnMouseHover (Glyph g, Point mouseLoc) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual bool OnMouseLeave (Glyph g) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual bool OnMouseMove (Glyph g, MouseButtons button, Point mouseLoc) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual bool OnMouseUp (Glyph g, MouseButtons button) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual void OnQueryContinueDrag (Glyph g, QueryContinueDragEventArgs e) + { + throw new NotImplementedException (); + } + } +} + diff --git a/source/ShiftUI/Design/Behavior/BehaviorDragDropEventArgs.cs b/source/ShiftUI/Design/Behavior/BehaviorDragDropEventArgs.cs new file mode 100644 index 0000000..9a22361 --- /dev/null +++ b/source/ShiftUI/Design/Behavior/BehaviorDragDropEventArgs.cs @@ -0,0 +1,50 @@ +// +// ShiftUI.Design.Behavior.BehaviorDragDropEventArgs +// +// Author: +// Atsushi Enomoto (atsushi@ximian.com) +// +// Copyright (C) 2007 Novell, Inc. +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections; + +namespace ShiftUI.Design.Behavior +{ + public class BehaviorDragDropEventArgs : EventArgs + { + ICollection components; + + public BehaviorDragDropEventArgs (ICollection dragComponents) + { + this.components = dragComponents; + } + + public ICollection DragComponents { + get { return components; } + } + } +} + diff --git a/source/ShiftUI/Design/Behavior/BehaviorDragDropEventHandler.cs b/source/ShiftUI/Design/Behavior/BehaviorDragDropEventHandler.cs new file mode 100644 index 0000000..83c1ef3 --- /dev/null +++ b/source/ShiftUI/Design/Behavior/BehaviorDragDropEventHandler.cs @@ -0,0 +1,36 @@ +// +// ShiftUI.Design.Behavior.BehaviorDragDropEventHandler +// +// Author: +// Atsushi Enomoto (atsushi@ximian.com) +// +// Copyright (C) 2007 Novell, Inc. +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +namespace ShiftUI.Design.Behavior +{ + public delegate void BehaviorDragDropEventHandler (object sender, BehaviorDragDropEventArgs e); +} + diff --git a/source/ShiftUI/Design/Behavior/BehaviorService.cs b/source/ShiftUI/Design/Behavior/BehaviorService.cs new file mode 100644 index 0000000..cc741b1 --- /dev/null +++ b/source/ShiftUI/Design/Behavior/BehaviorService.cs @@ -0,0 +1,154 @@ +// +// ShiftUI.Design.Behavior.BehaviorService +// +// Author: +// Atsushi Enomoto (atsushi@ximian.com) +// +// Copyright (C) 2007 Novell, Inc. +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; + +namespace ShiftUI.Design.Behavior +{ + public sealed class BehaviorService : IDisposable + { + internal BehaviorService () + { + } + + public event BehaviorDragDropEventHandler BeginDrag; + public event BehaviorDragDropEventHandler EndDrag; + public event EventHandler Synchronize; + + [MonoTODO] + public BehaviorServiceAdornerCollection Adorners { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public Graphics AdornerWindowGraphics { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public Behavior CurrentBehavior { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public Point AdornerWindowPointToScreen (Point p) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public Point AdornerWindowToScreen () + { + throw new NotImplementedException (); + } + + [MonoTODO] + public Rectangle WidgetRectInAdornerWindow (Widget c) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public Point WidgetToAdornerWindow (Widget c) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public void Dispose () + { + throw new NotImplementedException (); + } + + [MonoTODO] + public Behavior GetNextBehavior (Behavior behavior) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public void Invalidate () + { + throw new NotImplementedException (); + } + + [MonoTODO] + public void Invalidate (Rectangle rect) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public void Invalidate (Region r) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public Point MapAdornerWindowPoint (IntPtr handle, Point pt) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public Behavior PopBehavior (Behavior behavior) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public void PushBehavior (Behavior behavior) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public void PushCaptureBehavior (Behavior behavior) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public Point ScreenToAdornerWindow (Point p) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public void SyncSelection () + { + throw new NotImplementedException (); + } + } +} + diff --git a/source/ShiftUI/Design/Behavior/BehaviorServiceAdornerCollection.cs b/source/ShiftUI/Design/Behavior/BehaviorServiceAdornerCollection.cs new file mode 100644 index 0000000..2850cd4 --- /dev/null +++ b/source/ShiftUI/Design/Behavior/BehaviorServiceAdornerCollection.cs @@ -0,0 +1,128 @@ +// +// ShiftUI.Design.Behavior.BehaviorServiceAdornerCollection +// +// Author: +// Atsushi Enomoto (atsushi@ximian.com) +// +// Copyright (C) 2007 Novell, Inc. +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +using System; +using System.Collections; + +namespace ShiftUI.Design.Behavior +{ + public sealed class BehaviorServiceAdornerCollection : CollectionBase + { + int state; + + public BehaviorServiceAdornerCollection (BehaviorService behaviorService) + : this (behaviorService.Adorners) + { + } + + public BehaviorServiceAdornerCollection (Adorner [] value) + { + if (value == null) + throw new ArgumentNullException ("value"); + InnerList.AddRange (value); + } + + public BehaviorServiceAdornerCollection (BehaviorServiceAdornerCollection value) + { + if (value == null) + throw new ArgumentNullException ("value"); + InnerList.AddRange (value); + } + + internal int State { + get { return state; } + } + + public Adorner this [int index] { + get { return (Adorner) InnerList [index]; } + set { + if (value == null) + throw new ArgumentNullException ("value"); + InnerList [index] = value; + } + } + + public int Add (Adorner value) + { + state++; + return InnerList.Add (value); + } + + public void AddRange (Adorner [] value) + { + state++; + if (value == null) + throw new ArgumentNullException ("value"); + InnerList.AddRange (value); + } + + public void AddRange (BehaviorServiceAdornerCollection value) + { + state++; + if (value == null) + throw new ArgumentNullException ("value"); + InnerList.AddRange (value); + } + + public bool Contains (Adorner value) + { + return InnerList.Contains (value); + } + + public void CopyTo (Adorner [] array, int index) + { + InnerList.CopyTo (array, index); + } + + public int IndexOf (Adorner value) + { + return InnerList.IndexOf (value); + } + + public BehaviorServiceAdornerCollectionEnumerator GetEnumerator () + { + return new BehaviorServiceAdornerCollectionEnumerator (this); + } + + public void Insert (int index, Adorner value) + { + state++; + InnerList.Insert (index, value); + } + + public void Remove (Adorner value) + { + state++; + InnerList.Remove (value); + } + } +} + diff --git a/source/ShiftUI/Design/Behavior/BehaviorServiceAdornerCollectionEnumerator.cs b/source/ShiftUI/Design/Behavior/BehaviorServiceAdornerCollectionEnumerator.cs new file mode 100644 index 0000000..a4e9138 --- /dev/null +++ b/source/ShiftUI/Design/Behavior/BehaviorServiceAdornerCollectionEnumerator.cs @@ -0,0 +1,90 @@ +// +// ShiftUI.Design.Behavior.BehaviorServiceAdornerCollectionEnumerator +// +// Author: +// Atsushi Enomoto (atsushi@ximian.com) +// +// Copyright (C) 2007 Novell, Inc. +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +using System; +using System.Collections; + +namespace ShiftUI.Design.Behavior +{ + public class BehaviorServiceAdornerCollectionEnumerator : IEnumerator + { + BehaviorServiceAdornerCollection mappings; + int index, state; + + public BehaviorServiceAdornerCollectionEnumerator (BehaviorServiceAdornerCollection mappings) + { + if (mappings == null) + throw new ArgumentNullException ("mappings"); + this.mappings = mappings; + + Reset (); + } + + public Adorner Current { + get { return index < 0 ? null : mappings [index]; } + } + + void CheckState () + { + if (mappings.State != state) + throw new InvalidOperationException ("Collection has changed"); + } + + public bool MoveNext () + { + CheckState (); + if (index++ < mappings.Count) + return true; + index--; + return false; + } + + public void Reset () + { + index = -1; + } + + object IEnumerator.Current { + get { return Current; } + } + + bool IEnumerator.MoveNext () + { + return MoveNext (); + } + + void IEnumerator.Reset () + { + Reset (); + } + } +} + diff --git a/source/ShiftUI/Design/Behavior/ComponentGlyph.cs b/source/ShiftUI/Design/Behavior/ComponentGlyph.cs new file mode 100644 index 0000000..0f8c53b --- /dev/null +++ b/source/ShiftUI/Design/Behavior/ComponentGlyph.cs @@ -0,0 +1,73 @@ +// +// ShiftUI.Design.Behavior.ComponentGlyph +// +// Author: +// Atsushi Enomoto (atsushi@ximian.com) +// +// Copyright (C) 2007 Novell, Inc. +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Design; +using System.Drawing.Drawing2D; + +namespace ShiftUI.Design.Behavior +{ + public class ComponentGlyph : Glyph + { + IComponent component; + + public ComponentGlyph (IComponent relatedComponent) + : this (relatedComponent, null) + { + } + + public ComponentGlyph (IComponent relatedComponent, Behavior behavior) + : base (behavior) + { + this.component = relatedComponent; + } + + [MonoTODO] + public IComponent RelatedComponent { + get { return component; } + } + + [MonoTODO] + public override Cursor GetHitTest (Point p) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public override void Paint (PaintEventArgs pe) + { + throw new NotImplementedException (); + } + } +} + diff --git a/source/ShiftUI/Design/Behavior/ControlBodyGlyph.cs b/source/ShiftUI/Design/Behavior/ControlBodyGlyph.cs new file mode 100644 index 0000000..547eea1 --- /dev/null +++ b/source/ShiftUI/Design/Behavior/ControlBodyGlyph.cs @@ -0,0 +1,70 @@ +// +// ShiftUI.Design.Behavior.WidgetBodyGlyph +// +// Author: +// Atsushi Enomoto (atsushi@ximian.com) +// +// Copyright (C) 2007 Novell, Inc. +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Design; +using System.Drawing.Drawing2D; + +namespace ShiftUI.Design.Behavior +{ + public class WidgetBodyGlyph : ComponentGlyph + { + Rectangle bounds; + + [MonoTODO] + public WidgetBodyGlyph (Rectangle bounds, Cursor cursor, IComponent relatedComponent, Behavior behavior) + : base (relatedComponent, behavior) + { + this.bounds = bounds; + throw new NotImplementedException (); + } + + [MonoTODO] + public WidgetBodyGlyph (Rectangle bounds, Cursor cursor, IComponent relatedComponent, WidgetDesigner designer) + : this (bounds, cursor, relatedComponent, designer.BehaviorService.CurrentBehavior) + { + } + + [MonoTODO] + public override Rectangle Bounds { + get { return bounds; } + } + + [MonoTODO] + public override Cursor GetHitTest (Point p) + { + throw new NotImplementedException (); + } + } +} + diff --git a/source/ShiftUI/Design/Behavior/Glyph.cs b/source/ShiftUI/Design/Behavior/Glyph.cs new file mode 100644 index 0000000..3452627 --- /dev/null +++ b/source/ShiftUI/Design/Behavior/Glyph.cs @@ -0,0 +1,70 @@ +// +// ShiftUI.Design.Behavior.Glyph +// +// Author: +// Atsushi Enomoto (atsushi@ximian.com) +// +// Copyright (C) 2007 Novell, Inc. +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +using System; +using System.Drawing; +using System.Drawing.Design; +using System.Drawing.Drawing2D; + +namespace ShiftUI.Design.Behavior +{ + public abstract class Glyph + { + Behavior behavior; + + [MonoTODO] + protected Glyph (Behavior behavior) + { + SetBehavior (behavior); + } + + [MonoTODO] + public virtual Behavior Behavior { + get { return behavior; } + } + + [MonoTODO] + public virtual Rectangle Bounds { + get { throw new NotImplementedException (); } + } + + public abstract Cursor GetHitTest (Point p); + + public abstract void Paint (PaintEventArgs pe); + + [MonoTODO] + protected void SetBehavior (Behavior behavior) + { + throw new NotImplementedException (); + } + } +} + diff --git a/source/ShiftUI/Design/Behavior/GlyphCollection.cs b/source/ShiftUI/Design/Behavior/GlyphCollection.cs new file mode 100644 index 0000000..d19e689 --- /dev/null +++ b/source/ShiftUI/Design/Behavior/GlyphCollection.cs @@ -0,0 +1,111 @@ +// +// ShiftUI.Design.Behavior.GlyphCollection +// +// Author: +// Atsushi Enomoto (atsushi@ximian.com) +// +// Copyright (C) 2007 Novell, Inc. +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +using System; +using System.Collections; + +namespace ShiftUI.Design.Behavior +{ + public class GlyphCollection : CollectionBase + { + public GlyphCollection () + { + } + + public GlyphCollection (Glyph [] value) + { + if (value == null) + throw new ArgumentNullException ("value"); + InnerList.AddRange (value); + } + + public GlyphCollection (GlyphCollection value) + { + if (value == null) + throw new ArgumentNullException ("value"); + InnerList.AddRange (value); + } + + public Glyph this [int index] { + get { return (Glyph) InnerList [index]; } + set { + if (value == null) + throw new ArgumentNullException ("value"); + InnerList [index] = value; + } + } + + public int Add (Glyph value) + { + return InnerList.Add (value); + } + + public void AddRange (Glyph [] value) + { + if (value == null) + throw new ArgumentNullException ("value"); + InnerList.AddRange (value); + } + + public void AddRange (GlyphCollection value) + { + if (value == null) + throw new ArgumentNullException ("value"); + InnerList.AddRange (value); + } + + public bool Contains (Glyph value) + { + return InnerList.Contains (value); + } + + public void CopyTo (Glyph [] array, int index) + { + InnerList.CopyTo (array, index); + } + + public int IndexOf (Glyph value) + { + return InnerList.IndexOf (value); + } + + public void Insert (int index, Glyph value) + { + InnerList.Insert (index, value); + } + + public void Remove (Glyph value) + { + InnerList.Remove (value); + } + } +} + diff --git a/source/ShiftUI/Design/Behavior/GlyphSelectionType.cs b/source/ShiftUI/Design/Behavior/GlyphSelectionType.cs new file mode 100644 index 0000000..6220c03 --- /dev/null +++ b/source/ShiftUI/Design/Behavior/GlyphSelectionType.cs @@ -0,0 +1,41 @@ +// +// ShiftUI.Design.Behavior.GlyphSelectionType +// +// Author: +// Atsushi Enomoto (atsushi@ximian.com) +// +// Copyright (C) 2007 Novell, Inc. +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +namespace ShiftUI.Design.Behavior +{ + public enum GlyphSelectionType + { + NotSelected, + Selected, + SelectedPrimary + } +} + diff --git a/source/ShiftUI/Design/Behavior/SnapLine.cs b/source/ShiftUI/Design/Behavior/SnapLine.cs new file mode 100644 index 0000000..3b7da92 --- /dev/null +++ b/source/ShiftUI/Design/Behavior/SnapLine.cs @@ -0,0 +1,133 @@ +// +// ShiftUI.Design.Behavior.SnapLine +// +// Author: +// Atsushi Enomoto (atsushi@ximian.com) +// +// Copyright (C) 2007 Novell, Inc. +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + + +using System; + +namespace ShiftUI.Design.Behavior +{ + public sealed class SnapLine + { + [MonoTODO] + public static bool ShouldSnap (SnapLine line1, SnapLine line2) + { + throw new NotImplementedException (); + } + + SnapLineType type; + int offset; + string filter; + SnapLinePriority priority; + + [MonoTODO] + public SnapLine (SnapLineType type, int offset) + : this (type, offset, null) + { + } + + [MonoTODO] + public SnapLine (SnapLineType type, int offset, string filter) + : this (type, offset, filter, default (SnapLinePriority)) + { + } + + [MonoTODO] + public SnapLine (SnapLineType type, int offset, SnapLinePriority priority) + : this (type, offset, null, priority) + { + } + + [MonoTODO] + public SnapLine (SnapLineType type, int offset, string filter, SnapLinePriority priority) + { + this.type =type; + this.offset = offset; + this.filter = filter; + this.priority = priority; + } + + public string Filter { + get { return filter; } + } + + public bool IsHorizontal { + get { + switch (SnapLineType) { + case SnapLineType.Top: + case SnapLineType.Bottom: + case SnapLineType.Horizontal: + case SnapLineType.Baseline: + return true; + default: + return false; + } + } + } + + public bool IsVertical { + get { + switch (SnapLineType) { + case SnapLineType.Left: + case SnapLineType.Right: + case SnapLineType.Vertical: + return true; + default: + return false; + } + } + } + + public int Offset { + get { return offset; } + } + + public SnapLinePriority Priority { + get { return priority; } + } + + public SnapLineType SnapLineType { + get { return type; } + } + + [MonoTODO] + public void AdjustOffset (int adjustment) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public override string ToString () + { + return base.ToString (); + } + } +} + diff --git a/source/ShiftUI/Design/Behavior/SnapLinePriority.cs b/source/ShiftUI/Design/Behavior/SnapLinePriority.cs new file mode 100644 index 0000000..b0dff04 --- /dev/null +++ b/source/ShiftUI/Design/Behavior/SnapLinePriority.cs @@ -0,0 +1,42 @@ +// +// ShiftUI.Design.Behavior.SnapLinePriority +// +// Author: +// Atsushi Enomoto (atsushi@ximian.com) +// +// Copyright (C) 2007 Novell, Inc. +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +namespace ShiftUI.Design.Behavior +{ + public enum SnapLinePriority + { + Low = 1, + Medium, + High, + Always + } +} + diff --git a/source/ShiftUI/Design/Behavior/SnapLineType.cs b/source/ShiftUI/Design/Behavior/SnapLineType.cs new file mode 100644 index 0000000..a0b294b --- /dev/null +++ b/source/ShiftUI/Design/Behavior/SnapLineType.cs @@ -0,0 +1,45 @@ +// +// ShiftUI.Design.Behavior.SnapLineType +// +// Author: +// Atsushi Enomoto (atsushi@ximian.com) +// +// Copyright (C) 2007 Novell, Inc. +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +namespace ShiftUI.Design.Behavior +{ + public enum SnapLineType + { + Top, + Bottom, + Left, + Right, + Horizontal, + Vertical, + Baseline + } +} + diff --git a/source/ShiftUI/Design/ComponentDesigner.cs b/source/ShiftUI/Design/ComponentDesigner.cs new file mode 100644 index 0000000..f0034b6 --- /dev/null +++ b/source/ShiftUI/Design/ComponentDesigner.cs @@ -0,0 +1,438 @@ +// +// System.ComponentModel.Design.ComponentDesigner +// +// Authors: +// Ivan N. Zlatev (contact i-nZ.net) +// +// (C) 2006-2007 Ivan N. Zlatev + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +using System; +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design; + +namespace ShiftUI.Design +{ + + public class ComponentDesigner : ITreeDesigner, IDesigner, IDisposable, IDesignerFilter, IComponentInitializer + { + +#region ShadowPropertyCollection + + protected sealed class ShadowPropertyCollection + { + + private Hashtable _properties = null; + private IComponent _component; + + internal ShadowPropertyCollection (IComponent component) + { + _component = component; + } + + // Returns Widget's property value (if available) if there is no shadowed one. + // + public object this[string propertyName] + { + get { + if (propertyName == null) + throw new System.ArgumentNullException("propertyName"); + + if (_properties != null && _properties.ContainsKey (propertyName)) + return _properties[propertyName]; + + PropertyDescriptor property = TypeDescriptor.GetProperties (_component.GetType ())[propertyName]; + if (property != null) + return property.GetValue (_component); + else + throw new System.Exception ("Propery not found!"); + } + set { + if (_properties == null) + _properties = new Hashtable (); + _properties[propertyName] = value; + } + } + + public bool Contains (string propertyName) + { + if (_properties != null) + return _properties.ContainsKey (propertyName); + else + return false; + } + + } // ShadowPropertyCollection +#endregion + + public ComponentDesigner () + { + } + + + private IComponent _component; + private DesignerVerbCollection _verbs; + private ShadowPropertyCollection _shadowPropertyCollection; + private DesignerActionListCollection _designerActionList; + + // This property indicates any components to copy or move along with the component managed + // by the designer during a copy, drag, or move operation. + // If this collection contains references to other components in the current design mode document, + // those components will be copied along with the component managed by the designer during a copy operation. + // When the component managed by the designer is selected, this collection is filled with any nested controls. + // This collection can also include other components, such as the buttons of a toolbar. + // + // supposedly contains all the children of the component, thus used for ITreeDesigner.Children + // + public virtual ICollection AssociatedComponents { + get { return new IComponent[0]; } + } + + public IComponent Component { + get { return _component; } + } + + public virtual DesignerVerbCollection Verbs { + get { + if (_verbs == null) + _verbs = new DesignerVerbCollection (); + + return _verbs; + } + } + + protected virtual InheritanceAttribute InheritanceAttribute { + get { + IInheritanceService service = (IInheritanceService) this.GetService (typeof (IInheritanceService)); + if (service != null) + return service.GetInheritanceAttribute (_component); + else + return InheritanceAttribute.Default; + } + } + + protected bool Inherited { + get { return !this.InheritanceAttribute.Equals (InheritanceAttribute.NotInherited); } + } + + //Gets a collection of property values that override user settings. + // + protected ShadowPropertyCollection ShadowProperties { + get { + if (_shadowPropertyCollection == null) { + _shadowPropertyCollection = new ShadowPropertyCollection(_component); + } + return _shadowPropertyCollection; + } + } + + public virtual DesignerActionListCollection ActionLists { + get { + if (_designerActionList == null) + _designerActionList = new DesignerActionListCollection (); + + return _designerActionList; + } + } + + protected virtual IComponent ParentComponent { + get { + IDesignerHost host = GetService (typeof (IDesignerHost)) as IDesignerHost; + if (host != null) { + IComponent rootComponent = host.RootComponent; + if (rootComponent != _component) + return rootComponent; + } + return null; + } + } + + public virtual void InitializeNewComponent (IDictionary defaultValues) + { + // Reset + // + OnSetComponentDefaults (); + } + + // MSDN: The default implementation of this method does nothing. + // + public virtual void InitializeExistingComponent (IDictionary defaultValues) + { + InitializeNonDefault (); + } + + + public virtual void Initialize (IComponent component) + { + if (component == null) + throw new ArgumentNullException ("component"); + + _component = component; + } + + [Obsolete ("This method has been deprecated. Use InitializeExistingComponent instead.")] + public virtual void InitializeNonDefault () + { + } + + + // This method is called when a user double-clicks (the representation of) a component. + // Tries to bind the default event to a method or creates a new one. + // + public virtual void DoDefaultAction() + { + IDesignerHost host = (IDesignerHost) this.GetService(typeof(IDesignerHost)); + DesignerTransaction transaction = null; + if (host != null) + transaction = host.CreateTransaction ("ComponentDesigner_AddEvent"); + + IEventBindingService eventBindingService = GetService (typeof(IEventBindingService)) as IEventBindingService; + EventDescriptor defaultEventDescriptor = null; + + if (eventBindingService != null) { + ISelectionService selectionService = this.GetService (typeof (ISelectionService)) as ISelectionService; + try { + if (selectionService != null) { + ICollection selectedComponents = selectionService.GetSelectedComponents (); + + foreach (IComponent component in selectedComponents) { + EventDescriptor eventDescriptor = TypeDescriptor.GetDefaultEvent (component); + if (eventDescriptor != null) { + PropertyDescriptor eventProperty = eventBindingService.GetEventProperty (eventDescriptor); + if (eventProperty != null && !eventProperty.IsReadOnly) { + string methodName = eventProperty.GetValue (component) as string; + bool newMethod = true; + + if (methodName != null || methodName != String.Empty) { + ICollection compatibleMethods = eventBindingService.GetCompatibleMethods (eventDescriptor); + foreach (string signature in compatibleMethods) { + if (signature == methodName) { + newMethod = false; + break; + } + } + } + if (newMethod) { + if (methodName == null) + methodName = eventBindingService.CreateUniqueMethodName (component, eventDescriptor); + + eventProperty.SetValue (component, methodName); + } + + if (component == _component) + defaultEventDescriptor = eventDescriptor; + } + } + } + + } + } + catch { + if (transaction != null) { + transaction.Cancel (); + transaction = null; + } + } + finally { + if (transaction != null) + transaction.Commit (); + } + + if (defaultEventDescriptor != null) + eventBindingService.ShowCode (_component, defaultEventDescriptor); + } + } + + + + [Obsolete ("This method has been deprecated. Use InitializeNewComponent instead.")] + // The default implementation of this method sets the default property of the component to + // the name of the component if the default property is a string and the property is not already set. + // This method can be implemented in a derived class to customize the initialization of the component + // that this designer is designing. + // + public virtual void OnSetComponentDefaults () + { + if (_component != null && _component.Site != null) { + PropertyDescriptor property = TypeDescriptor.GetDefaultProperty (_component); + if (property != null && property.PropertyType.Equals (typeof (string))) { + string propertyValue = (string)property.GetValue (_component); + if (propertyValue != null && propertyValue.Length != 0) + property.SetValue (_component, _component.Site.Name); + } + } + } + + + + + protected InheritanceAttribute InvokeGetInheritanceAttribute (ComponentDesigner toInvoke) + { + return toInvoke.InheritanceAttribute; + } + +#region IDesignerFilter + + // TypeDescriptor queries the component's site for ITypeDescriptorFilterService + // then invokes ITypeDescriptorFilterService.XXXX before retrieveing props/event/attributes, + // which then invokes the IDesignerFilter implementation of the component + // + protected virtual void PostFilterAttributes (IDictionary attributes) + { + } + + protected virtual void PostFilterEvents (IDictionary events) + { + } + + protected virtual void PostFilterProperties (IDictionary properties) + { + } + + protected virtual void PreFilterAttributes (IDictionary attributes) + { + } + + protected virtual void PreFilterEvents (IDictionary events) + { + } + + protected virtual void PreFilterProperties (IDictionary properties) + { + } +#endregion + + protected void RaiseComponentChanged (MemberDescriptor member, object oldValue, object newValue) + { + IComponentChangeService service = GetService (typeof (IComponentChangeService)) as IComponentChangeService; + if (service != null) + service.OnComponentChanged (_component, member, oldValue, newValue); + } + + protected void RaiseComponentChanging (MemberDescriptor member) + { + IComponentChangeService service = GetService (typeof (IComponentChangeService)) as IComponentChangeService; + if (service != null) + service.OnComponentChanging (_component, member); + } + +#region Implementation of IDesignerFilter + + void IDesignerFilter.PostFilterAttributes (IDictionary attributes) + { + PostFilterAttributes (attributes); + } + + void IDesignerFilter.PostFilterEvents (IDictionary events) + { + PostFilterEvents (events); + } + + void IDesignerFilter.PostFilterProperties (IDictionary properties) + { + PostFilterProperties (properties); + } + + void IDesignerFilter.PreFilterAttributes (IDictionary attributes) + { + PreFilterAttributes (attributes); + } + + void IDesignerFilter.PreFilterEvents (IDictionary events) + { + PreFilterEvents (events); + } + + void IDesignerFilter.PreFilterProperties (IDictionary properties) + { + PreFilterProperties (properties); + } + +#endregion + + +#region ITreeDesigner + // Returns a collection of the designers of the associated components + // + ICollection ITreeDesigner.Children { + get { + ICollection components = this.AssociatedComponents; + IDesignerHost host = GetService (typeof (IDesignerHost)) as IDesignerHost; + + if (host != null) { + ArrayList designers = new ArrayList (); + foreach (IComponent component in components) { + IDesigner designer = host.GetDesigner (component); + if (designer != null) + designers.Add (designer); + } + IDesigner[] result = new IDesigner[designers.Count]; + designers.CopyTo (result); + return result; + } + return new IDesigner[0]; + } + } + + IDesigner ITreeDesigner.Parent { + get { + IDesignerHost host = GetService (typeof (IDesignerHost)) as IDesignerHost; + if (host != null && this.ParentComponent != null) + return host.GetDesigner (this.ParentComponent); + + return null; + } + } +#endregion + + // Helper method - not an ISerivceProvider + // + protected virtual object GetService (Type service) + { + if (_component != null && _component.Site != null) + return _component.Site.GetService (service); + + return null; + } + + public void Dispose () + { + this.Dispose (true); + GC.SuppressFinalize (this); + } + + + protected virtual void Dispose (bool disposing) + { + if (disposing) + _component = null; + } + + ~ComponentDesigner () + { + this.Dispose (false); + } + } +} diff --git a/source/ShiftUI/Design/ComponentEditorForm.cs b/source/ShiftUI/Design/ComponentEditorForm.cs new file mode 100644 index 0000000..0cd0584 --- /dev/null +++ b/source/ShiftUI/Design/ComponentEditorForm.cs @@ -0,0 +1,96 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Dennis Hayes (dennish@raytek.com) + +using System; +using System.ComponentModel; +using ShiftUI; +using System.Runtime.InteropServices; + +namespace ShiftUI.Design { + [ToolboxItem (false)] + [ClassInterfaceAttribute (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + public class ComponentEditorForm : Form { + + [MonoTODO] + public ComponentEditorForm(object component, Type[] pageTypes){ + } + + #region Public Properties + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + new public virtual bool AutoSize { + get { return base.AutoSize; } + set { base.AutoSize = value; } + } + #endregion + + [MonoTODO] + protected override void OnActivated(EventArgs e){ + } + + [MonoTODO] + protected virtual void OnSelChangeSelector(object source, TreeViewEventArgs e){ + } + + [MonoTODO] + public override bool PreProcessMessage(ref Message msg){ + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual DialogResult ShowForm(){ + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual DialogResult ShowForm(int page){ + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual DialogResult ShowForm(IWin32Window owner){ + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual DialogResult ShowForm(IWin32Window owner, int page){ + throw new NotImplementedException (); + } + [MonoTODO] + // can't override the function in Widget. bug in compiler. Fixed? + protected override void OnHelpRequested(HelpEventArgs e){ + } + + #region Public Events + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler AutoSizeChanged { + add { base.AutoSizeChanged += value; } + remove { base.AutoSizeChanged -= value; } + } + #endregion + } +} diff --git a/source/ShiftUI/Design/ComponentEditorPage.cs b/source/ShiftUI/Design/ComponentEditorPage.cs new file mode 100644 index 0000000..9b93b9a --- /dev/null +++ b/source/ShiftUI/Design/ComponentEditorPage.cs @@ -0,0 +1,210 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Andreas Nahr (ClassDevelopment@A-SoftTech.com) +// + +using System.ComponentModel; +using System.Drawing; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI.Design +{ + [ClassInterfaceAttribute (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + public abstract class ComponentEditorPage : Panel + { + private bool commitOnDeactivate = false; + private IComponent component; + private bool firstActivate = true; + private Icon icon; + private int loading = 0; + private bool loadRequired = false; + private IComponentEditorPageSite pageSite; + + public ComponentEditorPage () + { + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + new public virtual bool AutoSize { + get { return base.AutoSize; } + set { base.AutoSize = value; } + } + + public bool CommitOnDeactivate + { + get { return commitOnDeactivate; } + set { commitOnDeactivate = value; } + } + + protected IComponent Component { + get { return component; } + set { component = value; } + } + + [MonoTODO ("Find out what this does.")] + protected override CreateParams CreateParams { + get { + throw new NotImplementedException (); + } + } + + protected bool FirstActivate { + get { return firstActivate; } + set { firstActivate = value; } + } + + public Icon Icon { + get { return icon; } + set { icon = value; } + } + + protected int Loading { + get { return loading; } + set { loading = value; } + } + + protected bool LoadRequired { + get { return loadRequired; } + set { loadRequired = value; } + } + + protected IComponentEditorPageSite PageSite { + get { return pageSite; } + set { pageSite = value; } + } + + public virtual string Title { + get { return base.Text; } + } + + public virtual void Activate () + { + Visible = true; + firstActivate = false; + if (loadRequired) { + EnterLoadingMode (); + LoadComponent (); + ExitLoadingMode (); + } + } + + public virtual void ApplyChanges () + { + SaveComponent (); + } + + public virtual void Deactivate () + { + Visible = false; + } + + protected void EnterLoadingMode () + { + loading++; + } + + protected void ExitLoadingMode () + { + loading--; + } + + public virtual Widget GetWidget () + { + return this; + } + + protected IComponent GetSelectedComponent () + { + return component; + } + + protected bool IsFirstActivate () + { + return firstActivate; + } + + protected bool IsLoading () + { + return (loading != 0); + } + + public virtual bool IsPageMessage (ref Message msg) + { + return PreProcessMessage (ref msg); + } + + protected abstract void LoadComponent (); + + [MonoTODO ("Find out what this does.")] + public virtual void OnApplyComplete () + { + } + + protected virtual void ReloadComponent () + { + loadRequired = true; + } + + protected abstract void SaveComponent (); + + public virtual void SetComponent (IComponent component) + { + this.component = component; + ReloadComponent (); + } + + [MonoTODO ("Find out what this does.")] + protected virtual void SetDirty () + { + } + + public virtual void SetSite (IComponentEditorPageSite site) + { + pageSite = site; + pageSite.GetWidget ().Widgets.Add (this); + + } + + public virtual void ShowHelp () + { + } + + public virtual bool SupportsHelp () + { + return false; + } + + #region Public Events + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler AutoSizeChanged { + add { base.AutoSizeChanged += value; } + remove { base.AutoSizeChanged -= value; } + } + #endregion + } +} diff --git a/source/ShiftUI/Design/ComponentTray.cs b/source/ShiftUI/Design/ComponentTray.cs new file mode 100644 index 0000000..d4c0f93 --- /dev/null +++ b/source/ShiftUI/Design/ComponentTray.cs @@ -0,0 +1,247 @@ +// +// ShiftUI.Design.ComponentTray +// +// Authors: +// Ivan N. Zlatev (contact i-nZ.net) +// +// (C) 2006-2007 Ivan N. Zlatev + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +// STUBS ONLY!!! +// +// + +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using ShiftUI; +using System.Drawing; +using System.Drawing.Design; +using System.Collections; + +namespace ShiftUI.Design +{ + [DesignTimeVisible (false)] + [ToolboxItem (false)] + [ProvideProperty ("Location", typeof (IComponent))] + public class ComponentTray : ScrollableWidget, IExtenderProvider + { + + private IServiceProvider _serviceProvider; + private IDesigner _mainDesigner = null; + private bool _showLargeIcons = false; + private bool _autoArrange = false; + + public ComponentTray (IDesigner mainDesigner, IServiceProvider serviceProvider) + { + if (mainDesigner == null) { + throw new ArgumentNullException ("mainDesigner"); + } + if (serviceProvider == null) { + throw new ArgumentNullException ("serviceProvider"); + } + + _mainDesigner = mainDesigner; + _serviceProvider = serviceProvider; + } + + public bool AutoArrange { + get { return _autoArrange; } + set { _autoArrange = value; } + } + + [MonoTODO] + public int ComponentCount { + get { return 0; } + } + + public bool ShowLargeIcons { + get { return _showLargeIcons; } + set { _showLargeIcons = value; } + } + + + [MonoTODO] + public virtual void AddComponent (IComponent component) + { + } + + protected virtual bool CanCreateComponentFromTool (ToolboxItem tool) + { + return true; + } + + protected virtual bool CanDisplayComponent (IComponent component) + { + return false; + } + + [MonoTODO] + public void CreateComponentFromTool (ToolboxItem tool) + { + } + + [MonoTODO] + protected void DisplayError (Exception e) + { + } + + protected override void Dispose (bool disposing) + { + } + + [Browsable (false)] + [Category ("Layout")] + [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + [DesignOnly (true)] + [Localizable (false)] + [MonoTODO] + public Point GetLocation (IComponent receiver) + { + return new Point (0,0); + } + + [MonoTODO] + public void SetLocation (IComponent receiver, Point location) + { + } + + [MonoTODO] + public IComponent GetNextComponent (IComponent component, bool forward) + { + throw new NotImplementedException (); + } + + [Browsable (false)] + [Category ("Layout")] + [DesignOnly (true)] + [Localizable (false)] + [MonoTODO] + public Point GetTrayLocation (IComponent receiver) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public bool IsTrayComponent (IComponent comp) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public void SetTrayLocation (IComponent receiver, Point location) + { + throw new NotImplementedException (); + } + + [MonoTODO] + protected override void OnMouseDoubleClick (MouseEventArgs e) + { + } + + [MonoTODO] + protected override void OnDragDrop (DragEventArgs de) + { + } + + [MonoTODO] + protected override void OnDragEnter (DragEventArgs de) + { + } + + [MonoTODO] + protected override void OnDragLeave (EventArgs e) + { + } + + [MonoTODO] + protected override void OnDragOver (DragEventArgs de) + { + } + + [MonoTODO] + protected override void OnGiveFeedback (GiveFeedbackEventArgs gfevent) + { + } + + [MonoTODO] + protected override void OnLayout (LayoutEventArgs levent) + { + } + + [MonoTODO] + protected virtual void OnLostCapture () + { + } + + [MonoTODO] + protected override void OnMouseDown (MouseEventArgs e) + { + } + + [MonoTODO] + protected override void OnMouseMove (MouseEventArgs e) + { + } + + [MonoTODO] + protected override void OnMouseUp (MouseEventArgs e) + { + } + + [MonoTODO] + protected override void OnPaint (PaintEventArgs pe) + { + } + + [MonoTODO] + protected virtual void OnSetCursor () + { + } + + [MonoTODO] + public virtual void RemoveComponent (IComponent component) + { + } + + [MonoTODO] + protected override void WndProc (ref Message m) + { + base.WndProc (ref m); + } + + bool IExtenderProvider.CanExtend (object component) + { + return false; + } + + protected override object GetService (Type service) + { + if (_serviceProvider != null) { + return _serviceProvider.GetService (service); + } + return null; + } + + } +} diff --git a/source/ShiftUI/Design/Consts.cs b/source/ShiftUI/Design/Consts.cs new file mode 100644 index 0000000..ef7fc20 --- /dev/null +++ b/source/ShiftUI/Design/Consts.cs @@ -0,0 +1,100 @@ +// +// Consts.cs +// +// Author: +// Marek Sieradzki (marek.sieradzki@gmail.com) +// +// (C) 2006 Marek Sieradzki +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +#define NET_4_5 +using System; +using System.IO; +using Microsoft.Build.Utilities; + +public static class Consts { + + public static bool RunningOnMono () + { + return Type.GetType ("Mono.Runtime") != null; + } + + public static string BinPath { + get { + if (RunningOnMono ()) { +#if XBUILD_14 + string profile = "xbuild_14"; +#elif XBUILD_12 + string profile = "xbuild_12"; +#elif NET_4_5 + string profile = "net_4_x"; +#else + #error "Unknown profile" +#endif + var corlib = typeof (object).Assembly.Location; + var lib = Path.GetDirectoryName (Path.GetDirectoryName (corlib)); + return Path.Combine (lib, profile); + } else { +#if XBUILD_14 + return ToolLocationHelper.GetPathToBuildTools ("14.0"); +#elif XBUILD_12 + return ToolLocationHelper.GetPathToBuildTools ("12.0"); +#elif NET_4_5 + return ToolLocationHelper.GetPathToDotNetFramework (TargetDotNetFrameworkVersion.Version45); +#elif NET_4_0 + return ToolLocationHelper.GetPathToDotNetFramework (TargetDotNetFrameworkVersion.Version40); +#else + return ToolLocationHelper.GetPathToDotNetFramework (TargetDotNetFrameworkVersion.Version20); +#endif + } + } + } + + public static string ToolsVersionString { + get { +#if XBUILD_14 + return " ToolsVersion='14.0'"; +#elif XBUILD_12 + return " ToolsVersion='12.0'"; +#elif NET_4_0 + return " ToolsVersion='4.0'"; +#else + return String.Empty; +#endif + } + } + + public static string GetTasksAsmPath () + { +#if XBUILD_14 + return Path.Combine (BinPath, "Microsoft.Build.Tasks.Core.dll"); +#elif XBUILD_12 + return Path.Combine (BinPath, "Microsoft.Build.Tasks.v12.0.dll"); +#elif NET_4_0 + return Path.Combine (BinPath, "Microsoft.Build.Tasks.v4.0.dll"); +#else + return Path.Combine (BinPath, "Microsoft.Build.Tasks.dll"); +#endif + } + + public const string AssemblySystem_Drawing = "System.Drawing"; + public const string AssemblySystem_Design = "System.Design"; + public const string AssemblySystem_Windows_Forms = "ShiftUI"; +} diff --git a/source/ShiftUI/Design/ControlDataObject.cs b/source/ShiftUI/Design/ControlDataObject.cs new file mode 100644 index 0000000..932a4de --- /dev/null +++ b/source/ShiftUI/Design/ControlDataObject.cs @@ -0,0 +1,120 @@ +using System; +using ShiftUI; + +namespace ShiftUI.Design +{ + // A IDataObject that supports Widget and Widget[] format + // + internal class WidgetDataObject : IDataObject + { + private object _data = null; + private string _format = null; + + public WidgetDataObject () + { + _data = null; + _format = null; + } + + public WidgetDataObject (Widget control) + { + SetData (control); + } + + public WidgetDataObject (Widget[] controls) + { + SetData (controls); + } + + public object GetData (Type format) + { + return this.GetData (format.ToString ()); + } + + public object GetData (string format) + { + return this.GetData (format, true); + } + + public object GetData (string format, bool autoConvert) + { + if (format == _format) { + return _data; + } + return null; + } + + public bool GetDataPresent (Type format) + { + return this.GetDataPresent (format.ToString()); + } + + public bool GetDataPresent (string format) + { + return this.GetDataPresent (format, true); + } + + public bool GetDataPresent (string format, bool autoConvert) + { + if (format == _format) { + return true; + } + return false; + } + + public string[] GetFormats () + { + return this.GetFormats (true); + } + + public string[] GetFormats (bool autoConvert) + { + string[] formats = new string[2]; + formats[0] = typeof (Widget).ToString (); + formats[1] = typeof (Widget[]).ToString (); + return formats; + } + + public void SetData (object data) + { + if (data is Widget) + this.SetData (typeof (Widget), data); + else if (data is Widget[]) + this.SetData (typeof (Widget[]), data); + } + + public void SetData (Type format, object data) + { + this.SetData (format.ToString (), data); + } + + public void SetData (string format, object data) + { + this.SetData (format, true, data); + } + + public void SetData (string format, bool autoConvert, object data) + { + if (ValidateFormat (format)) { + _data = data; + _format = format; + } + } + + private bool ValidateFormat (string format) + { + bool valid = false; + + string[] formats = GetFormats (); + foreach (string f in formats) { + if (f == format) { + valid = true; + break; + } + } + + return valid; + } + } +} + diff --git a/source/ShiftUI/Design/ControlDesigner.cs b/source/ShiftUI/Design/ControlDesigner.cs new file mode 100644 index 0000000..e241f08 --- /dev/null +++ b/source/ShiftUI/Design/ControlDesigner.cs @@ -0,0 +1,974 @@ +// +// ShiftUI.Design.WidgetDesigner +// +// Authors: +// Ivan N. Zlatev (contact i-nZ.net) +// +// (C) 2006-2007 Ivan N. Zlatev + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Runtime.InteropServices; +using ShiftUI; +using System.Drawing; +using System.Drawing.Design; +using System.Collections; +using ShiftUI.Design.Behavior; + +namespace ShiftUI.Design +{ + public class WidgetDesigner : ComponentDesigner, IMessageReceiver + { + + + private WndProcRouter _messageRouter; + private bool _locked = false; + private bool _mouseDown = false; + private bool _mouseMoveAfterMouseDown = false; + private bool _mouseDownFirstMove = false; + private bool _firstMouseMoveInClient = true; + + public WidgetDesigner () + { + } + +#region Initialization + public override void Initialize (IComponent component) + { + base.Initialize (component); + + if (!(component is Widget)) + throw new ArgumentException ("Component is not a Widget."); + + Widget.Text = component.Site.Name; + _messageRouter = new WndProcRouter ((Widget) component, (IMessageReceiver) this); + Widget.WindowTarget = _messageRouter; + + // DT properties + // + this.Visible = true; + this.Enabled = true; + this.Locked = false; + this.AllowDrop = false; + // + // The control properties + // + Widget.Enabled = true; + Widget.Visible = true; + Widget.AllowDrop = false; + + this.Widget.DragDrop += new DragEventHandler (OnDragDrop); + this.Widget.DragEnter += new DragEventHandler (OnDragEnter); + this.Widget.DragLeave += new EventHandler (OnDragLeave); + this.Widget.DragOver += new DragEventHandler (OnDragOver); + + // XXX: The control already has a handle? + // + if (Widget.IsHandleCreated) + OnCreateHandle (); + + } + + // The default implementation of this method sets the component's Text property to + // its name (Component.Site.Name), if the property field is of type string. + // + public override void OnSetComponentDefaults () + { + if (this.Component != null && this.Component.Site != null) { + PropertyDescriptor propertyDescriptor = TypeDescriptor.GetProperties (this.Component)["Text"]; + if (propertyDescriptor != null && !propertyDescriptor.IsReadOnly && + propertyDescriptor.PropertyType == typeof (string)) { + propertyDescriptor.SetValue (Component, Component.Site.Name); + } + } + } +#endregion + + +#region Properties and Fields - AccessabilityObject Left + protected static readonly Point InvalidPoint = new Point (int.MinValue, int.MinValue); + + protected internal BehaviorService BehaviorService { + get { throw new NotImplementedException (); } + } + + public virtual Widget Widget { + get { return (Widget) base.Component; } + } + + protected virtual bool EnableDragRect { + get { return true; } + } + + public virtual SelectionRules SelectionRules { + get { + if (this.Widget == null) + return SelectionRules.None; + + // all controls on the surface are visible + // + SelectionRules selectionRules = SelectionRules.Visible; + + if ((bool)GetValue (this.Component, "Locked") == true) { + selectionRules |= SelectionRules.Locked; + } + else { + DockStyle dockStyle = (DockStyle) this.GetValue (base.Component, "Dock", typeof (DockStyle)); + + switch (dockStyle) { + case DockStyle.Top: + selectionRules |= SelectionRules.BottomSizeable; + break; + case DockStyle.Left: + selectionRules |= SelectionRules.RightSizeable; + break; + case DockStyle.Right: + selectionRules |= SelectionRules.LeftSizeable; + break; + case DockStyle.Bottom: + selectionRules |= SelectionRules.TopSizeable; + break; + case DockStyle.Fill: + break; + default: + selectionRules |= SelectionRules.Moveable; + selectionRules |= SelectionRules.AllSizeable; + break; + } + } + + return selectionRules; + } + } + + public override ICollection AssociatedComponents { + get { + ArrayList components = new ArrayList (); + foreach (Widget c in this.Widget.Widgets) + if (c.Site != null) + components.Add (c); + return components; + } + } + + protected override IComponent ParentComponent { + get { return this.GetValue (this.Widget, "Parent") as Widget;} + } + // TODO: implement WidgetDesigner.WidgetAccessabilityObject + // + public virtual AccessibleObject AccessibilityObject { + get { + if (accessibilityObj == null) + accessibilityObj = new AccessibleObject (); + + return accessibilityObj; + } + } + protected AccessibleObject accessibilityObj; + +#endregion + + +#region WndProc + + protected void DefWndProc (ref Message m) + { + _messageRouter.ToWidget (ref m); + } + + protected void BaseWndProc (ref Message m) + { + _messageRouter.ToSystem (ref m); + } + + void IMessageReceiver.WndProc (ref Message m) + { + this.WndProc (ref m); + } + + // Keep in mind that messages are recieved for the child controls if routed + // + protected virtual void WndProc (ref Message m) + { + // Filter out kb input + // + if ((Native.Msg) m.Msg >= Native.Msg.WM_KEYFIRST && (Native.Msg) m.Msg <= Native.Msg.WM_KEYLAST) + return; + + // Mouse messages should be routed the control, if GetHitTest (virtual) returns true. + // + if (IsMouseMessage ((Native.Msg) m.Msg) && + this.GetHitTest (new Point (Native.LoWord((int) m.LParam), Native.HiWord (((int) m.LParam))))) { + + this.DefWndProc (ref m); + return; + } + + switch ((Native.Msg) m.Msg) { + case Native.Msg.WM_CREATE: + this.DefWndProc (ref m); + if (m.HWnd == this.Widget.Handle) + OnCreateHandle (); + break; + + case Native.Msg.WM_CONTEXTMENU: + break; + + case Native.Msg.WM_SETCURSOR: + if (this.GetHitTest (new Point (Native.LoWord ((int) m.LParam), Native.HiWord ((int) m.LParam)))) + this.DefWndProc (ref m); + else + OnSetCursor (); + break; + + case Native.Msg.WM_SETFOCUS: + this.DefWndProc (ref m); + break; + + case Native.Msg.WM_PAINT: + // Wait for control's WM_PAINT to complete first. + // + this.DefWndProc (ref m); + + Graphics gfx = Graphics.FromHwnd (m.HWnd); + PaintEventArgs args = new PaintEventArgs (gfx, this.Widget.Bounds); + OnPaintAdornments (args); + gfx.Dispose (); + args.Dispose (); + break; + + case Native.Msg.WM_NCRBUTTONDOWN: + case Native.Msg.WM_NCLBUTTONDOWN: + case Native.Msg.WM_NCMBUTTONDOWN: + case Native.Msg.WM_NCLBUTTONDBLCLK: + case Native.Msg.WM_NCRBUTTONDBLCLK: + break; + + case Native.Msg.WM_LBUTTONDBLCLK: + case Native.Msg.WM_RBUTTONDBLCLK: + case Native.Msg.WM_MBUTTONDBLCLK: + if ((Native.Msg)m.Msg == Native.Msg.WM_LBUTTONDBLCLK) + _mouseButtonDown = MouseButtons.Left; + else if ((Native.Msg)m.Msg == Native.Msg.WM_RBUTTONDBLCLK) + _mouseButtonDown = MouseButtons.Right; + else if ((Native.Msg)m.Msg == Native.Msg.WM_MBUTTONDBLCLK) + _mouseButtonDown = MouseButtons.Middle; + OnMouseDoubleClick (); + this.BaseWndProc (ref m); + break; + + case Native.Msg.WM_MOUSEHOVER: + OnMouseHover (); + break; + + case Native.Msg.WM_LBUTTONDOWN: + case Native.Msg.WM_RBUTTONDOWN: + case Native.Msg.WM_MBUTTONDOWN: + _mouseMoveAfterMouseDown = true; + if ((Native.Msg)m.Msg == Native.Msg.WM_LBUTTONDOWN) + _mouseButtonDown = MouseButtons.Left; + else if ((Native.Msg)m.Msg == Native.Msg.WM_RBUTTONDOWN) + _mouseButtonDown = MouseButtons.Right; + else if ((Native.Msg)m.Msg == Native.Msg.WM_MBUTTONDOWN) + _mouseButtonDown = MouseButtons.Middle; + + if (_firstMouseMoveInClient) { + OnMouseEnter (); + _firstMouseMoveInClient = false; + } + this.OnMouseDown (Native.LoWord ((int)m.LParam), Native.HiWord ((int)m.LParam)); + this.BaseWndProc (ref m); + break; + + case Native.Msg.WM_MOUSELEAVE: + _firstMouseMoveInClient = false; + OnMouseLeave (); + this.BaseWndProc (ref m); + break; + + // The WM_CANCELMODE message is sent to cancel certain modes, such as mouse capture. + // For example, the system sends this message to the active window when a dialog box + // or message box is displayed. Certain functions also send this message explicitly to + // the specified window regardless of whether it is the active window. For example, + // the EnableWindow function sends this message when disabling the specified window. + // + case Native.Msg.WM_CANCELMODE: + OnMouseDragEnd (true); + this.DefWndProc (ref m); + break; + + case Native.Msg.WM_LBUTTONUP: + case Native.Msg.WM_RBUTTONUP: + case Native.Msg.WM_NCLBUTTONUP: + case Native.Msg.WM_NCRBUTTONUP: + case Native.Msg.WM_MBUTTONUP: + case Native.Msg.WM_NCMBUTTONUP: + _mouseMoveAfterMouseDown = false; // just in case + this.OnMouseUp (); + this.BaseWndProc (ref m); + break; + + // // MWF Specific msg! - must reach control + // // + // case Native.Msg.WM_MOUSE_ENTER: + // _firstMouseMoveInClient = false; // just so that nothing will get fired in WM_MOUSEMOVE + // OnMouseEnter (); + // this.DefWndProc (ref m); + // break; + + // FIXME: The first MOUSEMOVE after WM_MOUSEDOWN should be ingored + // + case Native.Msg.WM_MOUSEMOVE: + if (_mouseMoveAfterMouseDown) { // mousemove is send after each mousedown so ignore that + _mouseMoveAfterMouseDown = false; + this.BaseWndProc (ref m); + return; + } + // If selection is in progress pass the mouse move msg to the primary selection. + // If resizing is in progress pass to the parent of the primary selection (remmember that the selection + // frame is not a control and is drawn in the parent of the primary selection). + // + // Required in order for those 2 operations to continue when the mouse is moving over a control covering + // the one where the action takes place. + // + IUISelectionService uiSelectionServ = this.GetService (typeof (IUISelectionService)) as IUISelectionService; + ISelectionService selectionServ = this.GetService (typeof (ISelectionService)) as ISelectionService; + IDesignerHost host = this.GetService (typeof (IDesignerHost)) as IDesignerHost; + + + if (uiSelectionServ != null && selectionServ != null && host != null) { + Widget primarySelection = selectionServ.PrimarySelection as Widget; + Point location = new Point (Native.LoWord ((int)m.LParam), Native.HiWord ((int)m.LParam)); + + if (uiSelectionServ.SelectionInProgress && + this.Component != host.RootComponent && + this.Component != selectionServ.PrimarySelection) { + + location = primarySelection.PointToClient (this.Widget.PointToScreen (location)); + Native.SendMessage (primarySelection.Handle, (Native.Msg)m.Msg, m.WParam, Native.LParam (location.X, location.Y)); + } + else if (uiSelectionServ.ResizeInProgress && + // this.Component != host.RootComponent && + this.Widget.Parent == ((Widget)selectionServ.PrimarySelection).Parent) { + + location = this.Widget.Parent.PointToClient (this.Widget.PointToScreen (location)); + Native.SendMessage (this.Widget.Parent.Handle, (Native.Msg)m.Msg, m.WParam, Native.LParam (location.X, location.Y)); + } + else { + this.OnMouseMove (location.X, location.Y); + } + } + else { + this.OnMouseMove (Native.LoWord ((int)m.LParam), Native.HiWord ((int)m.LParam)); + } + this.BaseWndProc (ref m); + break; + + default: + // Pass everything else to the control and return + // + this.DefWndProc (ref m); + break; + } + } + + // Indicates whether a mouse click at the specified point should be handled by the control. + // + protected virtual bool GetHitTest (Point point) + { + return false; + } + + private bool IsMouseMessage (Native.Msg msg) + { + if (msg >= Native.Msg.WM_MOUSEFIRST && msg <= Native.Msg.WM_MOUSELAST) + return true; + else if (msg >= Native.Msg.WM_NCLBUTTONDOWN && msg <= Native.Msg.WM_NCMBUTTONDBLCLK) + return true; + else if (msg == Native.Msg.WM_MOUSEHOVER || msg == Native.Msg.WM_MOUSELEAVE) + return true; + else + return false; + } +#endregion + + +#region WndProc Message Handlers + + protected virtual void OnSetCursor () + { + } + + // Raises the DoDefaultAction. + // + private void OnMouseDoubleClick () + { + try { + base.DoDefaultAction (); + } + catch (Exception e) { + this.DisplayError (e); + } + } + + internal virtual void OnMouseDown (int x, int y) + { + _mouseDown = true; + _mouseDownFirstMove = true; + IUISelectionService uiSelection = this.GetService (typeof (IUISelectionService)) as IUISelectionService; + if (uiSelection != null && uiSelection.AdornmentsHitTest (this.Widget, x, y)) { + // 1) prevent primary selection from being changed at this point. + // 2) delegate behaviour in the future to the IUISelectionService + } + else { + ISelectionService selectionService = this.GetService (typeof (ISelectionService)) as ISelectionService; + if (selectionService != null) { + selectionService.SetSelectedComponents (new IComponent[] { this.Component }); + } + } + } + + // Note that this is a pure WM_MOUSEMOVE acceptor + // + internal virtual void OnMouseMove (int x, int y) + { + if (_mouseDown) { + if (_mouseDownFirstMove) { + OnMouseDragBegin (x, y); + _mouseDownFirstMove = false; + } + else { + OnMouseDragMove (x, y); + } + } + + } + + internal virtual void OnMouseUp () + { + IUISelectionService uiSelection = this.GetService (typeof (IUISelectionService)) as IUISelectionService; + + if (_mouseDown) { + this.OnMouseDragEnd (false); + if (uiSelection != null && (uiSelection.SelectionInProgress || uiSelection.ResizeInProgress)) { + uiSelection.MouseDragEnd (false); + } + _mouseDown = false; + } + else { + if (uiSelection != null && (uiSelection.SelectionInProgress || uiSelection.ResizeInProgress)) { + // If the mouse up happens over the a control which is not defacto participating in + // the selection or resizing in progress, then inform the IUISelectionService of that event + // + uiSelection.MouseDragEnd (false); + } + } + } + + protected virtual void OnMouseEnter () + { + } + + protected virtual void OnMouseHover () + { + } + + protected virtual void OnMouseLeave () + { + } + + // Provides an opportunity to perform additional processing immediately + // after the control handle has been created. + // + protected virtual void OnCreateHandle () + { + } + + // Called after the control is done with the painting so that the designer host + // can paint stuff over it. + // + protected virtual void OnPaintAdornments (PaintEventArgs pe) + { + } +#endregion + + +#region Mouse Dragging + + MouseButtons _mouseButtonDown; + + internal MouseButtons MouseButtonDown { + get { return _mouseButtonDown; } + } + + protected virtual void OnMouseDragBegin (int x, int y) + { + IUISelectionService selectionServ = this.GetService (typeof (IUISelectionService)) as IUISelectionService; + if (selectionServ != null && ((this.SelectionRules & SelectionRules.Moveable) == SelectionRules.Moveable)) { + // once this is fired the parent control (parentcontroldesigner) will start getting dragover events. + // + selectionServ.DragBegin (); + } + } + + protected virtual void OnMouseDragMove (int x, int y) + { + } + + protected virtual void OnMouseDragEnd (bool cancel) + { + } +#endregion + + +#region Parenting + protected void HookChildWidgets (Widget firstWidget) + { + if (firstWidget != null) { + foreach (Widget control in firstWidget.Widgets) { + control.WindowTarget = (IWindowTarget) new WndProcRouter (control, (IMessageReceiver) this); + } + } + } + + protected void UnhookChildWidgets (Widget firstWidget) + { + if (firstWidget != null) { + foreach (Widget control in firstWidget.Widgets) { + if (control.WindowTarget is WndProcRouter) + ((WndProcRouter) control.WindowTarget).Dispose (); + } + } + } + + // Someone please tell me why the hell is this method here? + // What about having ParentWidgetDesigner.CanParent(...) ? + // + public virtual bool CanBeParentedTo (IDesigner parentDesigner) + { + IDesignerHost host = this.GetService (typeof (IDesignerHost)) as IDesignerHost; + + if (parentDesigner is ParentWidgetDesigner && + this.Component != host.RootComponent && + !this.Widget.Widgets.Contains (((ParentWidgetDesigner)parentDesigner).Widget)) { + return true; + } else { + return false; + } + } +#endregion + + protected void DisplayError (Exception e) + { + if (e != null) { + IUIService uiService = GetService (typeof (IUIService)) as IUIService; + if (uiService != null) { + uiService.ShowError (e); + } + else { + string errorText = e.Message; + if (errorText == null || errorText == String.Empty) + errorText = e.ToString (); + MessageBox.Show (errorText, "Error"); + } + } + } + +#region Drag and Drop handling + + // Enables or disables Drag and Drop + // + protected void EnableDragDrop(bool value) + { + if (this.Widget != null) { + if (value) { + Widget.DragDrop += new DragEventHandler (OnDragDrop); + Widget.DragOver += new DragEventHandler (OnDragOver); + Widget.DragEnter += new DragEventHandler (OnDragEnter); + Widget.DragLeave += new EventHandler (OnDragLeave); + Widget.GiveFeedback += new GiveFeedbackEventHandler (OnGiveFeedback); + Widget.AllowDrop = true; + } + else { + Widget.DragDrop -= new DragEventHandler (OnDragDrop); + Widget.DragOver -= new DragEventHandler (OnDragOver); + Widget.DragEnter -= new DragEventHandler (OnDragEnter); + Widget.DragLeave -= new EventHandler (OnDragLeave); + Widget.GiveFeedback -= new GiveFeedbackEventHandler (OnGiveFeedback); + Widget.AllowDrop = false; + } + } + } + + private void OnGiveFeedback (object sender, GiveFeedbackEventArgs e) + { + OnGiveFeedback (e); + } + + private void OnDragDrop (object sender, DragEventArgs e) + { + OnDragDrop (e); + } + + private void OnDragEnter (object sender, DragEventArgs e) + { + OnDragEnter (e); + } + + private void OnDragLeave (object sender, EventArgs e) + { + OnDragLeave (e); + } + + private void OnDragOver (object sender, DragEventArgs e) + { + OnDragOver (e); + } + + protected virtual void OnGiveFeedback (GiveFeedbackEventArgs e) + { + e.UseDefaultCursors = false; + } + + protected virtual void OnDragDrop (DragEventArgs e) + { + } + + protected virtual void OnDragEnter (DragEventArgs e) + { + } + + protected virtual void OnDragLeave (EventArgs e) + { + } + + protected virtual void OnDragOver (DragEventArgs e) + { + } +#endregion + + +#region Redirected Properties + + // This IDesignerFilter interface method override adds a set of properties + // to this designer's component at design time. This method adds the following + // browsable properties: "Visible", "Enabled", "ContextMenu", "AllowDrop", "Location", + // "Name", "Widgets", and "Locked". + // + // XXX: We aren't redirecting Widgets + // + protected override void PreFilterProperties (IDictionary properties) + { + base.PreFilterProperties (properties); + + string[] newProperties = { + "Visible", "Enabled", "ContextMenu", "AllowDrop", "Location", "Name", + }; + + Attribute[][] attributes = { + new Attribute[] { new DefaultValueAttribute (true) }, + new Attribute[] { new DefaultValueAttribute (true) }, + new Attribute[] { new DefaultValueAttribute (null) }, + new Attribute[] { new DefaultValueAttribute (false) }, + new Attribute[] { new DefaultValueAttribute (typeof (Point), "0, 0") }, + new Attribute[] {} + }; + + PropertyDescriptor propertyDescriptor = null; + + // If existing redirect each property to the WidgetDesigner. + // + for (int i=0; i < newProperties.Length; i++) { + propertyDescriptor = properties[newProperties[i]] as PropertyDescriptor; + if (propertyDescriptor != null) + properties[newProperties[i]] = TypeDescriptor.CreateProperty (typeof (WidgetDesigner), + propertyDescriptor, + attributes[i]); + } + + // This one is a must to have. + // + properties["Locked"] = TypeDescriptor.CreateProperty (typeof (WidgetDesigner), "Locked", + typeof(bool), + new Attribute[] { + DesignOnlyAttribute.Yes, + BrowsableAttribute.Yes, + CategoryAttribute.Design, + new DefaultValueAttribute (false), + new DescriptionAttribute("The Locked property determines if we can move or resize the control.") + }); + + } + + // ShadowProperties returns the real property value if there is no "shadow" one set + // Welcome to the land of shadows... :-) + // + private bool Visible { + get { return (bool) base.ShadowProperties["Visible"]; } + set { base.ShadowProperties["Visible"] = value; } + } + + private bool Enabled { + get { return (bool) base.ShadowProperties["Enabled"]; } + set { base.ShadowProperties["Enabled"] = value; } + } + + private bool Locked { + get { return _locked; } + set { _locked = value; } + } + + private bool AllowDrop { + get { return (bool)base.ShadowProperties["AllowDrop"]; } + set { base.ShadowProperties["AllowDrop"] = value; } + } + + private string Name { + get { return base.Component.Site.Name; } + set { base.Component.Site.Name = value; } + } + + private Point Location { + get { return this.Widget.Location; } + set { this.Widget.Location = value; } + } +#endregion + + +#region Utility methods + internal object GetValue (object component, string propertyName) + { + return this.GetValue (component, propertyName, null); + } + + internal object GetValue (object component, string propertyName, Type propertyType) + { + PropertyDescriptor prop = TypeDescriptor.GetProperties (component)[propertyName] as PropertyDescriptor; + if (prop == null) + throw new InvalidOperationException ("Property \"" + propertyName + "\" is missing on " + + component.GetType().AssemblyQualifiedName); + if (propertyType != null && !propertyType.IsAssignableFrom (prop.PropertyType)) + throw new InvalidOperationException ("Types do not match: " + prop.PropertyType.AssemblyQualifiedName + + " : " + propertyType.AssemblyQualifiedName); + return prop.GetValue (component); + } + + internal void SetValue (object component, string propertyName, object value) + { + PropertyDescriptor prop = TypeDescriptor.GetProperties (component)[propertyName] as PropertyDescriptor; + + if (prop == null) + throw new InvalidOperationException ("Property \"" + propertyName + "\" is missing on " + + component.GetType().AssemblyQualifiedName); + if (!prop.PropertyType.IsAssignableFrom (value.GetType ())) + throw new InvalidOperationException ("Types do not match: " + value.GetType ().AssemblyQualifiedName + + " : " + prop.PropertyType.AssemblyQualifiedName); + if (!prop.IsReadOnly) + prop.SetValue (component, value); + } +#endregion + + protected override void Dispose (bool disposing) + { + if (disposing) { + if (this.Widget != null) { + UnhookChildWidgets (Widget); + OnMouseDragEnd (true); + _messageRouter.Dispose (); + this.Widget.DragDrop -= new DragEventHandler (OnDragDrop); + this.Widget.DragEnter -= new DragEventHandler (OnDragEnter); + this.Widget.DragLeave -= new EventHandler (OnDragLeave); + this.Widget.DragOver -= new DragEventHandler (OnDragOver); + } + } + base.Dispose (true); + } + + + + public virtual WidgetDesigner InternalWidgetDesigner (int internalWidgetIndex) + { + return null; + } + + public virtual int NumberOfInternalWidgetDesigners () + { + return 0; + } + + protected bool EnableDesignMode (Widget child, string name) + { + if (name == null) + throw new ArgumentNullException ("name"); + if (child == null) + throw new ArgumentNullException ("child"); + + bool success = false; + INestedContainer nestedContainer = this.GetService (typeof (INestedContainer)) as INestedContainer; + if (nestedContainer != null) { + nestedContainer.Add (child, name); + success = true; + } + return success; + } + +#region NET_2_0 Stubs + + [ComVisible (true)] + public class WidgetDesignerAccessibleObject : AccessibleObject + { + [MonoTODO] + public WidgetDesignerAccessibleObject (WidgetDesigner designer, Widget control) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public override AccessibleObject GetChild (int index) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public override int GetChildCount () + { + throw new NotImplementedException (); + } + + [MonoTODO] + public override AccessibleObject GetFocused () + { + throw new NotImplementedException (); + } + + [MonoTODO] + public override AccessibleObject GetSelected () + { + throw new NotImplementedException (); + } + + [MonoTODO] + public override AccessibleObject HitTest (int x, int y) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public override Rectangle Bounds { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public override string DefaultAction { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public override string Description { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public override string Name { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public override AccessibleObject Parent { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public override AccessibleRole Role { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public override AccessibleStates State { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public override string Value { + get { throw new NotImplementedException (); } + } + } + + [MonoTODO] + protected virtual WidgetBodyGlyph GetWidgetGlyph (GlyphSelectionType selectionType) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual GlyphCollection GetGlyphs (GlyphSelectionType selectionType) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public override void InitializeExistingComponent (IDictionary defaultValues) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public override void InitializeNewComponent (IDictionary defaultValues) + { + throw new NotImplementedException (); + } + + [MonoTODO] + protected virtual void OnDragComplete (DragEventArgs de) + { + throw new NotImplementedException (); + } + + [MonoTODO] + protected override InheritanceAttribute InheritanceAttribute { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public virtual IList SnapLines { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public virtual bool ParticipatesWithSnapLines { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public bool AutoResizeHandles { + get { throw new NotImplementedException (); } + set { throw new NotImplementedException (); } + } +#endregion + + + } +} diff --git a/source/ShiftUI/Design/DefaultMenuCommands.cs b/source/ShiftUI/Design/DefaultMenuCommands.cs new file mode 100644 index 0000000..8284d82 --- /dev/null +++ b/source/ShiftUI/Design/DefaultMenuCommands.cs @@ -0,0 +1,274 @@ +// +// System.ComponentModel.Design.DefaultMenuCommands.cs +// +// Author: +// Ivan N. Zlatev +// +// (C) 2008 Ivan N. Zlatev +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.ComponentModel.Design.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Runtime.InteropServices; +using ShiftUI; +using System.Drawing; +using System.Drawing.Design; +using System.Collections; +using System.IO; +using ShiftUI.Design; + +namespace ShiftUI +{ + internal sealed class DefaultMenuCommands + { + private IServiceProvider _serviceProvider; + private const string DT_DATA_FORMAT = "DT_DATA_FORMAT"; + + public DefaultMenuCommands (IServiceProvider serviceProvider) + { + if (serviceProvider == null) + throw new ArgumentNullException ("serviceProvider"); + _serviceProvider = serviceProvider; + } + + public void AddTo (IMenuCommandService commands) + { + commands.AddCommand (new MenuCommand (Copy, StandardCommands.Copy)); + commands.AddCommand (new MenuCommand (Cut, StandardCommands.Cut)); + commands.AddCommand (new MenuCommand (Paste, StandardCommands.Paste)); + commands.AddCommand (new MenuCommand (Delete, StandardCommands.Delete)); + commands.AddCommand (new MenuCommand (SelectAll, StandardCommands.SelectAll)); + } + + private object _clipboard = null; + + private void Copy (object sender, EventArgs args) + { + IDesignerSerializationService stateSerializer = GetService (typeof (IDesignerSerializationService)) as IDesignerSerializationService; + IDesignerHost host = GetService (typeof (IDesignerHost)) as IDesignerHost; + ISelectionService selection = GetService (typeof (ISelectionService)) as ISelectionService; + if (host == null || stateSerializer == null || selection == null) + return; + + // copy selected components and their associated components + ICollection selectedComponents = selection.GetSelectedComponents (); + ArrayList toCopy = new ArrayList (); + foreach (object component in selectedComponents) { + if (component == host.RootComponent) + continue; + toCopy.Add (component); + Design.ComponentDesigner designer = host.GetDesigner ((IComponent)component) as Design.ComponentDesigner; + if (designer != null && designer.AssociatedComponents != null) + toCopy.AddRange (designer.AssociatedComponents); + } + object stateData = stateSerializer.Serialize (toCopy); + _clipboard = stateData; + // Console.WriteLine ("Copied components: "); + // foreach (object c in toCopy) + // Console.WriteLine (((IComponent)c).Site.Name); + // + + // TODO: MWF X11 doesn't seem to support custom clipboard formats - bug #357642 + // + // MemoryStream stream = new MemoryStream (); + // new BinaryFormatter().Serialize (stream, stateData); + // stream.Seek (0, SeekOrigin.Begin); + // byte[] serializedData = stream.GetBuffer (); + // Clipboard.SetDataObject (new DataObject (DT_DATA_FORMAT, serializedData)); + } + + // Reminder: We set control.Parent so that it gets serialized for Undo/Redo + // + private void Paste (object sender, EventArgs args) + { + IDesignerSerializationService stateSerializer = GetService (typeof (IDesignerSerializationService)) as IDesignerSerializationService; + ISelectionService selection = GetService (typeof (ISelectionService)) as ISelectionService; + IDesignerHost host = GetService (typeof (IDesignerHost)) as IDesignerHost; + IComponentChangeService changeService = GetService (typeof (IComponentChangeService)) as IComponentChangeService; + if (host == null || stateSerializer == null) + return; + // + // TODO: MWF X11 doesn't seem to support custom clipboard formats - bug #357642 + // + // IDataObject dataObject = Clipboard.GetDataObject (); + // byte[] data = dataObject == null ? null : dataObject.GetData (DT_DATA_FORMAT) as byte[]; + // if (data != null) { + // MemoryStream stream = new MemoryStream (data); + // stateSerializer.Deserialize (new BinaryFormatter().Deserialize (stream)); + // ..... + // } + // + if (_clipboard == null) + return; + + DesignerTransaction transaction = host.CreateTransaction ("Paste"); + ICollection components = stateSerializer.Deserialize (_clipboard); + // Console.WriteLine ("Pasted components: "); + // foreach (object c in components) + // Console.WriteLine (((IComponent)c).Site.Name); + foreach (object component in components) { + Widget control = component as Widget; + if (control == null) + continue; // pure Components are added to the ComponentTray by the DocumentDesigner + + PropertyDescriptor parentProperty = TypeDescriptor.GetProperties (control)["Parent"]; + if (control.Parent != null) { + // Already parented during deserialization? + // In that case explicitly raise component changing/ed for the Parent property, + // so it get's cought by the UndoEngine + if (changeService != null) { + changeService.OnComponentChanging (control, parentProperty); + changeService.OnComponentChanged (control, parentProperty, null, control.Parent); + } + } else { + ParentWidgetDesigner parentDesigner = null; + if (selection != null && selection.PrimarySelection != null) + parentDesigner = host.GetDesigner ((IComponent)selection.PrimarySelection) as ParentWidgetDesigner; + if (parentDesigner == null) + parentDesigner = host.GetDesigner (host.RootComponent) as DocumentDesigner; + if (parentDesigner != null && parentDesigner.CanParent (control)) + parentProperty.SetValue (control, parentDesigner.Widget); + } + } + _clipboard = null; + transaction.Commit (); + ((IDisposable)transaction).Dispose (); + } + + private void Cut (object sender, EventArgs args) + { + IDesignerHost host = GetService (typeof (IDesignerHost)) as IDesignerHost; + if (host == null) + return; + using (DesignerTransaction transaction = host.CreateTransaction ("Cut")) { + Copy (this, EventArgs.Empty); + Delete (this, EventArgs.Empty); + transaction.Commit (); + } + } + + private void Delete (object sender, EventArgs args) + { + IDesignerHost host = GetService (typeof (IDesignerHost)) as IDesignerHost; + ISelectionService selection = GetService (typeof (ISelectionService)) as ISelectionService; + if (host == null || selection == null) + return; + + ICollection selectedComponents = selection.GetSelectedComponents (); + string description = "Delete " + + (selectedComponents.Count > 1 ? (selectedComponents.Count.ToString () + " controls") : + ((IComponent)selection.PrimarySelection).Site.Name); + DesignerTransaction transaction = host.CreateTransaction (description); + + foreach (object component in selectedComponents) { + if (component != host.RootComponent) { + Design.ComponentDesigner designer = host.GetDesigner ((IComponent)component) as Design.ComponentDesigner; + if (designer != null && designer.AssociatedComponents != null) { + foreach (object associatedComponent in designer.AssociatedComponents) + host.DestroyComponent ((IComponent)associatedComponent); + } + host.DestroyComponent ((IComponent)component); + } + } + selection.SetSelectedComponents (selectedComponents, SelectionTypes.Remove); + transaction.Commit (); + } + + private void SelectAll (object sender, EventArgs args) + { + IDesignerHost host = GetService (typeof (IDesignerHost)) as IDesignerHost; + ISelectionService selection = GetService (typeof (ISelectionService)) as ISelectionService; + if (host != null && selection != null) + selection.SetSelectedComponents (host.Container.Components, SelectionTypes.Replace); + } + + // * StandardCommands + // o AlignBottom + // o AlignHorizontalCenters + // o AlignLeft + // o AlignRight + // o AlignToGrid + // o AlignTop + // o AlignVerticalCenters + // o BringToFront + // o CenterHorizontally + // o CenterVertically + // -o Copy + // -o Cut + // -o Delete + // o HorizSpaceConcatenate + // o HorizSpaceDecrease + // o HorizSpaceIncrease + // o HorizSpaceMakeEqual + // -o Paste + // -o SelectAll + // o SendToBack + // o SizeToWidget + // o SizeToWidgetHeight + // o SizeToWidgetWidth + // o SizeToGrid + // o SnapToGrid + // o TabOrder + // o VertSpaceConcatenate + // o VertSpaceDecrease + // o VertSpaceIncrease + // o VertSpaceMakeEqual + // o ShowGrid + // o LockWidgets + // + // * MenuCommands + // o KeyDefaultAction + // o KeySelectNext + // o KeySelectPrevious + // o KeyMoveLeft + // o KeySizeWidthDecrease + // o KeyMoveRight + // o KeySizeWidthIncrease + // o KeyMoveUp + // o KeySizeHeightIncrease + // o KeyMoveDown + // o KeySizeHeightDecrease + // o KeyCancel + // o KeyNudgeLeft + // o KeyNudgeDown + // o KeyNudgeRight + // o KeyNudgeUp + // o KeyNudgeHeightIncrease + // o KeyNudgeHeightDecrease + // o KeyNudgeWidthDecrease + // o KeyNudgeWidthIncrease + // o DesignerProperties + // o KeyReverseCancel + + private object GetService (Type serviceType) + { + if (_serviceProvider != null) + return _serviceProvider.GetService (serviceType); + return null; + } + } +} diff --git a/source/ShiftUI/Design/DocumentDesigner.cs b/source/ShiftUI/Design/DocumentDesigner.cs new file mode 100644 index 0000000..e132b1d --- /dev/null +++ b/source/ShiftUI/Design/DocumentDesigner.cs @@ -0,0 +1,485 @@ +// +// ShiftUI.Design.DocumentDesigner +// +// Authors: +// Ivan N. Zlatev (contact i-nZ.net) +// +// (C) 2006-2007 Ivan N. Zlatev + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using ShiftUI; +using System.Drawing; +using System.Drawing.Design; +using System.Collections; +using ShiftUI.Design.Behavior; + +namespace ShiftUI.Design +{ + [ToolboxItemFilter ("ShiftUI")] + public class DocumentDesigner : ScrollableWidgetDesigner, IRootDesigner, IToolboxUser + { + + // This is what you *see* + /* + .-------------------------------------. + | Panel to host the designed Widget | + |--------------Splitter---------------| + | Panel with a ComponentTray | + |_____________________________________| + + */ + // +#region DesignerViewFrame + public class DesignerViewFrame : ShiftUI.UserWidget + { + private ShiftUI.Panel DesignerPanel; + private ShiftUI.Splitter splitter1; + private ShiftUI.Panel ComponentTrayPanel; + private ComponentTray _componentTray; + private Widget _designedWidget; + + public DesignerViewFrame (Widget designedWidget, ComponentTray tray) + { + if (designedWidget == null) { + throw new ArgumentNullException ("designedWidget"); + } + if (tray == null) { + throw new ArgumentNullException ("tray"); + } + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + + _designedWidget = designedWidget; + this.SuspendLayout (); + this.DesignerPanel.Widgets.Add (designedWidget); + this.ResumeLayout (); + + this.ComponentTray = tray; + } + +#region Windows Forms Designer generated code + /// + /// This method is required for Windows Forms designer support. + /// Do not change the method contents inside the source code editor. The Forms designer might + /// not be able to load this method if it was changed manually. + /// + private void InitializeComponent() { + this.ComponentTrayPanel = new ShiftUI.Panel(); + this.splitter1 = new ShiftUI.Splitter(); + this.DesignerPanel = new ShiftUI.Panel(); + this.SuspendLayout(); + // + // ComponentTrayPanel + // + this.ComponentTrayPanel.BackColor = System.Drawing.Color.LemonChiffon; + this.ComponentTrayPanel.Dock = ShiftUI.DockStyle.Bottom; + this.ComponentTrayPanel.Location = new System.Drawing.Point(0, 194); + this.ComponentTrayPanel.Name = "ComponentTrayPanel"; + this.ComponentTrayPanel.Size = new System.Drawing.Size(292, 72); + this.ComponentTrayPanel.TabIndex = 1; + this.ComponentTrayPanel.Visible = false; + // + // splitter1 + // + this.splitter1.Dock = ShiftUI.DockStyle.Bottom; + this.splitter1.Location = new System.Drawing.Point(0, 186); + this.splitter1.Name = "splitter1"; + this.splitter1.Size = new System.Drawing.Size(292, 8); + this.splitter1.TabIndex = 2; + this.splitter1.TabStop = false; + this.splitter1.Visible = false; + // + // DesignerPanel + // + this.DesignerPanel.AutoScroll = true; + this.DesignerPanel.BackColor = System.Drawing.Color.White; + this.DesignerPanel.Dock = ShiftUI.DockStyle.Fill; + this.DesignerPanel.Location = new System.Drawing.Point(0, 0); + this.DesignerPanel.Name = "DesignerPanel"; + this.DesignerPanel.Size = new System.Drawing.Size(292, 266); + this.DesignerPanel.TabIndex = 0; + this.DesignerPanel.MouseUp += new ShiftUI.MouseEventHandler(this.DesignerPanel_MouseUp); + this.DesignerPanel.MouseMove += new ShiftUI.MouseEventHandler(this.DesignerPanel_MouseMove); + this.DesignerPanel.MouseDown += new ShiftUI.MouseEventHandler(this.DesignerPanel_MouseDown); + this.DesignerPanel.Paint += new PaintEventHandler (DesignerPanel_Paint); + // + // DesignerViewFrame + // + this.Widgets.Add(this.splitter1); + this.Widgets.Add(this.ComponentTrayPanel); + this.Widgets.Add(this.DesignerPanel); + this.Name = "UserWidget1"; + this.Size = new System.Drawing.Size(292, 266); + this.Dock = DockStyle.Fill; + this.ResumeLayout(false); + } + +#endregion + + private bool _mouseDown = false; + private bool _firstMove = false; + + void DesignerPanel_Paint (object sender, PaintEventArgs e) + { + IUISelectionService selectionServ = this.DesignedWidget.Site.GetService (typeof (IUISelectionService)) as IUISelectionService; + if (selectionServ != null) + selectionServ.PaintAdornments (this.DesignerPanel, e.Graphics); + } + + void DesignerPanel_MouseDown(object sender, ShiftUI.MouseEventArgs e) + { + _mouseDown = true; + _firstMove = true; + } + + void DesignerPanel_MouseMove(object sender, ShiftUI.MouseEventArgs e) + { + IUISelectionService selectionServ = this.DesignedWidget.Site.GetService (typeof (IUISelectionService)) as IUISelectionService; + if (selectionServ == null) + return; + + selectionServ.SetCursor (e.X, e.Y); + if (_mouseDown) { + if (_firstMove) { + selectionServ.MouseDragBegin (this.DesignerPanel, e.X, e.Y); + _firstMove = false; + } + else { + selectionServ.MouseDragMove (e.X, e.Y); + } + } + else if (selectionServ.SelectionInProgress) { + selectionServ.MouseDragMove (e.X, e.Y); + } + } + + void DesignerPanel_MouseUp(object sender, ShiftUI.MouseEventArgs e) + { + IUISelectionService selectionServ = this.DesignedWidget.Site.GetService (typeof (IUISelectionService)) as IUISelectionService; + if (_mouseDown) { + if (selectionServ != null) + selectionServ.MouseDragEnd (false); + _mouseDown = false; + } + else if (selectionServ.SelectionInProgress) { + selectionServ.MouseDragEnd (false); + } + } + + // by default the component tray is hidden and essentially should be shown once there + // is a component added to it + // + public void ShowComponentTray () + { + if (!this.ComponentTray.Visible) { + this.ComponentTrayPanel.Visible = true; + this.ComponentTray.Visible = true; + this.splitter1.Visible = true; + } + } + + public void HideComponentTray () + { + if (!this.ComponentTray.Visible) { + this.ComponentTrayPanel.Visible = true; + this.ComponentTray.Visible = true; + this.splitter1.Visible = true; + } + } + + public ComponentTray ComponentTray { + get { return _componentTray; } + set { + this.SuspendLayout (); + this.ComponentTrayPanel.Widgets.Remove (_componentTray); + this.ComponentTrayPanel.Widgets.Add (value); + this.ResumeLayout (); + _componentTray = value; + _componentTray.Visible = false; + } + } + + public Widget DesignedWidget { + get { return _designedWidget; } + set { + } + } + + protected override void Dispose (bool disposing) + { + if (_designedWidget != null) { + this.DesignerPanel.Widgets.Remove (_designedWidget); + _designedWidget = null; + } + + if (_componentTray != null) { + this.ComponentTrayPanel.Widgets.Remove (_componentTray); + _componentTray.Dispose (); + _componentTray = null; + } + + base.Dispose (disposing); + } + } +#endregion + + + + + private DesignerViewFrame _designerViewFrame; + + public DocumentDesigner () + { + } + + private DesignerViewFrame View { + get { return _designerViewFrame; } + } + +#region Initialization + public override void Initialize (IComponent component) + { + base.Initialize (component); + + _designerViewFrame = new DesignerViewFrame (this.Widget, new ComponentTray (this, component.Site)); + _designerViewFrame.DesignedWidget.Location = new Point (15, 15); + SetValue (this.Component, "Location", new Point (0, 0)); + + IComponentChangeService componentChangeSvc = GetService (typeof (IComponentChangeService)) as IComponentChangeService; + if (componentChangeSvc != null) { + componentChangeSvc.ComponentAdded += new ComponentEventHandler (OnComponentAdded); + componentChangeSvc.ComponentRemoved += new ComponentEventHandler (OnComponentRemoved); + } + + IMenuCommandService menuCommands = GetService (typeof (IMenuCommandService)) as IMenuCommandService; + IServiceContainer serviceContainer = this.GetService (typeof (IServiceContainer)) as IServiceContainer; + if (menuCommands != null && serviceContainer != null) + new DefaultMenuCommands (serviceContainer).AddTo (menuCommands); + InitializeSelectionService (); + } + + private void InitializeSelectionService () + { + IUISelectionService guiSelectionService = this.GetService (typeof (IUISelectionService)) as IUISelectionService; + if (guiSelectionService == null) { + IServiceContainer serviceContainer = this.GetService (typeof (IServiceContainer)) as IServiceContainer; + serviceContainer.AddService (typeof (IUISelectionService), (IUISelectionService) new UISelectionService (serviceContainer)); + } + + ISelectionService selectionService = this.GetService (typeof (ISelectionService)) as ISelectionService; + selectionService.SetSelectedComponents (new IComponent[] { this.Component }); + } + + + protected override void Dispose (bool disposing) + { + if (disposing) { + if (_designerViewFrame != null) { + _designerViewFrame.Dispose (); + _designerViewFrame = null; + + } + IComponentChangeService componentChangeSvc = GetService (typeof (IComponentChangeService)) as IComponentChangeService; + if (componentChangeSvc != null) { + componentChangeSvc.ComponentAdded -= new ComponentEventHandler (OnComponentAdded); + componentChangeSvc.ComponentRemoved -= new ComponentEventHandler (OnComponentRemoved); + } + } + base.Dispose (disposing); + } +#endregion + + +#region MSDN says overriden + + public override GlyphCollection GetGlyphs (GlyphSelectionType selectionType) + { + return base.GetGlyphs (selectionType); + } + + protected override void WndProc (ref Message m) + { + base.WndProc (ref m); + } + + protected override void OnCreateHandle () + { + base.OnCreateHandle (); + } + +#endregion + + +#region Components and ComponentTray + + private void OnComponentAdded (object sender, ComponentEventArgs args) + { + if (!(args.Component is Widget)) { + this.View.ComponentTray.AddComponent (args.Component); + if (this.View.ComponentTray.ComponentCount > 0) { + if (!this.View.ComponentTray.Visible) + this.View.ShowComponentTray (); + } + } + } + + private void OnComponentRemoved (object sender, ComponentEventArgs args) + { + if (!(args.Component is Widget)) { + this.View.ComponentTray.RemoveComponent (args.Component); + if (this.View.ComponentTray.ComponentCount == 0) { + if (this.View.ComponentTray.Visible) + this.View.HideComponentTray (); + } + } + } +#endregion + + +#region IRootDesigner + + object IRootDesigner.GetView (ViewTechnology technology) + { + if (technology != ViewTechnology.Default) + throw new ArgumentException ("Only ViewTechnology.WindowsForms is supported."); + return _designerViewFrame; + } + + ViewTechnology[] IRootDesigner.SupportedTechnologies { + get { + return new ViewTechnology[] { ViewTechnology.Default }; + } + } +#endregion + + +#region IToolBoxUser + + // Indicates whether the specified tool is supported by the designer. + // If it is not the tool is disabled in the toolbox. + // + // Used for subclasses, e.g the FormDocumentDesigner won't accept a Form? + // + bool IToolboxUser.GetToolSupported (ToolboxItem tool) + { + return this.GetToolSupported (tool); + } + + protected virtual bool GetToolSupported (ToolboxItem tool) + { + return true; + } + + + // Handles the behavior that occurs when a user double-clicks a toolbox item. + // + void IToolboxUser.ToolPicked (ToolboxItem tool) + { + this.ToolPicked (tool); + } + + // ToolPicked is called when the user double-clicks on a toolbox item. + // The document designer should create a component for the specified tool. + // Only tools that are enabled in the toolbox will be passed to this method. + // + // I create the component in the parent container of the primary selection. + // If not available I create it in the rootcomponent (this essentially :-) ) + // + protected virtual void ToolPicked (ToolboxItem tool) + { + ISelectionService selectionSvc = GetService (typeof (ISelectionService)) as ISelectionService; + IDesignerHost host = GetService (typeof (IDesignerHost)) as IDesignerHost; + if (selectionSvc != null && host != null) { + IDesigner designer = host.GetDesigner ((IComponent) selectionSvc.PrimarySelection); + if (designer is ParentWidgetDesigner) + ParentWidgetDesigner.InvokeCreateTool ((ParentWidgetDesigner) designer, tool); + else + this.CreateTool (tool); + } + else { + this.CreateTool (tool); + } + IToolboxService tbServ = this.GetService (typeof (IToolboxService)) as IToolboxService; + tbServ.SelectedToolboxItemUsed (); + } +#endregion + + +#region Properties + // A root designer can be resized to the bottom and to the right. + // + public override SelectionRules SelectionRules { + get { + return (SelectionRules.RightSizeable | SelectionRules.BottomSizeable | SelectionRules.Visible); + } + } +#endregion + + +#region Metadata filtering and Design-Time properties + + // MSDN says that this adds the "BackColor" and "Location" browsable design-time propeties. + // + // The reason for overwriting the Location property created by the ControDesigner is that + // the root component is not draggable (e.g a form has a static location in the DesignerViewFrame) + // + protected override void PreFilterProperties (IDictionary properties) + { + base.PreFilterProperties (properties); + + PropertyDescriptor propertyDescriptor = properties["BackColor"] as PropertyDescriptor; + if (propertyDescriptor != null) { + properties["BackColor"] = TypeDescriptor.CreateProperty (typeof (DocumentDesigner), + propertyDescriptor, + new Attribute[] { new DefaultValueAttribute (System.Drawing.SystemColors.Control) }); + } + + propertyDescriptor = properties["Location"] as PropertyDescriptor; + if (propertyDescriptor != null) { + properties["Location"] = TypeDescriptor.CreateProperty (typeof (DocumentDesigner), + propertyDescriptor, + new Attribute[] { new DefaultValueAttribute (typeof (Point), "0, 0") }); + } + } + + private Color BackColor { + get { return (Color) ShadowProperties["BackColor"]; } + set { + ShadowProperties["BackColor"] = value; + this.Widget.BackColor = value; + } + } + + private Point Location { + get { return (Point) ShadowProperties["Location"]; } + set { ShadowProperties["Location"] = value; } + } +#endregion + + } +} diff --git a/source/ShiftUI/Design/EventsTab.cs b/source/ShiftUI/Design/EventsTab.cs new file mode 100644 index 0000000..570f850 --- /dev/null +++ b/source/ShiftUI/Design/EventsTab.cs @@ -0,0 +1,101 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2008 Novell, Inc. +// +// Authors: +// Dennis Hayes (dennish@raytek.com) +// Rafael Teixeira (rafaelteixeirabr@hotmail.com) +// Ivan N. Zlatev (contact@i-nz.net) +// + +// COMPLETE + +using System; +using System.ComponentModel; +using System.ComponentModel.Design; + +namespace ShiftUI.Design +{ + public class EventsTab : PropertyTab + { + private EventsTab() + { + } + + private IServiceProvider serviceProvider; + + public EventsTab(IServiceProvider sp) + { + this.serviceProvider = sp; + } + + public override string HelpKeyword { + get { return TabName; } + } + + public override string TabName { + get { return "Events"; } + } + + public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object component, + Attribute[] attributes) + { + IEventBindingService eventPropertySvc = null; + EventDescriptorCollection events = null; + + if (serviceProvider != null) + eventPropertySvc = (IEventBindingService) serviceProvider.GetService(typeof(IEventBindingService)); + + if (eventPropertySvc == null) + return new PropertyDescriptorCollection(null); + + if (attributes != null) + events = TypeDescriptor.GetEvents(component, attributes); + else + events = TypeDescriptor.GetEvents(component); + + // Return event properties for the event descriptors. + return eventPropertySvc.GetEventProperties(events); + } + + public override PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes) + { + return this.GetProperties(null, component, attributes); + } + + public override bool CanExtend(object extendee) + { + return false; + } + + public override PropertyDescriptor GetDefaultProperty(object obj) + { + if (serviceProvider == null) + return null; + + EventDescriptor defaultEvent = TypeDescriptor.GetDefaultEvent (obj); + IEventBindingService eventPropertySvc = (IEventBindingService) serviceProvider.GetService(typeof(IEventBindingService)); + if (defaultEvent != null && eventPropertySvc != null) + return eventPropertySvc.GetEventProperty (defaultEvent); + return null; + } + + } +} diff --git a/source/ShiftUI/Design/FormDocumentDesigner.cs b/source/ShiftUI/Design/FormDocumentDesigner.cs new file mode 100644 index 0000000..d3f8b14 --- /dev/null +++ b/source/ShiftUI/Design/FormDocumentDesigner.cs @@ -0,0 +1,86 @@ +// +// ShiftUI.Design.FormDocumentDesigner +// +// Authors: +// Ivan N. Zlatev (contact i-nZ.net) +// +// (C) 2008 Ivan N. Zlatev + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using ShiftUI; +using System.Drawing; +using System.Drawing.Design; +using System.Collections; + +namespace ShiftUI.Design +{ + internal class FormDocumentDesigner : DocumentDesigner + { + + public FormDocumentDesigner () + { + } + + public override void Initialize (IComponent component) + { + Form form = component as Form; + if (form == null) + throw new NotSupportedException ("FormDocumentDesigner can be initialized only with Forms"); + + form.TopLevel = false; + form.Visible = true; + base.Initialize (component); + } + + public override bool CanParent (Widget control) + { + if (control is Form) + return false; + return base.CanParent (control); + } + + protected override void WndProc (ref Message m) + { + // Filter out titlebar clicks + // + switch ((Native.Msg) m.Msg) { + case Native.Msg.WM_NCLBUTTONDBLCLK: + case Native.Msg.WM_NCLBUTTONDOWN: + case Native.Msg.WM_NCMBUTTONDBLCLK: + case Native.Msg.WM_NCMBUTTONDOWN: + case Native.Msg.WM_NCRBUTTONDBLCLK: + case Native.Msg.WM_NCRBUTTONDOWN: + ISelectionService selectionServ = this.GetService (typeof (ISelectionService)) as ISelectionService; + if (selectionServ != null) + selectionServ.SetSelectedComponents (new object[] { this.Component }); + break; + default: + base.WndProc (ref m); + break; + } + } + } +} diff --git a/source/ShiftUI/Design/IMenuEditorService.cs b/source/ShiftUI/Design/IMenuEditorService.cs new file mode 100644 index 0000000..2d90849 --- /dev/null +++ b/source/ShiftUI/Design/IMenuEditorService.cs @@ -0,0 +1,34 @@ + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +using System; + +namespace ShiftUI.Design +{ + public interface IMenuEditorService + { + Menu GetMenu(); + bool IsActive(); + bool MessageFilter(ref Message m); + void SetMenu(Menu menu); + void SetSelection(MenuItem item); + } +} diff --git a/source/ShiftUI/Design/IMessageReceiver.cs b/source/ShiftUI/Design/IMessageReceiver.cs new file mode 100644 index 0000000..b36ad31 --- /dev/null +++ b/source/ShiftUI/Design/IMessageReceiver.cs @@ -0,0 +1,39 @@ +// +// ShiftUI.Design.IMessageReceiver +// +// Authors: +// Ivan N. Zlatev (contact i-nZ.net) +// +// (C) 2006-2007 Ivan N. Zlatev + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using ShiftUI; + +namespace ShiftUI.Design +{ + internal interface IMessageReceiver + { + void WndProc (ref Message m); + } +} diff --git a/source/ShiftUI/Design/IUISelectionService.cs b/source/ShiftUI/Design/IUISelectionService.cs new file mode 100644 index 0000000..7c8ad47 --- /dev/null +++ b/source/ShiftUI/Design/IUISelectionService.cs @@ -0,0 +1,71 @@ +// +// ShiftUI.Design.IUISelectionService +// +// Authors: +// Ivan N. Zlatev (contact i-nZ.net) +// +// (C) 2006-2007 Ivan N. Zlatev + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Drawing.Drawing2D; +using ShiftUI; + +namespace ShiftUI.Design +{ + + + internal interface IUISelectionService + { + bool SelectionInProgress { + get; + } + bool DragDropInProgress { + get; + } + bool ResizeInProgress { + get; + } + + Rectangle SelectionBounds { + get; + } + + void MouseDragBegin (Widget container, int x, int y); + void MouseDragMove (int x, int y); + void MouseDragEnd (bool cancel); + + void DragBegin (); + void DragOver (Widget container, int x, int y); + void DragDrop (bool cancel, Widget container, int x, int y); + + void PaintAdornments (Widget container, Graphics gfx); + bool SetCursor (int x, int y); + + bool AdornmentsHitTest (Widget control, int x, int y); + } +} diff --git a/source/ShiftUI/Design/IUIService.cs b/source/ShiftUI/Design/IUIService.cs new file mode 100644 index 0000000..71368dd --- /dev/null +++ b/source/ShiftUI/Design/IUIService.cs @@ -0,0 +1,52 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Andreas Nahr (ClassDevelopment@A-SoftTech.com) +// + +// NOT COMPLETE + +using System.Runtime.InteropServices; +using System.Collections; +using System; + +namespace ShiftUI.Design +{ + [Guid ("06a9c74b-5e32-4561-be73-381b37869f4f")] + public interface IUIService + { + IDictionary Styles {get;} + + bool CanShowComponentEditor (object component); + IWin32Window GetDialogOwnerWindow (); + void SetUIDirty (); + bool ShowComponentEditor (object component, IWin32Window parent); + void ShowError (Exception ex); + void ShowError (string message); + void ShowError (Exception ex, string message); + DialogResult ShowDialog (Form form); + void ShowMessage (string message); + void ShowMessage (string message, string caption); + DialogResult ShowMessage (string message, string caption, MessageBoxButtons buttons); + bool ShowToolWindow (Guid toolWindow); + } +} diff --git a/source/ShiftUI/Design/IWindowsFormsEditorService.cs b/source/ShiftUI/Design/IWindowsFormsEditorService.cs new file mode 100644 index 0000000..cfd5601 --- /dev/null +++ b/source/ShiftUI/Design/IWindowsFormsEditorService.cs @@ -0,0 +1,35 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Andreas Nahr (ClassDevelopment@A-SoftTech.com) +// + +// NOT COMPLETE + +namespace ShiftUI.Design +{ + public interface IWindowsFormsEditorService { + void CloseDropDown (); + void DropDownWidget (Widget Widget); + DialogResult ShowDialog (Form dialog); + } +} diff --git a/source/ShiftUI/Design/Native.cs b/source/ShiftUI/Design/Native.cs new file mode 100644 index 0000000..bd86c42 --- /dev/null +++ b/source/ShiftUI/Design/Native.cs @@ -0,0 +1,216 @@ +// +// ShiftUI.Design.Native +// +// Authors: +// Ivan N. Zlatev (contact i-nZ.net) +// +// (C) 2006-2007 Ivan N. Zlatev +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Drawing; +using ShiftUI; +using System.Runtime.InteropServices; +using System.Reflection; + + +namespace ShiftUI +{ + + internal class Native + { + + private static Type _xplatuiType; + + static Native () + { + Assembly assembly = Assembly.GetExecutingAssembly(); + if (assembly == null) + throw new InvalidOperationException ("Can't load ShiftUI assembly."); + + _xplatuiType = assembly.GetType ("ShiftUI.XplatUI"); + if (_xplatuiType == null) + throw new InvalidOperationException ("Can't find the ShiftUI.XplatUI type."); + } + + private static object InvokeMethod (string methodName, object[] args) + { + return InvokeMethod (methodName, args, null); + } + + // will also match types + private static object InvokeMethod (string methodName, object[] args, Type[] types) + { + MethodInfo method = null; + + if (types != null) { + method = _xplatuiType.GetMethod (methodName, BindingFlags.NonPublic | BindingFlags.Static | + BindingFlags.InvokeMethod, null, types, null); + } else { + method = _xplatuiType.GetMethod (methodName, BindingFlags.NonPublic | BindingFlags.Static | + BindingFlags.InvokeMethod); + } + + if (method == null) + throw new InvalidOperationException (methodName + " not found!"); + + return method.Invoke (null, args); + } + + public static void DefWndProc (ref Message m) + { + object[] args = new object[] { m }; + m.Result = (IntPtr) InvokeMethod ("DefWndProc", args); + m = (Message) args[0]; + } + + public static IntPtr SendMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam) + { + + Assembly assembly = Assembly.GetExecutingAssembly(); + Type refType = assembly.GetType ("ShiftUI.Message&"); + object[] args = new object[] { Message.Create (hwnd, (int)message, wParam, lParam) }; + InvokeMethod ("SendMessage", args, new Type[] { refType }); + return ((Message)args[0]).Result; + } + + public static Point PointToClient (Widget control, Point point) + { + if (control == null) + throw new ArgumentNullException ("control"); + + object[] args = new object[] { control.Handle, point.X, point.Y }; + InvokeMethod ("ScreenToClient", args); + return new Point ((int) args[1], (int) args[2]); + } + + public static IntPtr SetParent (IntPtr childHandle, IntPtr parentHandle) + { + return (IntPtr) InvokeMethod ("SetParent", new object[] { childHandle, parentHandle }); + } + + +#region Helpers + public static int HiWord (int dword) + { + // 12345678 -> 12340000 -> 00001234 + return ((dword >> 16) & 0x0000ffff); + } + + public static int LoWord (int dword) + { + // 12345678 -> 00005678 + return (dword & 0x0000ffff); + } + + public static IntPtr LParam (int hiword, int loword) + { + // results [hiword|loword] dword + // + return (IntPtr)((loword << 16) | (hiword & 0x0000FFFF)); + } +#endregion + + public enum Msg { + WM_CREATE = 0x0001, + WM_SETFOCUS = 0x0007, + WM_PAINT = 0X000F, + WM_CANCELMODE = 0x001F, + WM_SETCURSOR = 0x0020, + WM_CONTEXTMENU = 0x007B, + WM_NCHITTEST = 0x0084, + // + // AccessabilityObject + // + WM_GETOBJECT = 0x003D, + // + // Mouse input - Client area + // + WM_MOUSEFIRST = 0x0200, + WM_MOUSEMOVE = 0x0200, + WM_LBUTTONDOWN = 0x0201, + WM_LBUTTONUP = 0x0202, + WM_LBUTTONDBLCLK = 0x0203, + WM_RBUTTONDOWN = 0x0204, + WM_RBUTTONUP = 0x0205, + WM_RBUTTONDBLCLK = 0x0206, + WM_MBUTTONDOWN = 0x0207, + WM_MBUTTONUP = 0x0208, + WM_MBUTTONDBLCLK = 0x0209, + WM_MOUSEWHEEL = 0x020A, + WM_MOUSELAST = 0x020A, + WM_NCMOUSEHOVER = 0x02A0, + WM_MOUSEHOVER = 0x02A1, + WM_NCMOUSELEAVE = 0x02A2, + WM_MOUSELEAVE = 0x02A3, + // + // Mouse input - Non-client area + // + WM_NCMOUSEMOVE = 0x00A0, + WM_NCLBUTTONDOWN = 0x00A1, + WM_NCLBUTTONUP = 0x00A2, + WM_NCLBUTTONDBLCLK = 0x00A3, + WM_NCRBUTTONDOWN = 0x00A4, + WM_NCRBUTTONUP = 0x00A5, + WM_NCRBUTTONDBLCLK = 0x00A6, + WM_NCMBUTTONDOWN = 0x00A7, + WM_NCMBUTTONUP = 0x00A8, + WM_NCMBUTTONDBLCLK = 0x00A9, + // + // Keyboard input + // + WM_KEYFIRST = 0x0100, + WM_KEYDOWN = 0x0100, + WM_KEYUP = 0x0101, + WM_CHAR = 0x0102, + WM_DEADCHAR = 0x0103, + WM_SYSKEYDOWN = 0x0104, + WM_SYSKEYUP = 0x0105, + WM_SYS1CHAR = 0x0106, + WM_SYSDEADCHAR = 0x0107, + WM_KEYLAST = 0x0108, + // + // Scrolling + // + WM_HSCROLL = 0x0114, + WM_VSCROLL = 0x0115, + + // + // IME - International Text + // + WM_IME_SETCONTEXT = 0x0281, + WM_IME_NOTIFY = 0x0282, + WM_IME_CONTROL = 0x0283, + WM_IME_COMPOSITIONFULL = 0x0284, + WM_IME_SELECT = 0x0285, + WM_IME_CHAR = 0x0286, + WM_IME_REQUEST = 0x0288, + WM_IME_KEYDOWN = 0x0290, + WM_IME_KEYUP = 0x0291, + + // MWF Custom msgs + // + WM_MOUSE_ENTER = 0x0401, + } + } +} + diff --git a/source/ShiftUI/Design/ParentControlDesigner.cs b/source/ShiftUI/Design/ParentControlDesigner.cs new file mode 100644 index 0000000..0e906e7 --- /dev/null +++ b/source/ShiftUI/Design/ParentControlDesigner.cs @@ -0,0 +1,726 @@ +// +// ShiftUI.Design.ParentWidgetDesigner +// +// Authors: +// Ivan N. Zlatev (contact i-nZ.net) +// +// (C) 2006 Ivan N. Zlatev + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using ShiftUI; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Design; +using System.Collections; +using ShiftUI.Design.Behavior; + +namespace ShiftUI.Design + +{ + + public class ParentWidgetDesigner : WidgetDesigner + { + + public ParentWidgetDesigner () + { + } + + +#region Initialization + // Settings paths taken from the example at: + // http://msdn2.microsoft.com/en-us/library/system.componentmodel.design.idesigneroptionservice.aspx + // + public override void Initialize (IComponent component) + { + base.Initialize (component); + + this.Widget.AllowDrop = true; + + // Initialize the default values of the Design-Time properties. + // + _defaultDrawGrid = true; + _defaultSnapToGrid = true; + _defaultGridSize = new Size (8, 8); + + // If the parent Widget of the designed one has a ParentDesigner then inherit the values + // from it's designer. + // + if (this.Widget.Parent != null) { + ParentWidgetDesigner parentDesigner = GetParentWidgetDesignerOf (Widget.Parent); + if (parentDesigner != null) { + _defaultDrawGrid = (bool) GetValue (parentDesigner.Component, "DrawGrid"); + _defaultSnapToGrid = (bool) GetValue (parentDesigner.Component, "SnapToGrid"); + _defaultGridSize = (Size) GetValue (parentDesigner.Component, "GridSize"); + } + } + else { + // Else retrieve them through the IDesignerOptionService (if available) + // + IDesignerOptionService options = GetService (typeof (IDesignerOptionService)) as + IDesignerOptionService; + if (options != null) { + object value = null; + value = options.GetOptionValue (@"WindowsFormsDesigner\General", "DrawGrid"); + if (value is bool) + _defaultDrawGrid = (bool) value; + + value = options.GetOptionValue (@"WindowsFormsDesigner\General", "SnapToGrid"); + if (value is bool) + _defaultSnapToGrid = (bool) value; + + value = options.GetOptionValue (@"WindowsFormsDesigner\General", "GridSize"); + if (value is Size) + _defaultGridSize = (Size) value; + } + } + + IComponentChangeService componentChangeSvc = GetService (typeof (IComponentChangeService)) as IComponentChangeService; + if (componentChangeSvc != null) { + componentChangeSvc.ComponentRemoving += new ComponentEventHandler (OnComponentRemoving); + componentChangeSvc.ComponentRemoved += new ComponentEventHandler (OnComponentRemoved); + } + + // At the end set whatever we've managed to get + // + _drawGrid = _defaultDrawGrid; + _snapToGrid = _defaultSnapToGrid; + _gridSize = _defaultGridSize; + } + + protected override void Dispose (bool disposing) + { + if (disposing) { + EnableDragDrop (false); + OnMouseDragEnd (true); + } + base.Dispose (disposing); + } +#endregion + + +#region IToolboxService Related + + // This is the code that is executed when you drop a tool from the Toolbox in the designer. + // + + protected static void InvokeCreateTool (ParentWidgetDesigner toInvoke, ToolboxItem tool) + { + if (toInvoke != null) + toInvoke.CreateTool (tool); + } + + protected void CreateTool (ToolboxItem tool) + { + CreateToolCore (tool, DefaultWidgetLocation.X, DefaultWidgetLocation.Y, 0, 0, true, false); + } + + protected void CreateTool (ToolboxItem tool, Point location) + { + CreateToolCore (tool, location.X, location.Y, 0, 0, true, false); + } + + protected void CreateTool (ToolboxItem tool, Rectangle bounds) + { + CreateToolCore (tool, bounds.X, bounds.Y, bounds.Width, bounds.Width, true, true); + } + + // Creates a component from a ToolboxItem, sets its location and size if available and snaps it's + // location to the grid. + // + protected virtual IComponent[] CreateToolCore (ToolboxItem tool, int x, int y, int width, int height, + bool hasLocation, bool hasSize) + { + if (tool == null) + throw new ArgumentNullException ("tool"); + + IDesignerHost host = GetService (typeof (IDesignerHost)) as IDesignerHost; + DesignerTransaction transaction = host.CreateTransaction ("Create components in tool '" + tool.DisplayName + "'"); + IComponent[] components = tool.CreateComponents (host); + + foreach (IComponent component in components) + { + WidgetDesigner controlDesigner = host.GetDesigner (component) as WidgetDesigner; + if (controlDesigner == null) { // not a Widget, but e.g. a plain Component + continue; + } else if (!this.CanParent (controlDesigner)) { + host.DestroyComponent (component); + continue; + } + + Widget control = component as Widget; + if (control != null) { + this.Widget.SuspendLayout (); + // set parent instead of controls.Add so that it gets serialized for Undo/Redo + TypeDescriptor.GetProperties (control)["Parent"].SetValue (control, this.Widget); + this.Widget.SuspendLayout (); + + if (hasLocation) + base.SetValue (component, "Location", this.SnapPointToGrid (new Point (x, y))); + else + base.SetValue (component, "Location", this.SnapPointToGrid (this.DefaultWidgetLocation)); + + if (hasSize) + base.SetValue (component, "Size", new Size (width, height)); + + this.Widget.Refresh (); + } + } + ISelectionService selectionServ = this.GetService (typeof (ISelectionService)) as ISelectionService; + if (selectionServ != null) + selectionServ.SetSelectedComponents (components, SelectionTypes.Replace); + transaction.Commit (); + return components; + } + +#endregion + + +#region Drag and Drop + + // If the control is not already parented return true + // + public virtual bool CanParent (Widget control) + { + if (control != null) + return !control.Contains (this.Widget); + + return false; + } + + public virtual bool CanParent (WidgetDesigner designer) + { + return CanParent (designer.Widget); + } + + protected override void OnDragDrop (DragEventArgs e) + { + IUISelectionService selectionServ = this.GetService (typeof (IUISelectionService)) as IUISelectionService; + if (selectionServ != null) { + // once this is fired the parent control (parentcontroldesigner) will start getting dragover events. + // + Point location = this.SnapPointToGrid (this.Widget.PointToClient (new Point (e.X, e.Y))); + selectionServ.DragDrop (false, this.Widget, location.X, location.Y); + } + } + + protected override void OnDragEnter (DragEventArgs e) + { + this.Widget.Refresh (); + } + + protected override void OnDragLeave (EventArgs e) + { + this.Widget.Refresh (); + } + + protected override void OnDragOver (DragEventArgs e) + { + IUISelectionService selectionServ = this.GetService (typeof (IUISelectionService)) as IUISelectionService; + if (selectionServ != null) { + // once WidgetDesigner.MouseDragBegin is called this will start getting dragover events. + // + Point location = this.SnapPointToGrid (this.Widget.PointToClient (new Point (e.X, e.Y))); + selectionServ.DragOver (this.Widget, location.X, location.Y); + } + e.Effect = DragDropEffects.Move; + } +#endregion + + +#region Properties + // The default location where a control is placed, when added to the designer + // + protected virtual Point DefaultWidgetLocation { + get { return new Point (0, 0); } + } + + + protected override bool EnableDragRect { + get { return true; } + } +#endregion + +#region ComponentChange + + private void OnComponentRemoving (object sender, ComponentEventArgs args) + { + IComponentChangeService componentChangeSvc = GetService (typeof (IComponentChangeService)) as IComponentChangeService; + Widget control = args.Component as Widget; + if (control != null && control.Parent == this.Widget && componentChangeSvc != null) + componentChangeSvc.OnComponentChanging (args.Component, TypeDescriptor.GetProperties (args.Component)["Parent"]); + } + + private void OnComponentRemoved (object sender, ComponentEventArgs args) + { + IComponentChangeService componentChangeSvc = GetService (typeof (IComponentChangeService)) as IComponentChangeService; + Widget control = args.Component as Widget; + if (control != null && control.Parent == this.Widget && componentChangeSvc != null) { + control.Parent = null; + componentChangeSvc.OnComponentChanged (args.Component, + TypeDescriptor.GetProperties (args.Component)["Parent"], + this.Widget, null); + } + } +#endregion + +#region Design-Time Properties + + private bool _defaultDrawGrid; + private bool _defaultSnapToGrid; + private Size _defaultGridSize; + private bool _drawGrid; + private bool _snapToGrid; + private Size _gridSize; + + //This method adds the following design-time browsable properties: + // "DrawGrid", "SnapToGrid", and "GridSize". + // + protected override void PreFilterProperties (IDictionary properties) + { + base.PreFilterProperties (properties); + + properties["DrawGrid"] = TypeDescriptor.CreateProperty (typeof (ParentWidgetDesigner), + "DrawGrid", + typeof (bool), + new Attribute[] { + BrowsableAttribute.Yes, + DesignOnlyAttribute.Yes, + new DescriptionAttribute ( + "Indicates whether or not to draw the positioning grid."), + CategoryAttribute.Design + }); + + properties["SnapToGrid"] = TypeDescriptor.CreateProperty (typeof (ParentWidgetDesigner), + "SnapToGrid", + typeof (bool), + new Attribute[] { + BrowsableAttribute.Yes, + DesignOnlyAttribute.Yes, + new DescriptionAttribute ( + "Determines if controls should snap to the positioning grid."), + CategoryAttribute.Design + }); + + properties["GridSize"] = TypeDescriptor.CreateProperty (typeof (ParentWidgetDesigner), + "GridSize", + typeof (Size), + new Attribute[] { + BrowsableAttribute.Yes, + DesignOnlyAttribute.Yes, + new DescriptionAttribute ( + "Determines the size of the positioning grid."), + CategoryAttribute.Design + }); + + } + + + // Informs all children controls' ParentWidgetDesigners that the grid properties + // have changed and passes them + // + private void PopulateGridProperties () + { + // Widget.Invalidate (true) will redraw the control and it's children + // this will cause a WM_PAINT message to be send and the WidgetDesigenr will raise + // the OnPaintAdornments, where the grid drawing takes place. + // + // Note that this should be called *after* the grid properties have changed :-) + // + this.Widget.Invalidate (false); + + if (this.Widget != null) { + ParentWidgetDesigner designer = null; + foreach (Widget control in this.Widget.Widgets) { + designer = this.GetParentWidgetDesignerOf (control); + if (designer != null) + designer.OnParentGridPropertiesChanged (this); + } + } + } + + // Called by the parent ParentWidgetDesigner when it is populating the grid-related + // design-time properties changes + // + private void OnParentGridPropertiesChanged (ParentWidgetDesigner parentDesigner) + { + SetValue (this.Component, "DrawGrid", (bool) GetValue (parentDesigner.Component, "DrawGrid")); + SetValue (this.Component, "SnapToGrid", (bool) GetValue (parentDesigner.Component, "SnapToGrid")); + SetValue (this.Component, "GridSize", (Size) GetValue (parentDesigner.Component, "GridSize")); + + // Set also the default values to be those, because we should + // match the parent ParentWidgetDesigner values. + // called recursivly, so I will rather go for slower, but no stack-overflowable code + // + _defaultDrawGrid = (bool) GetValue (parentDesigner.Component, "DrawGrid"); + _defaultSnapToGrid = (bool) GetValue (parentDesigner.Component, "SnapToGrid"); + _defaultGridSize = (Size) GetValue (parentDesigner.Component, "GridSize"); + + this.PopulateGridProperties (); + } + + + // Retrieves the ParentWidgetDesigner of the specified control if available, + // else returns null. + // + private ParentWidgetDesigner GetParentWidgetDesignerOf (Widget control) + { + if (control != null) { + IDesignerHost designerHost = GetService (typeof (IDesignerHost)) as IDesignerHost; + if (designerHost != null) { + ParentWidgetDesigner designer = null; + designer = designerHost.GetDesigner (this.Widget.Parent) as ParentWidgetDesigner; + if (designer != null) + return designer; + } + } + return null; + } + + protected virtual bool DrawGrid { + get { return _drawGrid; } + set { + _drawGrid = value; + + if (value == false) + SetValue (this.Component, "SnapToGrid", false); + + PopulateGridProperties (); + } + } + + private bool SnapToGrid { + get { return _snapToGrid; } + set { + _snapToGrid = value; + PopulateGridProperties (); + } + } + + protected Size GridSize { + get { return _gridSize; } + set { + _gridSize = value; + PopulateGridProperties (); + } + } + + // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconshouldpersistresetmethods.asp + // + // The ShouldSerializerPROPERTYNAME determines whether a property has changed from + // the default value and should get serialized. + // + // The ResetPROPERTYNAME resets the property to it's default value (used when + // one right clicks on a property in the property grid and clicks on "Reset". + // + + private bool ShouldSerializeDrawGrid () + { + return DrawGrid != _defaultDrawGrid; + } + + private void ResetDrawGrid () + { + this.DrawGrid = _defaultDrawGrid; + } + + private bool ShouldSerializeSnapToGrid () + { + return _drawGrid != _defaultDrawGrid; + } + + private void ResetSnapToGrid () + { + this.SnapToGrid = _defaultSnapToGrid; + } + + private bool ShouldSerializeGridSize () + { + return GridSize != _defaultGridSize; + } + + private void ResetGridSize () + { + this.GridSize = _defaultGridSize; + } +#endregion + + +#region Design-Time Mouse Drag and Drop + protected override void OnMouseDragBegin (int x, int y) + { + // do not call base here because the behaviour is specific for the WidgetDesgner (does IUISelectionService.DragBegin) + // + + IUISelectionService selectionServ = this.GetService (typeof (IUISelectionService)) as IUISelectionService; + if (selectionServ != null) { + // once WidgetDesigner.MouseDragBegin is fired this will start getting dragover events. + // + Point location = new Point (x, y); + IDesignerHost host = GetService (typeof (IDesignerHost)) as IDesignerHost; + if (base.MouseButtonDown == MouseButtons.Middle && host != null && host.RootComponent != this.Widget) { + location = this.Widget.Parent.PointToClient (this.Widget.PointToScreen (new Point (x, y))); + // I have to do this, because I get DragOver events fired for the control I am actually dragging + // + this.Widget.AllowDrop = false; + selectionServ.DragBegin (); + } + else { + selectionServ.MouseDragBegin (this.Widget, location.X, location.Y); + } + } + } + + protected override void OnMouseDragMove (int x, int y) + { + IUISelectionService selectionServ = this.GetService (typeof (IUISelectionService)) as IUISelectionService; + if (selectionServ != null) { + Point location = new Point (x, y); + if (!selectionServ.SelectionInProgress) + location = this.SnapPointToGrid (new Point (x, y)); + + selectionServ.MouseDragMove (location.X, location.Y); + } + } + + protected override void OnMouseDragEnd (bool cancel) + { + IUISelectionService selectionServ = this.GetService (typeof (IUISelectionService)) as IUISelectionService; + if (selectionServ != null) { + // If there is a Toolbox component seleted then create it instead of finishing the selection + IToolboxService toolBoxService = this.GetService (typeof (IToolboxService)) as IToolboxService; + if (!cancel && toolBoxService != null && toolBoxService.GetSelectedToolboxItem () != null) { + if (selectionServ.SelectionInProgress) { + bool hasSize = selectionServ.SelectionBounds.Width > 0 && + selectionServ.SelectionBounds.Height > 0; + CreateToolCore (toolBoxService.GetSelectedToolboxItem (), + selectionServ.SelectionBounds.X, + selectionServ.SelectionBounds.Y, + selectionServ.SelectionBounds.Width, + selectionServ.SelectionBounds.Height, + true, hasSize); + toolBoxService.SelectedToolboxItemUsed (); + cancel = true; + } else if (!selectionServ.SelectionInProgress && + !selectionServ.ResizeInProgress && !selectionServ.DragDropInProgress){ + CreateTool (toolBoxService.GetSelectedToolboxItem (), _mouseDownPoint); + toolBoxService.SelectedToolboxItemUsed (); + cancel = true; + } + } + + if (selectionServ.SelectionInProgress || selectionServ.ResizeInProgress) + selectionServ.MouseDragEnd (cancel); + } + } + + protected override void OnDragComplete (DragEventArgs de) + { + base.OnDragComplete (de); + } + + Point _mouseDownPoint = Point.Empty; + + internal override void OnMouseDown (int x, int y) + { + _mouseDownPoint.X = x; + _mouseDownPoint.Y = y; + base.OnMouseDown (x, y); + } + + internal override void OnMouseUp () + { + base.OnMouseUp (); + if (!this.Widget.AllowDrop) // check MouseDragBegin for the reason of having this + this.Widget.AllowDrop = true; + _mouseDownPoint = Point.Empty; + } + + internal override void OnMouseMove (int x, int y) + { + IUISelectionService uiSelection = this.GetService (typeof (IUISelectionService)) as IUISelectionService; + if (uiSelection != null) + uiSelection.SetCursor (x, y); + + base.OnMouseMove (x, y); + } + + // Align the point to the grid + // + private Point SnapPointToGrid (Point location) + { + Rectangle gridSurface = this.Widget.Bounds; + Size gridSize = (Size)GetValue (this.Component, "GridSize"); + + if ((bool)GetValue (this.Component, "SnapToGrid")) { + int x = location.X + (gridSize.Width - (location.X % gridSize.Width)); + if (x > gridSurface.Width) + x = gridSurface.Width - gridSize.Width; + + location.X = x; + + int y = location.Y + (gridSize.Height - (location.Y % gridSize.Height)); + if (y > gridSurface.Height) + y = gridSurface.Height - gridSize.Height; + + location.Y = y; + } + return location; + } + +#endregion + + + #region WndProc and Misc Message Handlers + + protected override void OnSetCursor () + { + if (this.Widget != null) { + IToolboxService tbService = GetService (typeof (IToolboxService)) as IToolboxService; + if (tbService != null) + tbService.SetCursor (); + else + base.OnSetCursor (); + } + } + + // Draws the design-time grid if DrawGrid == true + // + protected override void OnPaintAdornments (PaintEventArgs pe) + { + base.OnPaintAdornments (pe); + + bool drawGrid; + Size gridSize; + + // in case WM_PAINT is received before the IDesignerFilter is invoked to add + // those properties. + try { + drawGrid = (bool)GetValue (this.Component, "DrawGrid"); + } catch { + drawGrid = this.DrawGrid; + } + try { + gridSize = (Size)GetValue (this.Component, "GridSize"); + } catch { + gridSize = this.GridSize; + } + + if (drawGrid) { + GraphicsState state = pe.Graphics.Save (); + pe.Graphics.TranslateTransform (this.Widget.ClientRectangle.X, + this.Widget.ClientRectangle.Y); + WidgetPaint.DrawGrid (pe.Graphics, this.Widget.ClientRectangle, gridSize, this.Widget.BackColor); + pe.Graphics.Restore (state); + } + + IUISelectionService selection = this.GetService (typeof (IUISelectionService)) as IUISelectionService; + if (selection != null) + selection.PaintAdornments (this.Widget, pe.Graphics); + } + +#endregion + + + protected Widget GetWidget (object component) + { + IComponent comp = component as IComponent; + + if (comp != null && comp.Site != null) { + IDesignerHost host = comp.Site.GetService (typeof (IDesignerHost)) as IDesignerHost; + if (host != null) { + WidgetDesigner designer = host.GetDesigner (comp) as WidgetDesigner; + if (designer != null) + return designer.Widget; + } + } + return null; + } + +#region NET_2_0 Stubs + [MonoTODO] + protected virtual bool AllowWidgetLasso { + get { return false; } + } + + [MonoTODO] + protected virtual bool AllowGenericDragBox { + get { return false; } + } + + [MonoTODO] + protected internal virtual bool AllowSetChildIndexOnDrop { + get { return false; } + } + + [MonoTODO] + public override IList SnapLines { + get { return new object [0]; } + } + + [MonoTODO] + protected ToolboxItem MouseDragTool { + get { return null; } + } + + [MonoTODO] + public override void InitializeNewComponent (IDictionary defaultValues) + { + base.InitializeNewComponent (defaultValues); + } + + [MonoTODO] + protected void AddPaddingSnapLines (ref ArrayList snapLines) + { + throw new NotImplementedException (); + } + + [MonoTODO] + protected virtual Widget GetParentForComponent (IComponent component) + { + throw new NotImplementedException (); + } + + [MonoTODO] + protected override WidgetBodyGlyph GetWidgetGlyph (GlyphSelectionType selectionType) + { + return base.GetWidgetGlyph (selectionType); + } + + [MonoTODO] + public override GlyphCollection GetGlyphs (GlyphSelectionType selectionType) + { + return base.GetGlyphs (selectionType); + } + + [MonoTODO] + protected Rectangle GetUpdatedRect (Rectangle originalRect, Rectangle dragRect, bool updateSize) + { + throw new NotImplementedException (); + } +#endregion + + } +} diff --git a/source/ShiftUI/Design/PropertyTab.cs b/source/ShiftUI/Design/PropertyTab.cs new file mode 100644 index 0000000..bb40e11 --- /dev/null +++ b/source/ShiftUI/Design/PropertyTab.cs @@ -0,0 +1,102 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: Marek Safar (marek.safar@seznam.cz) +// + +// COMPLETE + +using System.Drawing; +using System.ComponentModel; +using System; + +namespace ShiftUI.Design +{ + public abstract class PropertyTab: IExtenderProvider + { + Bitmap bitmap; + object[] components; + + protected PropertyTab () {} + + ~PropertyTab () + { + Dispose (false); + } + + public virtual Bitmap Bitmap { + get { + if (bitmap == null) { + Type t = base.GetType(); + bitmap = new Bitmap (t, t.Name + ".bmp"); + } + return bitmap; + } + } + + public virtual object[] Components { + get { return components; } + set { components = value; } + } + + public virtual string HelpKeyword { + get { return TabName; } + } + + public abstract string TabName { get; } + + public virtual bool CanExtend (object extendee) + { + return true; + } + + public virtual void Dispose() + { + Dispose (true); + GC.SuppressFinalize (this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing && bitmap != null) { + bitmap.Dispose (); + bitmap = null; + } + } + + public virtual PropertyDescriptor GetDefaultProperty (object component) + { + return TypeDescriptor.GetDefaultProperty(component); + } + + public virtual PropertyDescriptorCollection GetProperties (object component) + { + return GetProperties (component, null); + } + + public abstract PropertyDescriptorCollection GetProperties (object component, Attribute[] attributes); + + public virtual PropertyDescriptorCollection GetProperties (ITypeDescriptorContext context, object component, Attribute[] attributes) + { + return GetProperties (component, attributes); + } + } +} diff --git a/source/ShiftUI/Design/ScrollableControlDesigner.cs b/source/ShiftUI/Design/ScrollableControlDesigner.cs new file mode 100644 index 0000000..fb49f9a --- /dev/null +++ b/source/ShiftUI/Design/ScrollableControlDesigner.cs @@ -0,0 +1,83 @@ +// +// ShiftUI.Design.ScrollableWidgetDesigner +// +// Authors: +// Ivan N. Zlatev (contact i-nZ.net) +// +// (C) 2006-2007 Ivan N. Zlatev + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using ShiftUI; +using System.Drawing; +using System.Drawing.Design; +using System.Collections; + + + +namespace ShiftUI.Design +{ + + public class ScrollableWidgetDesigner : ParentWidgetDesigner + { + + public ScrollableWidgetDesigner () + { + } + + private const int HTHSCROLL = 6; + private const int HTVSCROLL = 7; + + protected override bool GetHitTest (Point point) + { + if (base.GetHitTest (point)) { + return true; + } + + // Check if the user has clicked on the scroll bars and forward the message to + // the ScrollableWidget. (Don't filter out the scrolling.). Keep in mind that scrollbars + // will be shown only if ScrollableWidget.AutoScroll = true + // + if (this.Widget is ScrollableWidget && ((ScrollableWidget)Widget).AutoScroll) { + int hitTestResult = (int) Native.SendMessage (this.Widget.Handle, + Native.Msg.WM_NCHITTEST, + IntPtr.Zero, + (IntPtr) Native.LParam (point.X, point.Y)); + if (hitTestResult == HTHSCROLL || hitTestResult == HTVSCROLL) + return true; + } + return false; + } + + + protected override void WndProc (ref Message m) + { + base.WndProc (ref m); + if (m.Msg == (int)Native.Msg.WM_HSCROLL || m.Msg == (int)Native.Msg.WM_VSCROLL) + this.DefWndProc (ref m); + } + } +} diff --git a/source/ShiftUI/Design/SelectionFrame.cs b/source/ShiftUI/Design/SelectionFrame.cs new file mode 100644 index 0000000..a3c092d --- /dev/null +++ b/source/ShiftUI/Design/SelectionFrame.cs @@ -0,0 +1,481 @@ +// +// ShiftUI.Design.SelectionFrame +// +// Authors: +// Ivan N. Zlatev (contact i-nZ.net) +// +// (C) 2006-2007 Ivan N. Zlatev + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Drawing.Drawing2D; +using ShiftUI; + + +namespace ShiftUI.Design +{ + // This is not a control! + // + internal class SelectionFrame + { + + public SelectionFrame (Widget control) + { + if (control == null) + throw new ArgumentNullException ("control"); + + _control = control; + } + + + private Rectangle _bounds; + private Widget _control; + private Rectangle[] _handles = new Rectangle[8]; + private GrabHandle _handle = GrabHandle.None; + private const int BORDER_SIZE = 7; + + +#region Properties + private enum GrabHandle { + None = -1, + TopLeft = 0, + TopMiddle, + TopRight, + Right, + BottomRight, + BottomMiddle, + BottomLeft, + Left, + Border // the border surrounding the control. + } + + public Rectangle Bounds { + get { + _bounds.X = _control.Location.X - BORDER_SIZE; + _bounds.Y = _control.Location.Y - BORDER_SIZE; + _bounds.Width = _control.Width + BORDER_SIZE *2; + _bounds.Height = _control.Height + BORDER_SIZE *2; + + return _bounds; + } + set { + _bounds = value; + _control.Bounds = _bounds; + } + } + + private SelectionRules SelectionRules { + get { + SelectionRules result = SelectionRules.AllSizeable; + + if (_control.Site != null) { + IDesignerHost host = _control.Site.GetService (typeof (IDesignerHost)) as IDesignerHost; + if (host != null) { + WidgetDesigner designer = host.GetDesigner (_control) as WidgetDesigner; + if (designer != null) + result = designer.SelectionRules; + } + } + + return result; + } + } + + public Widget Widget { + get { return _control; } + set { + if (value != null) + _control = value; + } + } + + public Widget Parent { + get { + if (_control.Parent == null) + return _control; + else + return _control.Parent; + } + } + + private GrabHandle GrabHandleSelected { + get { return _handle; } + set { _handle = value; } + } + + private bool PrimarySelection{ + get { + bool result = false; + if (this.Widget != null && this.Widget.Site != null) { + ISelectionService selection = this.Widget.Site.GetService (typeof (ISelectionService)) as ISelectionService; + if (selection != null && selection.PrimarySelection == this.Widget) + result = true; + } + return result; + } + } +#endregion + + +#region Drawing + public void OnPaint (Graphics gfx) + { + DrawFrame (gfx); + DrawGrabHandles (gfx); + } + + private void DrawGrabHandles (Graphics gfx) + { + GraphicsState state = gfx.Save(); + gfx.TranslateTransform (this.Bounds.X, this.Bounds.Y); + + for (int i = 0; i < _handles.Length; i++) { + _handles[i].Width = BORDER_SIZE; + _handles[i].Height = BORDER_SIZE; + } + + SelectionRules rules = this.SelectionRules; + bool primarySelection = this.PrimarySelection; + bool enabled = false; + + _handles[(int) GrabHandle.TopLeft].Location = new Point (0,0); + if (this.CheckSelectionRules (rules, SelectionRules.TopSizeable | SelectionRules.LeftSizeable)) + enabled = true; + + WidgetPaint.DrawGrabHandle (gfx, _handles[(int)GrabHandle.TopLeft], primarySelection, enabled); + enabled = false; + + _handles[(int) GrabHandle.TopMiddle].Location = new Point ((this.Bounds.Width - BORDER_SIZE) / 2, 0); + if (this.CheckSelectionRules (rules, SelectionRules.TopSizeable)) + enabled = true; + + WidgetPaint.DrawGrabHandle (gfx, _handles[(int)GrabHandle.TopMiddle], primarySelection, enabled); + enabled = false; + + _handles[(int) GrabHandle.TopRight].Location = new Point (this.Bounds.Width - BORDER_SIZE, 0); + if (this.CheckSelectionRules (rules, SelectionRules.TopSizeable | SelectionRules.RightSizeable)) + enabled = true; + + WidgetPaint.DrawGrabHandle (gfx, _handles[(int)GrabHandle.TopRight], primarySelection, enabled); + enabled = false; + + _handles[(int) GrabHandle.Right].Location = new Point (this.Bounds.Width - BORDER_SIZE, + (this.Bounds.Height - BORDER_SIZE) / 2); + if (this.CheckSelectionRules (rules, SelectionRules.RightSizeable)) + enabled = true; + + WidgetPaint.DrawGrabHandle (gfx, _handles[(int)GrabHandle.Right], primarySelection, enabled); + enabled = false; + + _handles[(int) GrabHandle.BottomRight].Location = new Point (this.Bounds.Width - BORDER_SIZE, + this.Bounds.Height - BORDER_SIZE); + if (this.CheckSelectionRules (rules, SelectionRules.BottomSizeable | SelectionRules.RightSizeable)) + enabled = true; + + WidgetPaint.DrawGrabHandle (gfx, _handles[(int)GrabHandle.BottomRight], primarySelection, enabled); + enabled = false; + + _handles[(int) GrabHandle.BottomMiddle].Location = new Point ((this.Bounds.Width - BORDER_SIZE) / 2, + this.Bounds.Height - BORDER_SIZE); + if (this.CheckSelectionRules (rules, SelectionRules.BottomSizeable)) + enabled = true; + + WidgetPaint.DrawGrabHandle (gfx, _handles[(int)GrabHandle.BottomMiddle], primarySelection, enabled); + enabled = false; + + _handles[(int) GrabHandle.BottomLeft].Location = new Point (0, this.Bounds.Height - BORDER_SIZE); + if (this.CheckSelectionRules (rules, SelectionRules.BottomSizeable | SelectionRules.LeftSizeable)) + enabled = true; + + WidgetPaint.DrawGrabHandle (gfx, _handles[(int)GrabHandle.BottomLeft], primarySelection, enabled); + enabled = false; + + _handles[(int) GrabHandle.Left].Location = new Point (0, (this.Bounds.Height - BORDER_SIZE) / 2); + if (this.CheckSelectionRules (rules, SelectionRules.LeftSizeable)) + enabled = true; + + WidgetPaint.DrawGrabHandle (gfx, _handles[(int)GrabHandle.Left], primarySelection, enabled); + gfx.Restore (state); + } + + protected void DrawFrame (Graphics gfx) + { + Color negativeColor = Color.FromArgb ((byte)~(_control.Parent.BackColor.R), + (byte)~(_control.Parent.BackColor.G), + (byte)~(_control.Parent.BackColor.B)); + Pen pen = new Pen (new HatchBrush (HatchStyle.Percent30, negativeColor, Color.FromArgb (0)), BORDER_SIZE); + gfx.DrawRectangle (pen, this.Widget.Bounds); + } +#endregion + + +#region Dragging + private bool _resizing = false; + + + public bool SetCursor (int x, int y) + { + bool modified = false; + + if (!_resizing) { + GrabHandle handle = PointToGrabHandle (this.PointToClient (Widget.MousePosition)); + if (handle != GrabHandle.None) + modified = true; + + if (handle == GrabHandle.TopLeft) + Cursor.Current = Cursors.SizeNWSE; + else if (handle == GrabHandle.TopMiddle) + Cursor.Current = Cursors.SizeNS; + else if (handle == GrabHandle.TopRight) + Cursor.Current = Cursors.SizeNESW; + else if (handle == GrabHandle.Right) + Cursor.Current = Cursors.SizeWE; + else if (handle == GrabHandle.BottomRight) + Cursor.Current = Cursors.SizeNWSE; + else if (handle == GrabHandle.BottomMiddle) + Cursor.Current = Cursors.SizeNS; + else if (handle == GrabHandle.BottomLeft) + Cursor.Current = Cursors.SizeNESW; + else if (handle == GrabHandle.Left) + Cursor.Current = Cursors.SizeWE; + else + Cursor.Current = Cursors.Default; + } + return modified; + } + + // container coordinates + public void ResizeBegin (int x, int y) + { + this.GrabHandleSelected = PointToGrabHandle (this.PointToClient (this.Parent.PointToScreen (new Point (x, y)))); + + if (this.GrabHandleSelected != GrabHandle.None) + _resizing = true; + } + + private bool CheckSelectionRules (SelectionRules rules, SelectionRules toCheck) + { + return ((rules & toCheck) == toCheck); + } + + // container coordinates returns deltaBounds + public Rectangle ResizeContinue (int x, int y) + { + //Console.WriteLine ("ResizeContinue: " + x + " : " + y); + //Console.WriteLine ("GrabHandleSelected: " + GrabHandleSelected); + + Rectangle bounds = (Rectangle)TypeDescriptor.GetProperties (_control)["Bounds"].GetValue (_control); + Rectangle deltaBounds = bounds; + Point pointerLocation = new Point (x, y); + SelectionRules rules = this.SelectionRules; + int top, height, left, width = 0; + + if (_resizing && this.GrabHandleSelected != GrabHandle.None && rules != SelectionRules.Locked) { + if (this.GrabHandleSelected == GrabHandle.TopLeft && + CheckSelectionRules (rules, SelectionRules.LeftSizeable | SelectionRules.TopSizeable)) { + + top = _control.Top; + height = _control.Height; + left = _control.Left; + width = _control.Width; + + if (pointerLocation.Y < _control.Bottom) { + top = pointerLocation.Y; + height = _control.Bottom - pointerLocation.Y; + } + if (pointerLocation.X < _control.Right) { + left = pointerLocation.X; + width = _control.Right - pointerLocation.X; + bounds = new Rectangle (left, top, width, height); + } + } + else if (this.GrabHandleSelected == GrabHandle.TopRight && + CheckSelectionRules (rules, SelectionRules.TopSizeable | SelectionRules.RightSizeable)) { + + top = _control.Top; + height = _control.Height; + width = _control.Width; + + if (pointerLocation.Y < _control.Bottom) { + top = pointerLocation.Y; + height = _control.Bottom - pointerLocation.Y; + } + width = pointerLocation.X - _control.Left; + bounds = new Rectangle (_control.Left, top, width, height); + } + else if (GrabHandleSelected == GrabHandle.TopMiddle && CheckSelectionRules (rules, SelectionRules.TopSizeable)) { + if (pointerLocation.Y < _control.Bottom) { + top = pointerLocation.Y; + height = _control.Bottom - pointerLocation.Y; + bounds = new Rectangle (_control.Left, top, _control.Width, height); + } + } + else if (this.GrabHandleSelected == GrabHandle.Right && CheckSelectionRules (rules, SelectionRules.RightSizeable)) { + width = pointerLocation.X - _control.Left; + bounds = new Rectangle (_control.Left, _control.Top, width, _control.Height); + } + else if (this.GrabHandleSelected == GrabHandle.BottomRight && + CheckSelectionRules (rules, SelectionRules.BottomSizeable | SelectionRules.RightSizeable)) { + + width = pointerLocation.X - _control.Left; + height = pointerLocation.Y - _control.Top; + bounds = new Rectangle (_control.Left, _control.Top, width, height); + } + else if (GrabHandleSelected == GrabHandle.BottomMiddle && CheckSelectionRules (rules, SelectionRules.BottomSizeable)) { + height = pointerLocation.Y - _control.Top; + bounds = new Rectangle (_control.Left, _control.Top, _control.Width, height); + } + else if (GrabHandleSelected == GrabHandle.BottomLeft && + CheckSelectionRules (rules, SelectionRules.BottomSizeable | SelectionRules.LeftSizeable)) { + + height = _control.Height; + left = _control.Left; + width = _control.Width; + + if (pointerLocation.X < _control.Right) { + left = pointerLocation.X; + width = _control.Right - pointerLocation.X; + } + height = pointerLocation.Y - _control.Top; + bounds = new Rectangle (left, _control.Top, width, height); + } + else if (GrabHandleSelected == GrabHandle.Left && CheckSelectionRules (rules, SelectionRules.LeftSizeable)) { + if (pointerLocation.X < _control.Right) { + left = pointerLocation.X; + width = _control.Right - pointerLocation.X; + bounds = new Rectangle (left, _control.Top, width, _control.Height); + } + } + + //Console.WriteLine ("bounds: " + bounds.ToString ()); + TypeDescriptor.GetProperties (_control)["Bounds"].SetValue (_control, bounds); + + } + + this.Parent.Refresh (); + deltaBounds.X = bounds.X - deltaBounds.X; + deltaBounds.Y = bounds.Y - deltaBounds.Y; + deltaBounds.Height = bounds.Height - deltaBounds.Height; + deltaBounds.Width = bounds.Width - deltaBounds.Width; + return deltaBounds; + } + + + public void ResizeEnd (bool cancel) + { + this.GrabHandleSelected = GrabHandle.None; + _resizing = false; + } + + public void Resize (Rectangle deltaBounds) + { + SelectionRules rules = this.SelectionRules; + + if (this.CheckSelectionRules (rules, SelectionRules.Locked) || !this.CheckSelectionRules (rules, SelectionRules.Moveable)) + return; + + Rectangle bounds = (Rectangle)TypeDescriptor.GetProperties (_control)["Bounds"].GetValue (_control); + + if (CheckSelectionRules (rules, SelectionRules.LeftSizeable)) { + bounds.X += deltaBounds.X; + bounds.Width += deltaBounds.Width; + } + if (CheckSelectionRules (rules, SelectionRules.RightSizeable) && !CheckSelectionRules (rules, SelectionRules.LeftSizeable)) { + bounds.Y += deltaBounds.Y; + bounds.Width += deltaBounds.Width; + } + if (CheckSelectionRules (rules, SelectionRules.TopSizeable)) { + bounds.Y += deltaBounds.Y; + bounds.Height += deltaBounds.Height; + } + if (CheckSelectionRules (rules, SelectionRules.BottomSizeable) && !CheckSelectionRules (rules, SelectionRules.TopSizeable)) { + bounds.Height += deltaBounds.Height; + } + + TypeDescriptor.GetProperties (_control)["Bounds"].SetValue (_control, bounds); + } +#endregion + + +#region Utility methods + + public bool HitTest (int x, int y) + { + if (PointToGrabHandle (this.PointToClient (this.Parent.PointToScreen (new Point (x, y)))) != GrabHandle.None) + return true; + else + return false; + } + + private GrabHandle PointToGrabHandle (Point pointerLocation) + { + GrabHandle result = GrabHandle.None; + + if (IsCursorOnGrabHandle (pointerLocation, _handles[0])) + result = GrabHandle.TopLeft; + else if (IsCursorOnGrabHandle (pointerLocation, _handles[1])) + result = GrabHandle.TopMiddle; + else if (IsCursorOnGrabHandle (pointerLocation, _handles[2])) + result = GrabHandle.TopRight; + else if (IsCursorOnGrabHandle (pointerLocation, _handles[3])) + result = GrabHandle.Right; + else if (IsCursorOnGrabHandle (pointerLocation, _handles[4])) + result = GrabHandle.BottomRight; + else if (IsCursorOnGrabHandle (pointerLocation, _handles[5])) + result = GrabHandle.BottomMiddle; + else if (IsCursorOnGrabHandle (pointerLocation, _handles[6])) + result = GrabHandle.BottomLeft; + else if (IsCursorOnGrabHandle (pointerLocation, _handles[7])) + result = GrabHandle.Left; + else + result = GrabHandle.None; + + return result; + } + + private bool IsCursorOnGrabHandle (Point pointerLocation, Rectangle handleRectangle) + { + if (pointerLocation.X >= handleRectangle.X && + pointerLocation.X <= handleRectangle.X + handleRectangle.Width && + pointerLocation.Y >= handleRectangle.Y && + pointerLocation.Y <= handleRectangle.Y + handleRectangle.Height) { + return true; + } + return false; + } + + private Point PointToClient (Point screenPoint) + { + Point pointerLocation = this.Parent.PointToClient (screenPoint); + pointerLocation.X = pointerLocation.X - this.Bounds.X; + pointerLocation.Y = pointerLocation.Y - this.Bounds.Y; + return pointerLocation; + } +#endregion + + } +} diff --git a/source/ShiftUI/Design/SelectionRules.cs b/source/ShiftUI/Design/SelectionRules.cs new file mode 100644 index 0000000..84e5a41 --- /dev/null +++ b/source/ShiftUI/Design/SelectionRules.cs @@ -0,0 +1,47 @@ +// +// ShiftUI.Design.SelectionRules.cs +// +// Author: +// Gert Driesen (drieseng@users.sourceforge.net) +// (C) 2004 Ximian, Inc. http://www.ximian.com +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; + +namespace ShiftUI.Design +{ + [Flags] + public enum SelectionRules + { + AllSizeable = 15, + BottomSizeable = 2, + LeftSizeable = 4, + Locked = -2147483648, + Moveable = 268435456, + None = 0, + RightSizeable = 8, + TopSizeable = 1, + Visible = 1073741824 + } +} diff --git a/source/ShiftUI/Design/ToolStripItemDesignerAvailability.cs b/source/ShiftUI/Design/ToolStripItemDesignerAvailability.cs new file mode 100644 index 0000000..5452d15 --- /dev/null +++ b/source/ShiftUI/Design/ToolStripItemDesignerAvailability.cs @@ -0,0 +1,43 @@ +// +// ToolStripItemDesignerAvailability.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; + +namespace ShiftUI.Design +{ + [Flags] + public enum ToolStripItemDesignerAvailability + { + None = 0, + ToolStrip = 1, + MenuStrip = 2, + ContextMenuStrip = 4, + StatusStrip = 8, + All = 15 + } +} diff --git a/source/ShiftUI/Design/ToolStripItemDesignerAvailabilityAttribute.cs b/source/ShiftUI/Design/ToolStripItemDesignerAvailabilityAttribute.cs new file mode 100644 index 0000000..f5ca759 --- /dev/null +++ b/source/ShiftUI/Design/ToolStripItemDesignerAvailabilityAttribute.cs @@ -0,0 +1,81 @@ +// +// ToolStripItemDesignerAvailabilityAttribute.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Collections.Generic; +using System.Text; + +namespace ShiftUI.Design +{ + [AttributeUsage (AttributeTargets.Class)] + public sealed class ToolStripItemDesignerAvailabilityAttribute : Attribute + { + private ToolStripItemDesignerAvailability visibility; + public static readonly ToolStripItemDesignerAvailabilityAttribute Default = new ToolStripItemDesignerAvailabilityAttribute (); + + #region Public Constructors + public ToolStripItemDesignerAvailabilityAttribute () + : base () + { + this.visibility = ToolStripItemDesignerAvailability.None; + } + + public ToolStripItemDesignerAvailabilityAttribute (ToolStripItemDesignerAvailability visibility) + : base () + { + this.visibility = visibility; + } + #endregion + + #region Public Properties + public ToolStripItemDesignerAvailability ItemAdditionVisibility { + get { return this.visibility; } + } + #endregion + + #region Public Methods + public override bool Equals (object obj) + { + if (!(obj is ToolStripItemDesignerAvailabilityAttribute)) + return false; + + return this.ItemAdditionVisibility == (obj as ToolStripItemDesignerAvailabilityAttribute).ItemAdditionVisibility; + } + + public override int GetHashCode () + { + return (int)this.visibility; + } + + public override bool IsDefaultAttribute () + { + return this.visibility == ToolStripItemDesignerAvailability.None; + } + #endregion + } +} diff --git a/source/ShiftUI/Design/UISelectionService.cs b/source/ShiftUI/Design/UISelectionService.cs new file mode 100644 index 0000000..78a722b --- /dev/null +++ b/source/ShiftUI/Design/UISelectionService.cs @@ -0,0 +1,532 @@ +// +// ShiftUI.Design.UISelectionService +// +// Authors: +// Ivan N. Zlatev (contact i-nZ.net) +// +// (C) 2007 Ivan N. Zlatev + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Drawing.Drawing2D; +using ShiftUI; + +namespace ShiftUI.Design +{ + + internal class UISelectionService : IUISelectionService + { + + private IServiceProvider _serviceProvider; + private DesignerTransaction _transaction; + private ISelectionService _selectionService; + + public UISelectionService (IServiceProvider serviceProvider) + { + if (serviceProvider == null) + throw new ArgumentNullException ("serviceProvider"); + + _serviceProvider = serviceProvider; + _transaction = null; + + _selectionService = serviceProvider.GetService (typeof (ISelectionService)) as ISelectionService; + if (_selectionService == null) { + IServiceContainer serviceContainer = serviceProvider.GetService (typeof (IServiceContainer)) as IServiceContainer; + _selectionService = new UISelectionService (serviceContainer) as ISelectionService; + serviceContainer.AddService (typeof (ISelectionService), (ISelectionService) _selectionService); + } + + _selectionService.SelectionChanged += new EventHandler (OnSelectionChanged); + } + + private ISelectionService SelectionService { + get { return _selectionService; } + } + + private object GetService (Type service) + { + return _serviceProvider.GetService (service); + } + + public bool SelectionInProgress { + get { return _selecting; } + } + + public bool DragDropInProgress { + get { return _dragging; } + } + + public bool ResizeInProgress{ + get { return _resizing; } + } + + + public bool SetCursor (int x, int y) + { + bool modified = false; + // if moving mouse around - set cursor if mouse is hovering a selectionframes' grabhandles + // + SelectionFrame frame = GetSelectionFrameAt (x, y); + if (frame != null && frame.HitTest (x, y) && frame.SetCursor (x, y)) + modified = true; + + return modified; + } + + + public void MouseDragBegin (Widget container, int x, int y) + { + // * start resizing the selection frame + // * start selecting + // + SelectionFrame frame = GetSelectionFrameAt (x, y); + + if (frame != null && frame.HitTest (x, y)) { + this.SelectionService.SetSelectedComponents (new IComponent[] { frame.Widget }); + if (_transaction == null) { + IDesignerHost host = this.GetService (typeof (IDesignerHost)) as IDesignerHost; + _transaction = host.CreateTransaction ("Resize " + + (this.SelectionService.SelectionCount == 1 ? ((IComponent)this.SelectionService.PrimarySelection).Site.Name : "controls")); + } + this.ResizeBegin (x, y); + } + else { + SelectionBegin (container, x, y); + } + } + + public void MouseDragMove (int x, int y) + { + if (_selecting) + SelectionContinue (x, y); + else if (_resizing) + ResizeContinue (x, y); + } + + public void MouseDragEnd (bool cancel) + { + if (_selecting) + SelectionEnd (cancel); + else if (_resizing) { + ResizeEnd (cancel); + if (_transaction != null) { + if (cancel) + _transaction.Cancel (); + else + _transaction.Commit (); + _transaction = null; + } + } + + if (Cursor.Current != Cursors.Default) + Cursor.Current = Cursors.Default; + } + + +#region Dragging + private bool _dragging = false; + private Point _prevMousePosition; + private bool _firstMove = false; + + // container coordinates (primary selection's) + // + public void DragBegin () + { + // Console.WriteLine ("DragBegin"); + if (_transaction == null) { + IDesignerHost host = this.GetService (typeof (IDesignerHost)) as IDesignerHost; + _transaction = host.CreateTransaction ("Move " + + (this.SelectionService.SelectionCount == 1? ((IComponent)this.SelectionService.PrimarySelection).Site.Name : "controls")); + } + _dragging = true; + _firstMove = true; + if (this.SelectionService.PrimarySelection != null) + ((Widget)this.SelectionService.PrimarySelection).DoDragDrop (new WidgetDataObject ((Widget)this.SelectionService.PrimarySelection), DragDropEffects.All); + } + + // container cordinates + // + public void DragOver (Widget container, int x, int y) + { + // Console.WriteLine ("DragOver"); + if (_dragging) { + if (_firstMove) { + _prevMousePosition = new Point (x, y); + _firstMove = false; + } + else { + int dx = x - _prevMousePosition.X; + int dy = y - _prevMousePosition.Y; + MoveSelection (container, dx, dy); + _prevMousePosition = new Point (x, y); + + // Repaint everything >_< + // + IDesignerHost host = this.GetService (typeof (IDesignerHost)) as IDesignerHost; + if (host != null && host.RootComponent != null) + ((Widget)host.RootComponent).Refresh (); + //container.Refresh (); + } + } + } + + // container coordinates + // + public void DragDrop (bool cancel, Widget container, int x, int y) + { + // Console.WriteLine ("UISelectionService.DragDrop: in " + container.Site.Name); + if (_dragging) { + int dx = x - _prevMousePosition.X; + int dy = y - _prevMousePosition.Y; + + MoveSelection (container, dx, dy); + _dragging = false; + + // Repaint everything + // + IDesignerHost host = this.GetService (typeof (IDesignerHost)) as IDesignerHost; + if (host != null && host.RootComponent != null) + ((Widget)host.RootComponent).Refresh (); + // Send mouse up message to the primary selection + // Else for parentcontroldesigner there is no mouseup event and it doesn't set allow drop back to false + // + Native.SendMessage (((Widget)this.SelectionService.PrimarySelection).Handle, Native.Msg.WM_LBUTTONUP, (IntPtr) 0, (IntPtr) 0); + if (_transaction != null) { + if (cancel) + _transaction.Cancel (); + else + _transaction.Commit (); + _transaction = null; + } + } + } + + private void MoveSelection (Widget container, int dx, int dy) + { + bool reparent = false; + Widget oldParent = null; + + if (((Widget)this.SelectionService.PrimarySelection).Parent != container && !this.SelectionService.GetComponentSelected (container)) { + reparent = true; + oldParent = ((Widget)this.SelectionService.PrimarySelection).Parent; + } + + // FIXME: Should check selectionstyle per control to determine if it's locked... + // if locked -> don't move + // + ICollection selection = this.SelectionService.GetSelectedComponents (); + foreach (Component component in selection) { + Widget control = component as Widget; + if (reparent) + TypeDescriptor.GetProperties (control)["Parent"].SetValue (control, container); + + PropertyDescriptor property = TypeDescriptor.GetProperties (control)["Location"]; + Point location = (Point) property.GetValue (control); + location.X += dx; + location.Y += dy; + property.SetValue (control, location); + } + + if (reparent) { + oldParent.Invalidate (false); + oldParent.Update (); + } + } +#endregion + + +#region Selection + + private bool _selecting = false; + private Widget _selectionContainer = null; + private Point _initialMousePosition; + private Rectangle _selectionRectangle; + // XXX + private ArrayList _selectionFrames = new ArrayList (); + + + public Rectangle SelectionBounds { + get { return _selectionRectangle; } + } + + // container coordinates + // + private void SelectionBegin (Widget container, int x, int y) + { + // Console.WriteLine ("SelectionBegin"); + _selecting = true; + _selectionContainer = container; + _prevMousePosition = new Point (x, y); + _initialMousePosition = _prevMousePosition; + _selectionRectangle = new Rectangle (x , y, 0, 0); + } + + private void SelectionContinue (int x, int y) + { + // Console.WriteLine ("SelectionContinue"); + if (_selecting) { + // right to right + // + if (x > _selectionRectangle.Right) { + _selectionRectangle.Width = x - _selectionRectangle.X; + } + // right to left + else if (x > _selectionRectangle.X && x < _selectionRectangle.Right && + x < _prevMousePosition.X) { + + _selectionRectangle.Width = x - _selectionRectangle.X; + } + // left to left - f + else if (x < _selectionRectangle.X) { + + // hasn't flipped + if (_prevMousePosition.X > _selectionRectangle.X) { + _selectionRectangle.X = _initialMousePosition.X; + _selectionRectangle.Width = 0; + } + else { + _selectionRectangle.Width += _selectionRectangle.X - x; + _selectionRectangle.X = x; + } + } + // left to right - f + else if (x > _selectionRectangle.X && x < _selectionRectangle.Right && + x > _prevMousePosition.X) { + + if (_prevMousePosition.X < _selectionRectangle.X) { + _selectionRectangle.X = _initialMousePosition.X; + _selectionRectangle.Width = 0; + } + else { + _selectionRectangle.Width -= x - _selectionRectangle.X; + _selectionRectangle.X = x; + } + } + + + if (y > _selectionRectangle.Bottom) { + _selectionRectangle.Height = y - _selectionRectangle.Y; + } + else if (y > _selectionRectangle.Y && y < _selectionRectangle.Bottom && + y < _prevMousePosition.Y) { + + _selectionRectangle.Height = y - _selectionRectangle.Y; + + } + else if (y < _selectionRectangle.Y) { + if (_prevMousePosition.Y > _selectionRectangle.Y) { + _selectionRectangle.Y = _initialMousePosition.Y; + _selectionRectangle.Height = 0; + } + else { + _selectionRectangle.Height += _selectionRectangle.Y - y; + _selectionRectangle.Y = y; + } + } + else if (y > _selectionRectangle.Y && y < _selectionRectangle.Bottom && + y > _prevMousePosition.Y) { + + if (_prevMousePosition.Y < _selectionRectangle.Y) { + _selectionRectangle.Y = _initialMousePosition.Y; + _selectionRectangle.Height = 0; + } + else { + _selectionRectangle.Height -= y - _selectionRectangle.Y; + _selectionRectangle.Y = y; + } + } + + _prevMousePosition.X = x; + _prevMousePosition.Y = y; + + _selectionContainer.Refresh (); + } + } + + private void SelectionEnd (bool cancel) + { + // Console.WriteLine ("SelectionEnd"); + _selecting = false; + ICollection selectedWidgets = GetWidgetsIn (_selectionRectangle); + // do not change selection if nothing has changed + // + if (selectedWidgets.Count != 0) + this.SelectionService.SetSelectedComponents (selectedWidgets, SelectionTypes.Replace); + + _selectionContainer.Refresh (); + } +#endregion + + +#region Resizing + private SelectionFrame _selectionFrame; + private bool _resizing = false; + + private void ResizeBegin (int x, int y) + { + // Console.WriteLine ("ResizeBegin"); + _resizing = true; + _selectionFrame = this.GetSelectionFrameAt (x, y); + _selectionFrame.ResizeBegin (x, y); + } + + private void ResizeContinue (int x, int y) + { + // Console.WriteLine ("ResizeContinue"); + Rectangle deltaBounds = _selectionFrame.ResizeContinue (x, y); + ICollection selection = this.SelectionService.GetSelectedComponents (); + + foreach (IComponent component in selection) { + if (component is Widget) { + SelectionFrame frame = GetSelectionFrameFor ((Widget)component); + if (frame != _selectionFrame) + frame.Resize (deltaBounds); + } + } + + } + + private void ResizeEnd (bool cancel) + { + // Console.WriteLine ("ResizeEnd"); + _selectionFrame.ResizeEnd (cancel); + _resizing = false; + } + + + private SelectionFrame GetSelectionFrameAt (int x, int y) + { + SelectionFrame result = null; + + foreach (SelectionFrame frame in _selectionFrames) { + if (frame.Bounds.Contains (new Point (x, y))) { + result = frame; + break; + } + } + + return result; + } + + private SelectionFrame GetSelectionFrameFor (Widget control) + { + foreach (SelectionFrame frame in _selectionFrames) { + if (control == frame.Widget) + return frame; + } + return null; + } +#endregion + + public bool AdornmentsHitTest (Widget control, int x, int y) + { + SelectionFrame frame = GetSelectionFrameAt (x, y); + if (frame != null) + return frame.HitTest (x, y); + + return false; + } + + // This method is called by all ParentWidgetDesigner.OnPaintAdornments. + // Selection frames are drawn in the parent container of the primary selection + // selection rectangle is drawn in the primary selection + // + public void PaintAdornments (Widget container, Graphics gfx) + { + IDesignerHost host = this.GetService (typeof (IDesignerHost)) as IDesignerHost; + + if (host == null || !(this.SelectionService.PrimarySelection is Widget)) + return; + + if ((Widget)this.SelectionService.PrimarySelection == container) { + if (_selecting) { + Color negativeColor = Color.FromArgb ((byte)~(_selectionContainer.BackColor.R), + (byte)~(_selectionContainer.BackColor.G), + (byte)~(_selectionContainer.BackColor.B)); + DrawSelectionRectangle (gfx, _selectionRectangle, negativeColor); + } + } + else if (((Widget)this.SelectionService.PrimarySelection).Parent == container) { + foreach (SelectionFrame frame in _selectionFrames) + frame.OnPaint (gfx); + } + } + + + private void DrawSelectionRectangle (Graphics gfx, Rectangle frame, Color color) + { + Pen pen = new Pen (color); + pen.DashStyle = DashStyle.Dash; + gfx.DrawRectangle (pen, frame); + } + + + private void OnSelectionChanged (object sender, EventArgs args) + { + ICollection selection = this.SelectionService.GetSelectedComponents (); + + if (_selectionFrames.Count == 0) { + foreach (Component component in selection) { + _selectionFrames.Add (new SelectionFrame ((Widget) component)); + } // this code should get executed only once! (when initial primary selection is set) + } else { + int i = 0; + foreach (Component component in selection) { + if (i >= _selectionFrames.Count) + _selectionFrames.Add (new SelectionFrame ((Widget) component)); + else + ((SelectionFrame)_selectionFrames[i]).Widget = (Widget) component; + i++; + } + if (i < _selectionFrames.Count) + _selectionFrames.RemoveRange (i, _selectionFrames.Count - i); + } + // Refresh the whole design surface (including the view) + // + IDesignerHost host = this.GetService (typeof (IDesignerHost)) as IDesignerHost; + Widget root = host.RootComponent as Widget; + if (root != null) { + if (root.Parent != null) + root.Parent.Refresh (); + else + root.Refresh (); + } + } + + private ICollection GetWidgetsIn (Rectangle rect) + { + ArrayList selectedWidgets = new ArrayList (); + + foreach (Widget control in _selectionContainer.Widgets) { + if (rect.Contains (control.Bounds) || rect.IntersectsWith (control.Bounds)) + selectedWidgets.Add (control); + } + return selectedWidgets; + } + + } +} diff --git a/source/ShiftUI/Design/WindowsFormsComponentEditor.cs b/source/ShiftUI/Design/WindowsFormsComponentEditor.cs new file mode 100644 index 0000000..9dbfc7a --- /dev/null +++ b/source/ShiftUI/Design/WindowsFormsComponentEditor.cs @@ -0,0 +1,65 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Andreas Nahr (ClassDevelopment@A-SoftTech.com) +// + +using System.ComponentModel; +using System; + +namespace ShiftUI.Design +{ + public abstract class WindowsFormsComponentEditor : ComponentEditor + { + protected WindowsFormsComponentEditor () + { + } + + public override bool EditComponent (ITypeDescriptorContext context, object component) + { + return EditComponent (context, component, null); + } + + public virtual bool EditComponent (ITypeDescriptorContext context, object component, IWin32Window owner) + { + ComponentEditorForm f = new ComponentEditorForm (component, GetComponentEditorPages ()); + if (f.ShowForm (owner, GetInitialComponentEditorPageIndex ()) == DialogResult.OK) + return true; + return false; + } + + public bool EditComponent (object component, IWin32Window owner) + { + return EditComponent (null, component, owner); + } + + protected virtual Type[] GetComponentEditorPages () + { + return null; + } + + protected virtual int GetInitialComponentEditorPageIndex () + { + return 0; + } + } +} diff --git a/source/ShiftUI/Design/WndProcRouter.cs b/source/ShiftUI/Design/WndProcRouter.cs new file mode 100644 index 0000000..83c3f1d --- /dev/null +++ b/source/ShiftUI/Design/WndProcRouter.cs @@ -0,0 +1,117 @@ +// +// ShiftUI.Design.WndProcRouter +// +// Authors: +// Ivan N. Zlatev (contact i-nZ.net) +// +// (C) 2006-2007 Ivan N. Zlatev + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using ShiftUI; +using System.Drawing; +using System.Drawing.Design; +using System.Collections; + + // Automatically reroutes Messages to the designer + // + +namespace ShiftUI.Design +{ + + internal class WndProcRouter : IWindowTarget, IDisposable + { + private IWindowTarget _oldTarget; + private IMessageReceiver _receiver; + private Widget _control; + + public WndProcRouter (Widget control, IMessageReceiver receiver) + { + if (control == null) + throw new ArgumentNullException ("control"); + if (receiver == null) + throw new ArgumentNullException ("receiver"); + + _oldTarget = control.WindowTarget; + _control = control; + _receiver = receiver; + } + + public Widget Widget { + get { return _control; } + } + + public IWindowTarget OldWindowTarget { + get { return _oldTarget; } + } + + // Route the message to the control + // + public void ToWidget (ref Message m) + { + //Console.WriteLine ("Widget: " + ((Native.Msg)m.Msg).ToString ()); + if (_oldTarget != null) + _oldTarget.OnMessage (ref m); + } + + public void ToSystem (ref Message m) + { + //Console.WriteLine ("System: " + ((Native.Msg)m.Msg).ToString ()); + Native.DefWndProc (ref m); + } + + // Just pass it to the old IWindowTarget + // + void IWindowTarget.OnHandleChange (IntPtr newHandle) + { + if (_oldTarget != null) + _oldTarget.OnHandleChange (newHandle); + } + + // Route the msg to the designer if available, else to + // control itself. + // + void IWindowTarget.OnMessage (ref Message m) + { + //Console.WriteLine ("Message: " + ((Native.Msg)m.Msg).ToString ()); + if (_receiver != null) + _receiver.WndProc (ref m); + else + this.ToWidget (ref m); + } + + // Disposes and puts back the old IWindowTarget + // + public void Dispose () + { + if (_control != null) + _control.WindowTarget = _oldTarget; + + _control = null; + _oldTarget = null; + } + + } +} diff --git a/source/ShiftUI/Dialogs/StringArrayDialog.cs b/source/ShiftUI/Dialogs/StringArrayDialog.cs new file mode 100644 index 0000000..5f99ff8 --- /dev/null +++ b/source/ShiftUI/Dialogs/StringArrayDialog.cs @@ -0,0 +1,558 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Drawing; + +namespace ShiftUI.Dialogs +{ + public interface IEditorDialog + { + object Value { get; } + void ShowEditor(); + } + + public class StringArrayDialog : Form, IEditorDialog + { + private string[] lines = null; + + public object Value + { + get { return lines; } + } + + public void ShowEditor() + { + this.StartPosition = FormStartPosition.CenterScreen; + this.ShowDialog(); + } + + public StringArrayDialog() + { + this.AllowTransparency = false; + this.AutoScale = true; + this.AutoScaleBaseSize = new Size(5, 13); + this.AutoScroll = false; + this.AutoSize = false; + this.AutoSizeMode = AutoSizeMode.GrowOnly; + this.AutoValidate = AutoValidate.Inherit; + this.BackColor = Color.FromArgb(240, 240, 240); + this.ClientSize = new Size(397, 391); + this.WidgetBox = true; + this.DesktopLocation = new Point(0, 0); + this.DialogResult = DialogResult.None; + this.FormBorderStyle = FormBorderStyle.Sizable; + this.HelpButton = false; + this.IsMdiContainer = false; + this.KeyPreview = false; + this.MaximizeBox = true; + this.MaximumSize = new Size(0, 0); + this.MinimizeBox = true; + this.MinimumSize = new Size(0, 0); + this.RightToLeftLayout = false; + this.ShowIcon = true; + this.ShowInTaskbar = true; + this.Size = new Size(397, 391); + this.SizeGripStyle = SizeGripStyle.Auto; + this.StartPosition = FormStartPosition.WindowsDefaultLocation; + this.TabIndex = 0; + this.TabStop = true; + this.TopLevel = true; + this.TopMost = false; + this.WindowState = FormWindowState.Normal; + this.Text = "String collection"; + this.Location = new Point(0, 0); + this.AutoScaleMode = AutoScaleMode.Inherit; + this.AutoScrollMargin = new Size(0, 0); + this.AutoScrollMinSize = new Size(0, 0); + this.AutoScrollPosition = new Point(0, 0); + this.Alignment = (ContentAlignment)0; + this.AccessibleDefaultActionDescription = ""; + this.AccessibleDescription = ""; + this.AccessibleName = ""; + this.AccessibleRole = AccessibleRole.Default; + this.AllowDrop = false; + this.Anchor = AnchorStyles.Top | AnchorStyles.Left; + this.AutoScrollOffset = new Point(0, 0); + this.BackgroundImageLayout = ImageLayout.Tile; + this.Capture = false; + this.CausesValidation = true; + this.Dock = DockStyle.None; + this.Enabled = true; + this.Font = new Font("Microsoft Sans Serif", (float)8.25, (FontStyle)0); + this.ForeColor = Color.FromArgb(0, 0, 0); + this.Height = 391; + this.ImeMode = ImeMode.NoControl; + this.IsAccessible = false; + this.Left = 0; + this.Name = "StringArrayDialog"; + this.RightToLeft = RightToLeft.No; + this.Top = 0; + this.UseWaitCursor = false; + this.Visible = false; + this.Width = 397; + + rtb_contents = new RichTextBox(); + rtb_contents.AllowDrop = false; + rtb_contents.AutoSize = false; + rtb_contents.AutoWordSelection = false; + rtb_contents.BackgroundImageLayout = ImageLayout.Tile; + rtb_contents.BulletIndent = 0; + rtb_contents.DetectUrls = true; + rtb_contents.EnableAutoDragDrop = false; + rtb_contents.Font = new Font("Microsoft Sans Serif", (float)8.25, (FontStyle)0); + rtb_contents.ForeColor = Color.FromArgb(0, 0, 0); + rtb_contents.LanguageOption = RichTextBoxLanguageOptions.AutoFontSizeAdjust; + rtb_contents.MaxLength = 2147483647; + rtb_contents.Multiline = true; + rtb_contents.RichTextShortcutsEnabled = true; + rtb_contents.RightMargin = 0; + rtb_contents.ScrollBars = RichTextBoxScrollBars.Both; + rtb_contents.SelectedText = ""; + rtb_contents.SelectionAlignment = HorizontalAlignment.Left; + rtb_contents.SelectionBackColor = Color.FromArgb(240, 240, 240); + rtb_contents.SelectionBullet = false; + rtb_contents.SelectionCharOffset = 0; + rtb_contents.SelectionColor = Color.FromArgb(0, 0, 0); + rtb_contents.SelectionFont = new Font("Microsoft Sans Serif", (float)8.25, (FontStyle)0); + rtb_contents.SelectionHangingIndent = 0; + rtb_contents.SelectionIndent = 0; + rtb_contents.SelectionLength = 0; + rtb_contents.SelectionProtected = false; + rtb_contents.SelectionRightIndent = 0; + rtb_contents.ShowSelectionMargin = false; + rtb_contents.Text = ""; + rtb_contents.AcceptsTab = false; + rtb_contents.BackColor = Color.FromArgb(255, 255, 255); + rtb_contents.BorderStyle = BorderStyle.Fixed3D; + rtb_contents.HideSelection = true; + rtb_contents.Modified = false; + rtb_contents.ReadOnly = false; + rtb_contents.SelectionStart = 0; + rtb_contents.ShortcutsEnabled = true; + rtb_contents.WordWrap = true; + rtb_contents.Alignment = (ContentAlignment)0; + rtb_contents.AccessibleDefaultActionDescription = ""; + rtb_contents.AccessibleDescription = ""; + rtb_contents.AccessibleName = ""; + rtb_contents.AccessibleRole = AccessibleRole.Default; + rtb_contents.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + rtb_contents.AutoScrollOffset = new Point(0, 0); + rtb_contents.MaximumSize = new Size(0, 0); + rtb_contents.MinimumSize = new Size(0, 0); + rtb_contents.Capture = false; + rtb_contents.CausesValidation = true; + rtb_contents.ClientSize = new Size(372, 281); + rtb_contents.Dock = DockStyle.None; + rtb_contents.Enabled = true; + rtb_contents.Height = 285; + rtb_contents.ImeMode = ImeMode.NoControl; + rtb_contents.IsAccessible = false; + rtb_contents.Left = 10; + rtb_contents.Location = new Point(10, 65); + rtb_contents.Name = "rtb_contents"; + rtb_contents.RightToLeft = RightToLeft.No; + rtb_contents.Size = new Size(376, 285); + rtb_contents.TabIndex = 0; + rtb_contents.TabStop = true; + rtb_contents.Top = 35; + rtb_contents.UseWaitCursor = false; + rtb_contents.Visible = true; + rtb_contents.Width = 376; + + this.Widgets.Add(rtb_contents); + rtb_contents.Show(); + lbtoplabel = new Label(); + lbtoplabel.AutoEllipsis = false; + lbtoplabel.AutoSize = false; + lbtoplabel.BackgroundImageLayout = ImageLayout.Tile; + lbtoplabel.BorderStyle = BorderStyle.None; + lbtoplabel.FlatStyle = FlatStyle.Standard; + lbtoplabel.ImageAlign = ContentAlignment.MiddleCenter; + lbtoplabel.ImageIndex = -1; + lbtoplabel.ImageKey = ""; + lbtoplabel.ImeMode = ImeMode.NoControl; + lbtoplabel.TabStop = false; + lbtoplabel.TextAlign = ContentAlignment.TopLeft; + lbtoplabel.UseMnemonic = true; + lbtoplabel.UseCompatibleTextRendering = true; + lbtoplabel.Text = "Enter each item on a separate line."; + lbtoplabel.Alignment = (ContentAlignment)0; + lbtoplabel.AccessibleDefaultActionDescription = ""; + lbtoplabel.AccessibleDescription = ""; + lbtoplabel.AccessibleName = ""; + lbtoplabel.AccessibleRole = AccessibleRole.Default; + lbtoplabel.AllowDrop = false; + lbtoplabel.Anchor = AnchorStyles.Top | AnchorStyles.Left; + lbtoplabel.AutoScrollOffset = new Point(0, 0); + lbtoplabel.MaximumSize = new Size(0, 0); + lbtoplabel.MinimumSize = new Size(0, 0); + lbtoplabel.BackColor = Color.FromArgb(240, 240, 240); + lbtoplabel.Capture = false; + lbtoplabel.CausesValidation = true; + lbtoplabel.ClientSize = new Size(189, 23); + lbtoplabel.Dock = DockStyle.None; + lbtoplabel.Enabled = true; + lbtoplabel.Font = new Font("Microsoft Sans Serif", (float)8.25, (FontStyle)0); + lbtoplabel.ForeColor = Color.FromArgb(0, 0, 0); + lbtoplabel.Height = 23; + lbtoplabel.IsAccessible = false; + lbtoplabel.Left = 16; + lbtoplabel.Location = new Point(16, 45); + lbtoplabel.Name = "lbtoplabel"; + lbtoplabel.RightToLeft = RightToLeft.No; + lbtoplabel.Size = new Size(189, 23); + lbtoplabel.TabIndex = 1; + lbtoplabel.Top = 15; + lbtoplabel.UseWaitCursor = false; + lbtoplabel.Visible = true; + lbtoplabel.Width = 189; + + this.Widgets.Add(lbtoplabel); + lbtoplabel.Show(); + btnok = new Button(); + btnok.Click += (o, a) => + { + this.DialogResult = DialogResult.OK; + lines = rtb_contents.Lines; + this.Close(); + }; + btnok.AutoSizeMode = AutoSizeMode.GrowAndShrink; + btnok.DialogResult = DialogResult.None; + btnok.AutoEllipsis = false; + btnok.AutoSize = true; + btnok.BackColor = Color.FromArgb(240, 240, 240); + btnok.FlatStyle = FlatStyle.Standard; + btnok.ImageAlign = ContentAlignment.MiddleCenter; + btnok.ImageIndex = -1; + btnok.ImageKey = ""; + btnok.ImeMode = ImeMode.Disable; + btnok.Text = "OK"; + btnok.TextAlign = ContentAlignment.MiddleCenter; + btnok.TextImageRelation = TextImageRelation.Overlay; + btnok.UseCompatibleTextRendering = true; + btnok.UseMnemonic = true; + btnok.UseVisualStyleBackColor = true; + btnok.Alignment = (ContentAlignment)0; + btnok.AccessibleDefaultActionDescription = ""; + btnok.AccessibleDescription = ""; + btnok.AccessibleName = ""; + btnok.AccessibleRole = AccessibleRole.Default; + btnok.AllowDrop = false; + btnok.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; + btnok.AutoScrollOffset = new Point(0, 0); + btnok.MaximumSize = new Size(0, 0); + btnok.MinimumSize = new Size(0, 0); + btnok.BackgroundImageLayout = ImageLayout.Tile; + btnok.Capture = false; + btnok.CausesValidation = true; + btnok.ClientSize = new Size(39, 23); + btnok.Dock = DockStyle.None; + btnok.Enabled = true; + btnok.Font = new Font("Microsoft Sans Serif", (float)8.25, (FontStyle)0); + btnok.ForeColor = Color.FromArgb(0, 0, 0); + btnok.Height = 23; + btnok.IsAccessible = false; + btnok.Left = 11; + btnok.Location = new Point(11, 355); + btnok.Name = "btnok"; + btnok.RightToLeft = RightToLeft.No; + btnok.Size = new Size(39, 23); + btnok.TabIndex = 2; + btnok.TabStop = true; + btnok.Top = 325; + btnok.UseWaitCursor = false; + btnok.Visible = true; + btnok.Width = 39; + + this.Widgets.Add(btnok); + btnok.Show(); + + } + public RichTextBox rtb_contents = null; + public Label lbtoplabel = null; + public Button btnok = null; + } + + public class ComboBoxEditorDialog : Form, IEditorDialog + { + ComboBox.ObjectCollection lines = null; + + public object Value + { + get { + return lines; + } + } + + public void ShowEditor() + { + this.StartPosition = FormStartPosition.CenterScreen; + this.ShowDialog(); + } + + public ComboBoxEditorDialog(ComboBox owner) + { + this.AllowTransparency = false; + this.AutoScale = true; + this.AutoScaleBaseSize = new Size(5, 13); + this.AutoScroll = false; + this.AutoSize = false; + this.AutoSizeMode = AutoSizeMode.GrowOnly; + this.AutoValidate = AutoValidate.Inherit; + this.BackColor = Color.FromArgb(240, 240, 240); + this.ClientSize = new Size(397, 391); + this.WidgetBox = true; + this.DesktopLocation = new Point(0, 0); + this.DialogResult = DialogResult.None; + this.FormBorderStyle = FormBorderStyle.Sizable; + this.HelpButton = false; + this.IsMdiContainer = false; + this.KeyPreview = false; + this.MaximizeBox = true; + this.MaximumSize = new Size(0, 0); + this.MinimizeBox = true; + this.MinimumSize = new Size(0, 0); + this.RightToLeftLayout = false; + this.ShowIcon = true; + this.ShowInTaskbar = true; + this.Size = new Size(397, 391); + this.SizeGripStyle = SizeGripStyle.Auto; + this.StartPosition = FormStartPosition.WindowsDefaultLocation; + this.TabIndex = 0; + this.TabStop = true; + this.TopLevel = true; + this.TopMost = false; + this.WindowState = FormWindowState.Normal; + this.Text = "ComboBox item collection"; + this.Location = new Point(0, 0); + this.AutoScaleMode = AutoScaleMode.Inherit; + this.AutoScrollMargin = new Size(0, 0); + this.AutoScrollMinSize = new Size(0, 0); + this.AutoScrollPosition = new Point(0, 0); + this.Alignment = (ContentAlignment)0; + this.AccessibleDefaultActionDescription = ""; + this.AccessibleDescription = ""; + this.AccessibleName = ""; + this.AccessibleRole = AccessibleRole.Default; + this.AllowDrop = false; + this.Anchor = AnchorStyles.Top | AnchorStyles.Left; + this.AutoScrollOffset = new Point(0, 0); + this.BackgroundImageLayout = ImageLayout.Tile; + this.Capture = false; + this.CausesValidation = true; + this.Dock = DockStyle.None; + this.Enabled = true; + this.Font = new Font("Microsoft Sans Serif", (float)8.25, (FontStyle)0); + this.ForeColor = Color.FromArgb(0, 0, 0); + this.Height = 391; + this.ImeMode = ImeMode.NoControl; + this.IsAccessible = false; + this.Left = 0; + this.Name = "StringArrayDialog"; + this.RightToLeft = RightToLeft.No; + this.Top = 0; + this.UseWaitCursor = false; + this.Visible = false; + this.Width = 397; + + rtb_contents = new RichTextBox(); + rtb_contents.AllowDrop = false; + rtb_contents.AutoSize = false; + rtb_contents.AutoWordSelection = false; + rtb_contents.BackgroundImageLayout = ImageLayout.Tile; + rtb_contents.BulletIndent = 0; + rtb_contents.DetectUrls = true; + rtb_contents.EnableAutoDragDrop = false; + rtb_contents.Font = new Font("Microsoft Sans Serif", (float)8.25, (FontStyle)0); + rtb_contents.ForeColor = Color.FromArgb(0, 0, 0); + rtb_contents.LanguageOption = RichTextBoxLanguageOptions.AutoFontSizeAdjust; + rtb_contents.MaxLength = 2147483647; + rtb_contents.Multiline = true; + rtb_contents.RichTextShortcutsEnabled = true; + rtb_contents.RightMargin = 0; + rtb_contents.ScrollBars = RichTextBoxScrollBars.Both; + rtb_contents.SelectedText = ""; + rtb_contents.SelectionAlignment = HorizontalAlignment.Left; + rtb_contents.SelectionBackColor = Color.FromArgb(240, 240, 240); + rtb_contents.SelectionBullet = false; + rtb_contents.SelectionCharOffset = 0; + rtb_contents.SelectionColor = Color.FromArgb(0, 0, 0); + rtb_contents.SelectionFont = new Font("Microsoft Sans Serif", (float)8.25, (FontStyle)0); + rtb_contents.SelectionHangingIndent = 0; + rtb_contents.SelectionIndent = 0; + rtb_contents.SelectionLength = 0; + rtb_contents.SelectionProtected = false; + rtb_contents.SelectionRightIndent = 0; + rtb_contents.ShowSelectionMargin = false; + rtb_contents.Text = ""; + rtb_contents.AcceptsTab = false; + rtb_contents.BackColor = Color.FromArgb(255, 255, 255); + rtb_contents.BorderStyle = BorderStyle.Fixed3D; + rtb_contents.HideSelection = true; + rtb_contents.Modified = false; + rtb_contents.ReadOnly = false; + rtb_contents.SelectionStart = 0; + rtb_contents.ShortcutsEnabled = true; + rtb_contents.WordWrap = true; + rtb_contents.Alignment = (ContentAlignment)0; + rtb_contents.AccessibleDefaultActionDescription = ""; + rtb_contents.AccessibleDescription = ""; + rtb_contents.AccessibleName = ""; + rtb_contents.AccessibleRole = AccessibleRole.Default; + rtb_contents.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + rtb_contents.AutoScrollOffset = new Point(0, 0); + rtb_contents.MaximumSize = new Size(0, 0); + rtb_contents.MinimumSize = new Size(0, 0); + rtb_contents.Capture = false; + rtb_contents.CausesValidation = true; + rtb_contents.ClientSize = new Size(372, 281); + rtb_contents.Dock = DockStyle.None; + rtb_contents.Enabled = true; + rtb_contents.Height = 285; + rtb_contents.ImeMode = ImeMode.NoControl; + rtb_contents.IsAccessible = false; + rtb_contents.Left = 10; + rtb_contents.Location = new Point(10, 65); + rtb_contents.Name = "rtb_contents"; + rtb_contents.RightToLeft = RightToLeft.No; + rtb_contents.Size = new Size(376, 285); + rtb_contents.TabIndex = 0; + rtb_contents.TabStop = true; + rtb_contents.Top = 35; + rtb_contents.UseWaitCursor = false; + rtb_contents.Visible = true; + rtb_contents.Width = 376; + foreach(var line in owner.Items) + { + if (string.IsNullOrEmpty(rtb_contents.Text)) + { + rtb_contents.Text += "\r\n" + line.ToString(); + } + else + { + rtb_contents.Text += "\r\n" + line.ToString(); + } + } + + this.Widgets.Add(rtb_contents); + rtb_contents.Show(); + lbtoplabel = new Label(); + lbtoplabel.AutoEllipsis = false; + lbtoplabel.AutoSize = false; + lbtoplabel.BackgroundImageLayout = ImageLayout.Tile; + lbtoplabel.BorderStyle = BorderStyle.None; + lbtoplabel.FlatStyle = FlatStyle.Standard; + lbtoplabel.ImageAlign = ContentAlignment.MiddleCenter; + lbtoplabel.ImageIndex = -1; + lbtoplabel.ImageKey = ""; + lbtoplabel.ImeMode = ImeMode.NoControl; + lbtoplabel.TabStop = false; + lbtoplabel.TextAlign = ContentAlignment.TopLeft; + lbtoplabel.UseMnemonic = true; + lbtoplabel.UseCompatibleTextRendering = true; + lbtoplabel.Text = "Enter each item on a separate line."; + lbtoplabel.Alignment = (ContentAlignment)0; + lbtoplabel.AccessibleDefaultActionDescription = ""; + lbtoplabel.AccessibleDescription = ""; + lbtoplabel.AccessibleName = ""; + lbtoplabel.AccessibleRole = AccessibleRole.Default; + lbtoplabel.AllowDrop = false; + lbtoplabel.Anchor = AnchorStyles.Top | AnchorStyles.Left; + lbtoplabel.AutoScrollOffset = new Point(0, 0); + lbtoplabel.MaximumSize = new Size(0, 0); + lbtoplabel.MinimumSize = new Size(0, 0); + lbtoplabel.BackColor = Color.FromArgb(240, 240, 240); + lbtoplabel.Capture = false; + lbtoplabel.CausesValidation = true; + lbtoplabel.ClientSize = new Size(189, 23); + lbtoplabel.Dock = DockStyle.None; + lbtoplabel.Enabled = true; + lbtoplabel.Font = new Font("Microsoft Sans Serif", (float)8.25, (FontStyle)0); + lbtoplabel.ForeColor = Color.FromArgb(0, 0, 0); + lbtoplabel.Height = 23; + lbtoplabel.IsAccessible = false; + lbtoplabel.Left = 16; + lbtoplabel.Location = new Point(16, 45); + lbtoplabel.Name = "lbtoplabel"; + lbtoplabel.RightToLeft = RightToLeft.No; + lbtoplabel.Size = new Size(189, 23); + lbtoplabel.TabIndex = 1; + lbtoplabel.Top = 15; + lbtoplabel.UseWaitCursor = false; + lbtoplabel.Visible = true; + lbtoplabel.Width = 189; + + this.Widgets.Add(lbtoplabel); + lbtoplabel.Show(); + btnok = new Button(); + btnok.Click += (o, a) => + { + this.DialogResult = DialogResult.OK; + lines = new ComboBox.ObjectCollection(owner); + foreach(var line in rtb_contents.Lines) + { + lines.Add(line); + } + this.Close(); + }; + btnok.AutoSizeMode = AutoSizeMode.GrowAndShrink; + btnok.DialogResult = DialogResult.None; + btnok.AutoEllipsis = false; + btnok.AutoSize = true; + btnok.BackColor = Color.FromArgb(240, 240, 240); + btnok.FlatStyle = FlatStyle.Standard; + btnok.ImageAlign = ContentAlignment.MiddleCenter; + btnok.ImageIndex = -1; + btnok.ImageKey = ""; + btnok.ImeMode = ImeMode.Disable; + btnok.Text = "OK"; + btnok.TextAlign = ContentAlignment.MiddleCenter; + btnok.TextImageRelation = TextImageRelation.Overlay; + btnok.UseCompatibleTextRendering = true; + btnok.UseMnemonic = true; + btnok.UseVisualStyleBackColor = true; + btnok.Alignment = (ContentAlignment)0; + btnok.AccessibleDefaultActionDescription = ""; + btnok.AccessibleDescription = ""; + btnok.AccessibleName = ""; + btnok.AccessibleRole = AccessibleRole.Default; + btnok.AllowDrop = false; + btnok.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; + btnok.AutoScrollOffset = new Point(0, 0); + btnok.MaximumSize = new Size(0, 0); + btnok.MinimumSize = new Size(0, 0); + btnok.BackgroundImageLayout = ImageLayout.Tile; + btnok.Capture = false; + btnok.CausesValidation = true; + btnok.ClientSize = new Size(39, 23); + btnok.Dock = DockStyle.None; + btnok.Enabled = true; + btnok.Font = new Font("Microsoft Sans Serif", (float)8.25, (FontStyle)0); + btnok.ForeColor = Color.FromArgb(0, 0, 0); + btnok.Height = 23; + btnok.IsAccessible = false; + btnok.Left = 11; + btnok.Location = new Point(11, 355); + btnok.Name = "btnok"; + btnok.RightToLeft = RightToLeft.No; + btnok.Size = new Size(39, 23); + btnok.TabIndex = 2; + btnok.TabStop = true; + btnok.Top = 325; + btnok.UseWaitCursor = false; + btnok.Visible = true; + btnok.Width = 39; + + this.Widgets.Add(btnok); + btnok.Show(); + + } + public RichTextBox rtb_contents = null; + public Label lbtoplabel = null; + public Button btnok = null; + + } + +} diff --git a/source/ShiftUI/Dialogs/ThreadExceptionDialog.cs b/source/ShiftUI/Dialogs/ThreadExceptionDialog.cs new file mode 100644 index 0000000..9bfc2fb --- /dev/null +++ b/source/ShiftUI/Dialogs/ThreadExceptionDialog.cs @@ -0,0 +1,233 @@ +// +// ShiftUI.ThreadExceptionDialog.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Authors: +// Marek Safar marek.safar@seznam.cz +// +// Copyright (C) Novell Inc., 2004 + +// COMPLETE - BUT DISABLED TEXTBOX + +using System; +using System.Drawing; +using System.Text; +using System.Reflection; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + public class ThreadExceptionDialog: Form + { + Exception e; + bool details; + + private ShiftUI.Button buttonIgnore; + private ShiftUI.Button buttonAbort; + private ShiftUI.Button buttonDetails; + private ShiftUI.Label labelException; + private ShiftUI.Label label1; + private ShiftUI.TextBox textBoxDetails; + private ShiftUI.Label helpText; + + private void InitializeComponent() + { + this.helpText = new ShiftUI.Label(); + this.buttonAbort = new ShiftUI.Button(); + this.buttonIgnore = new ShiftUI.Button(); + this.buttonDetails = new ShiftUI.Button(); + this.labelException = new ShiftUI.Label(); + this.textBoxDetails = new ShiftUI.TextBox(); + this.label1 = new ShiftUI.Label(); + this.SuspendLayout(); + // + // helpText + // + this.helpText.Location = new System.Drawing.Point(60, 8); + this.helpText.Name = "helpText"; + this.helpText.Size = new System.Drawing.Size(356, 40); + this.helpText.TabIndex = 0; + this.helpText.Text = "An unhandled exception has occurred in you application. If you click Ignore the a" + + "pplication will ignore this error and attempt to continue. If you click Abort, t" + + "he application will quit immediately."; + // + // buttonAbort + // + this.buttonAbort.DialogResult = ShiftUI.DialogResult.Abort; + this.buttonAbort.Location = new System.Drawing.Point(332, 112); + this.buttonAbort.Name = "buttonAbort"; + this.buttonAbort.Size = new System.Drawing.Size(85, 23); + this.buttonAbort.TabIndex = 4; + this.buttonAbort.Text = "&Abort"; + this.buttonAbort.Click += new System.EventHandler(this.buttonAbort_Click); + // + // buttonIgnore + // + this.buttonIgnore.DialogResult = ShiftUI.DialogResult.Ignore; + this.buttonIgnore.Location = new System.Drawing.Point(236, 112); + this.buttonIgnore.Name = "buttonIgnore"; + this.buttonIgnore.Size = new System.Drawing.Size(85, 23); + this.buttonIgnore.TabIndex = 3; + this.buttonIgnore.Text = "&Ignore"; + // + // buttonDetails + // + this.buttonDetails.Location = new System.Drawing.Point(140, 112); + this.buttonDetails.Name = "buttonDetails"; + this.buttonDetails.Size = new System.Drawing.Size(85, 23); + this.buttonDetails.TabIndex = 2; + this.buttonDetails.Text = "Show &Details"; + this.buttonDetails.Click += new System.EventHandler(this.buttonDetails_Click); + // + // labelException + // + this.labelException.Location = new System.Drawing.Point(60, 64); + this.labelException.Name = "labelException"; + this.labelException.Size = new System.Drawing.Size(356, 32); + this.labelException.TabIndex = 1; + // + // textBoxDetails + // + this.textBoxDetails.Location = new System.Drawing.Point(8, 168); + this.textBoxDetails.Multiline = true; + this.textBoxDetails.Name = "textBoxDetails"; + this.textBoxDetails.ReadOnly = true; + this.textBoxDetails.ScrollBars = ShiftUI.ScrollBars.Both; + this.textBoxDetails.Size = new System.Drawing.Size(408, 196); + this.textBoxDetails.TabIndex = 5; + this.textBoxDetails.TabStop = false; + this.textBoxDetails.Text = ""; + this.textBoxDetails.WordWrap = false; + // + // label1 + // + this.label1.Location = new System.Drawing.Point(8, 148); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(100, 16); + this.label1.TabIndex = 0; + this.label1.Text = "Exception details"; + // + // ThreadExceptionDialog + // + this.AcceptButton = this.buttonIgnore; + this.CancelButton = this.buttonAbort; + this.ClientSize = new System.Drawing.Size(428, 374); + this.Widgets.Add(this.label1); + this.Widgets.Add(this.textBoxDetails); + this.Widgets.Add(this.labelException); + this.Widgets.Add(this.buttonDetails); + this.Widgets.Add(this.buttonIgnore); + this.Widgets.Add(this.buttonAbort); + this.Widgets.Add(this.helpText); + this.FormBorderStyle = ShiftUI.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ThreadExceptionDialog"; + this.ShowInTaskbar = false; + this.StartPosition = ShiftUI.FormStartPosition.CenterScreen; + this.TopMost = true; + this.Paint += new PaintEventHandler (PaintHandler); + this.ResumeLayout(false); + } + + public ThreadExceptionDialog (Exception t) + { + this.e = t; + InitializeComponent (); + + this.labelException.Text = t.Message; + if (Form.ActiveForm != null) + this.Text = Form.ActiveForm.Text; + else + this.Text = "Mono"; + this.buttonAbort.Enabled = Application.AllowQuit; + RefreshDetails (); + FillExceptionDetails (); + } + + void buttonDetails_Click(object sender, System.EventArgs e) + { + details = !details; + RefreshDetails (); + } + + void FillExceptionDetails () + { + StringBuilder sb = new StringBuilder (); + sb.Append (e.ToString ()); + sb.Append (Environment.NewLine + Environment.NewLine); + sb.Append ("Loaded assemblies:" + Environment.NewLine + Environment.NewLine); + + foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies ()) { + AssemblyName an = a.GetName (); + sb.AppendFormat ("Name:\t{0}" + Environment.NewLine, an.Name); + sb.AppendFormat ("Version:\t{0}" + Environment.NewLine, an.Version); + sb.AppendFormat ("Location:\t{0}" + Environment.NewLine, an.CodeBase); + sb.Append (Environment.NewLine); + } + textBoxDetails.Text = sb.ToString (); + } + + void RefreshDetails () + { + if (details) { + buttonDetails.Text = "Hide &Details"; + Height = 410; + label1.Visible = true; + textBoxDetails.Visible = true; + return; + } + buttonDetails.Text = "Show &Details"; + label1.Visible = false; + textBoxDetails.Visible = false; + Height = 180; + } + + void buttonAbort_Click(object sender, System.EventArgs e) + { + Application.Exit (); + } + + void PaintHandler (object o, PaintEventArgs args) + { + Graphics g = args.Graphics; + g.DrawIcon (SystemIcons.Error, 15, 10); + } + + [Browsable (false)] + [EditorBrowsable (EditorBrowsableState.Never)] + [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override bool AutoSize { + get { return base.AutoSize; } + set { base.AutoSize = value; } + } + + [Browsable (false)] + [EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler AutoSizeChanged { + add { base.AutoSizeChanged += value; } + remove { base.AutoSizeChanged -= value; } + } + } +} diff --git a/source/ShiftUI/Enums/AccessibleEvents.cs b/source/ShiftUI/Enums/AccessibleEvents.cs new file mode 100644 index 0000000..90a9e82 --- /dev/null +++ b/source/ShiftUI/Enums/AccessibleEvents.cs @@ -0,0 +1,74 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +// COMPLETE + +namespace ShiftUI { + public enum AccessibleEvents { + SystemSound = 1, + SystemAlert = 2, + SystemForeground = 3, + SystemMenuStart = 4, + SystemMenuEnd = 5, + SystemMenuPopupStart = 6, + SystemMenuPopupEnd = 7, + SystemCaptureStart = 8, + SystemCaptureEnd = 9, + SystemMoveSizeStart = 10, + SystemMoveSizeEnd = 11, + SystemContextHelpStart = 12, + SystemContextHelpEnd = 13, + SystemDragDropStart = 14, + SystemDragDropEnd = 15, + SystemDialogStart = 16, + SystemDialogEnd = 17, + SystemScrollingStart = 18, + SystemScrollingEnd = 19, + SystemSwitchStart = 20, + SystemSwitchEnd = 21, + SystemMinimizeStart = 22, + SystemMinimizeEnd = 23, + Create = 32768, + Destroy = 32769, + Show = 32770, + Hide = 32771, + Reorder = 32772, + Focus = 32773, + Selection = 32774, + SelectionAdd = 32775, + SelectionRemove = 32776, + SelectionWithin = 32777, + StateChange = 32778, + LocationChange = 32779, + NameChange = 32780, + DescriptionChange = 32781, + ValueChange = 32782, + ParentChange = 32783, + HelpChange = 32784, + DefaultActionChange = 32785, + AcceleratorChange = 32786 + } +} diff --git a/source/ShiftUI/Enums/AccessibleNavigation.cs b/source/ShiftUI/Enums/AccessibleNavigation.cs new file mode 100644 index 0000000..1fb49be --- /dev/null +++ b/source/ShiftUI/Enums/AccessibleNavigation.cs @@ -0,0 +1,39 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com + + +// COMPLETE + +namespace ShiftUI { + public enum AccessibleNavigation { + Up = 1, + Down = 2, + Left = 3, + Right = 4, + Next = 5, + Previous = 6, + FirstChild = 7, + LastChild = 8 + } +} diff --git a/source/ShiftUI/Enums/AccessibleObject.cs b/source/ShiftUI/Enums/AccessibleObject.cs new file mode 100644 index 0000000..9411c58 --- /dev/null +++ b/source/ShiftUI/Enums/AccessibleObject.cs @@ -0,0 +1,561 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Peter Dennis Bartok pbartok@novell.com +// + + +// NOT COMPLETE + +using Accessibility; +using System.Drawing; +using System.Globalization; +using System.Reflection; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + [ComVisible(true)] + public class AccessibleObject : StandardOleMarshalObject, IReflect, IAccessible { + #region Private Variables + internal string name; + internal string value; + internal Widget owner; + internal AccessibleRole role; + internal AccessibleStates state; + internal string default_action; + internal string description; + internal string help; + internal string keyboard_shortcut; + #endregion // Private Variables + + #region Public Constructors + public AccessibleObject() { + this.owner = null; + this.value = null; + this.name = null; + this.role = AccessibleRole.Default; + this.default_action = null; + this.description = null; + this.help = null; + this.keyboard_shortcut = null; + this.state = AccessibleStates.None; + } + #endregion // Public Constructors + + #region Private Constructors + internal AccessibleObject(Widget owner) : this () { + this.owner=owner; + } + #endregion // Private Constructors + + #region Public Instance Properties + public virtual Rectangle Bounds { + get { + return owner.Bounds; + } + } + + public virtual string DefaultAction { + get { + return default_action; + } + } + + public virtual string Description { + get { + return description; + } + } + + public virtual string Help { + get { + return help; + } + } + + public virtual string KeyboardShortcut { + get { + return keyboard_shortcut; + } + } + + public virtual string Name { + get { + return name; + } + + set { + name=value; + } + } + + public virtual AccessibleObject Parent { + get { + if ((owner!=null) && (owner.Parent!=null)) { + return owner.Parent.AccessibilityObject; + } + return null; + } + } + + public virtual AccessibleRole Role { + get { + return role; + } + } + + public virtual AccessibleStates State { + get { +#if not + if (owner!=null) { + if (owner.Focused) { + state |= AccessibleStates.Focused; + } + + if (!owner.Visible) { + state |= AccessibleStates.Invisible; + } + } +#endif + return state; + } + } + + public virtual string Value { + get { + return this.value; + } + + set { + this.value=value; + } + } + #endregion // Public Instance Properties + + #region Public Instance Methods + public virtual void DoDefaultAction() { + if (owner!=null) { + owner.DoDefaultAction(); + } + } + + public virtual AccessibleObject GetChild(int index) { + if (owner!=null) { + if (indexowner.Bottom)) { + return owner.Parent.Widgets[i].AccessibilityObject; + } + } + + } + return owner.AccessibilityObject; + } + + case AccessibleNavigation.Left: { + if (owner.Parent != null) { + for (int i=0; iowner.Right)) { + return owner.Parent.Widgets[i].AccessibilityObject; + } + } + + } + return owner.AccessibilityObject; + } + + // Logical navigation + case AccessibleNavigation.Next: { + if (owner.Parent != null) { + if ((index+1)0) { + return owner.Parent.Widgets[index-1].AccessibilityObject; + } else { + return owner.Parent.Widgets[owner.Parent.Widgets.Count-1].AccessibilityObject; + } + } else { + return owner.AccessibilityObject; + } + } + + case AccessibleNavigation.FirstChild: { + if (owner.Widgets.Count>0) { + return owner.Widgets[0].AccessibilityObject; + } else { + return owner.AccessibilityObject; + } + } + + case AccessibleNavigation.LastChild: { + if (owner.Widgets.Count>0) { + return owner.Widgets[owner.Widgets.Count-1].AccessibilityObject; + } else { + return owner.AccessibilityObject; + } + } + } + + return owner.AccessibilityObject; + } + + public virtual void Select(AccessibleSelection flags) { + if ((flags & AccessibleSelection.TakeFocus) != 0){ + owner.Focus(); + } + return; + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + protected void UseStdAccessibleObjects(IntPtr handle) { + } + + protected void UseStdAccessibleObjects(IntPtr handle, int objid) { + UseStdAccessibleObjects(handle, 0); + } + #endregion // Protected Instance Methods + + + #region Internal Methods + internal static AccessibleObject FindFocusWidget(Widget parent) { + Widget child; + + if (parent != null) { + for (int i=0; i < parent.Widgets.Count; i++) { + child = parent.Widgets[i]; + if ((child.AccessibilityObject.state & AccessibleStates.Focused) != 0) { + return child.AccessibilityObject; + } + + if (child.Widgets.Count>0) { + AccessibleObject result; + + result = FindFocusWidget(child); + if (result != null) { + return result; + } + } + } + } + return null; + } + + internal static AccessibleObject FindSelectedWidget(Widget parent) { + Widget child; + + if (parent != null) { + for (int i=0; i < parent.Widgets.Count; i++) { + child = parent.Widgets[i]; + if ((child.AccessibilityObject.state & AccessibleStates.Selected) != 0) { + return child.AccessibilityObject; + } + if (child.Widgets.Count>0) { + AccessibleObject result; + + result = FindSelectedWidget(child); + if (result != null) { + return result; + } + } + } + } + return null; + } + + internal static Widget FindHittestWidget(Widget parent, int x, int y) { + Widget child; + Point child_point; + Point hittest_point; + + hittest_point = new Point(x, y); + + child_point = parent.PointToClient(hittest_point); + if (parent.ClientRectangle.Contains(child_point)) { + return parent; + } + + for (int i=0; i < parent.Widgets.Count; i++) { + child=parent.Widgets[i]; + child_point = child.PointToClient(hittest_point); + if (child.ClientRectangle.Contains(child_point)) { + return child; + } + if (child.Widgets.Count>0) { + Widget result; + + result = FindHittestWidget(child, x, y); + if (result != null) { + return result; + } + } + } + return null; + } + #endregion // Internal Methods + + #region IReflection Methods and Properties + FieldInfo IReflect.GetField(String name, BindingFlags bindingAttr) { + throw new NotImplementedException(); + } + + FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr) { + throw new NotImplementedException(); + } + + MemberInfo[] IReflect.GetMember(String name, BindingFlags bindingAttr) { + throw new NotImplementedException(); + } + + MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr) { + throw new NotImplementedException(); + } + + MethodInfo IReflect.GetMethod(String name, BindingFlags bindingAttr) { + throw new NotImplementedException(); + } + + MethodInfo IReflect.GetMethod(String name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers) { + throw new NotImplementedException(); + } + + MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr) { + throw new NotImplementedException(); + } + + PropertyInfo IReflect.GetProperty(String name, BindingFlags bindingAttr) { + throw new NotImplementedException(); + } + + PropertyInfo IReflect.GetProperty(String name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) { + throw new NotImplementedException(); + } + + PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr) { + throw new NotImplementedException(); + } + + Object IReflect.InvokeMember(String name, BindingFlags invokeAttr, Binder binder, Object target, Object[] args, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParameters) { + throw new NotImplementedException(); + } + + Type IReflect.UnderlyingSystemType { + get { + throw new NotImplementedException(); + } + } + #endregion // IReflection Methods and Properties + + #region IAccessible Methods and Properties + void IAccessible.accDoDefaultAction(object childID) { + throw new NotImplementedException(); + } + + int IAccessible.accChildCount { + get { + throw new NotImplementedException(); + } + } + + object IAccessible.accFocus { + get { + throw new NotImplementedException(); + } + } + + object IAccessible.accHitTest(int xLeft, int yTop) { + throw new NotImplementedException(); + } + + void IAccessible.accLocation(out int pxLeft, out int pyTop, out int pcxWidth, out int pcyHeight, object childID) { + throw new NotImplementedException(); + } + + object IAccessible.accNavigate(int navDir, object childID) { + throw new NotImplementedException(); + } + + object IAccessible.accParent { + get { + throw new NotImplementedException(); + } + } + + void IAccessible.accSelect(int flagsSelect, object childID) { + throw new NotImplementedException(); + } + + object IAccessible.accSelection { + get { + throw new NotImplementedException(); + } + } + + object IAccessible.get_accChild(object childID) { + throw new NotImplementedException(); + } + + string IAccessible.get_accDefaultAction(object childID) { + throw new NotImplementedException(); + } + + string IAccessible.get_accDescription(object childID) { + throw new NotImplementedException(); + } + + string IAccessible.get_accHelp(object childID) { + throw new NotImplementedException(); + } + + int IAccessible.get_accHelpTopic(out string pszHelpFile,object childID) { + throw new NotImplementedException(); + } + + string IAccessible.get_accKeyboardShortcut(object childID) { + throw new NotImplementedException(); + } + + string IAccessible.get_accName(object childID) { + throw new NotImplementedException(); + } + + object IAccessible.get_accRole(object childID) { + throw new NotImplementedException(); + } + + object IAccessible.get_accState(object childID) { + throw new NotImplementedException(); + } + + string IAccessible.get_accValue(object childID) { + throw new NotImplementedException(); + } + + void IAccessible.set_accName(object childID, string newName) { + throw new NotImplementedException(); + } + + void IAccessible.set_accValue(object childID, string newValue) { + throw new NotImplementedException(); + } + #endregion // IAccessible Methods and Properties + } +} diff --git a/source/ShiftUI/Enums/AccessibleRole.cs b/source/ShiftUI/Enums/AccessibleRole.cs new file mode 100644 index 0000000..95d0675 --- /dev/null +++ b/source/ShiftUI/Enums/AccessibleRole.cs @@ -0,0 +1,98 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +namespace ShiftUI { + public enum AccessibleRole { + None = 0, + TitleBar = 1, + MenuBar = 2, + ScrollBar = 3, + Grip = 4, + Sound = 5, + Cursor = 6, + Caret = 7, + Alert = 8, + Window = 9, + Client = 10, + MenuPopup = 11, + MenuItem = 12, + ToolTip = 13, + Application = 14, + Document = 15, + Pane = 16, + Chart = 17, + Dialog = 18, + Border = 19, + Grouping = 20, + Separator = 21, + ToolBar = 22, + StatusBar = 23, + Table = 24, + ColumnHeader = 25, + RowHeader = 26, + Column = 27, + Row = 28, + Cell = 29, + Link = 30, + HelpBalloon = 31, + Character = 32, + List = 33, + ListItem = 34, + Outline = 35, + OutlineItem = 36, + PageTab = 37, + PropertyPage = 38, + Indicator = 39, + Graphic = 40, + StaticText = 41, + Text = 42, + PushButton = 43, + CheckButton = 44, + RadioButton = 45, + ComboBox = 46, + DropList = 47, + ProgressBar = 48, + Dial = 49, + HotkeyField = 50, + Slider = 51, + SpinButton = 52, + Diagram = 53, + Animation = 54, + Equation = 55, + ButtonDropDown = 56, + ButtonMenu = 57, + ButtonDropDownGrid= 58, + WhiteSpace = 59, + PageTabList = 60, + Clock = 61, + Default = -1, + SplitButton = 62, + IpAddress = 63, + OutlineButton = 64 + } +} diff --git a/source/ShiftUI/Enums/AccessibleSelection.cs b/source/ShiftUI/Enums/AccessibleSelection.cs new file mode 100644 index 0000000..87186e9 --- /dev/null +++ b/source/ShiftUI/Enums/AccessibleSelection.cs @@ -0,0 +1,40 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE +using System; + +namespace ShiftUI { + [Flags] + public enum AccessibleSelection { + None = 0x00000000, + TakeFocus = 0x00000001, + TakeSelection = 0x00000002, + ExtendSelection = 0x00000004, + AddSelection = 0x00000008, + RemoveSelection = 0x00000010 + } +} diff --git a/source/ShiftUI/Enums/AccessibleStates.cs b/source/ShiftUI/Enums/AccessibleStates.cs new file mode 100644 index 0000000..e453e58 --- /dev/null +++ b/source/ShiftUI/Enums/AccessibleStates.cs @@ -0,0 +1,70 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE +using System; + +namespace ShiftUI { + + [Flags] + public enum AccessibleStates { + None = 0x00000000, + Unavailable = 0x00000001, + Selected = 0x00000002, + Focused = 0x00000004, + Pressed = 0x00000008, + Checked = 0x00000010, + Mixed = 0x00000020, + Indeterminate = 0x00000020, + ReadOnly = 0x00000040, + HotTracked = 0x00000080, + Default = 0x00000100, + Expanded = 0x00000200, + Collapsed = 0x00000400, + Busy = 0x00000800, + Floating = 0x00001000, + Marqueed = 0x00002000, + Animated = 0x00004000, + Invisible = 0x00008000, + Offscreen = 0x00010000, + Sizeable = 0x00020000, + Moveable = 0x00040000, + SelfVoicing = 0x00080000, + Focusable = 0x00100000, + Selectable = 0x00200000, + Linked = 0x00400000, + Traversed = 0x00800000, + MultiSelectable = 0x01000000, + ExtSelectable = 0x02000000, + AlertLow = 0x04000000, + AlertMedium = 0x08000000, + AlertHigh = 0x10000000, + Protected = 0x20000000, + [Obsolete] + Valid = 0x3FFFFFFF, + HasPopup = 0x40000000 + } +} diff --git a/source/ShiftUI/Enums/AmbientProperties.cs b/source/ShiftUI/Enums/AmbientProperties.cs new file mode 100644 index 0000000..fb1abe0 --- /dev/null +++ b/source/ShiftUI/Enums/AmbientProperties.cs @@ -0,0 +1,87 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +using System.Drawing; + +namespace ShiftUI { + public sealed class AmbientProperties { + #region Local Variables + private Color fore_color; + private Color back_color; + private Font font; + private Cursor cursor; + #endregion // Local Variables + + #region Public Constructors + public AmbientProperties() { + } + #endregion // Public Constructors + + #region Public Instance Properties + public Color BackColor { + get { + return back_color; + } + + set { + back_color = value; + } + } + + public Cursor Cursor { + get { + return cursor; + } + + set { + cursor = value; + } + } + + public Font Font { + get { + return font; + } + + set { + font = value; + } + } + + public Color ForeColor { + get { + return fore_color; + } + + set { + fore_color = value; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Enums/AnchorStyles.cs b/source/ShiftUI/Enums/AnchorStyles.cs new file mode 100644 index 0000000..52e8c53 --- /dev/null +++ b/source/ShiftUI/Enums/AnchorStyles.cs @@ -0,0 +1,41 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +using System.ComponentModel; +using System; + +namespace ShiftUI { + [Flags] + public enum AnchorStyles { + None = 0x00000000, + Top = 0x00000001, + Bottom = 0x00000002, + Left = 0x00000004, + Right = 0x00000008 + } +} diff --git a/source/ShiftUI/Enums/Appearance.cs b/source/ShiftUI/Enums/Appearance.cs new file mode 100644 index 0000000..d9f8774 --- /dev/null +++ b/source/ShiftUI/Enums/Appearance.cs @@ -0,0 +1,37 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +using System.Runtime.InteropServices; + +namespace ShiftUI { + [ComVisible(true)] + public enum Appearance { + Normal = 0, + Button = 1 + } +} diff --git a/source/ShiftUI/Enums/ArrangeDirection.cs b/source/ShiftUI/Enums/ArrangeDirection.cs new file mode 100644 index 0000000..3b98715 --- /dev/null +++ b/source/ShiftUI/Enums/ArrangeDirection.cs @@ -0,0 +1,41 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +// COMPLETE + +using System; +using System.Runtime.InteropServices; + +namespace ShiftUI { + [Flags] + [ComVisible(true)] + public enum ArrangeDirection { + Left = 0, + Right = 0, + Down = 4, + Up = 4 + } +} diff --git a/source/ShiftUI/Enums/ArrangeStartingPosition.cs b/source/ShiftUI/Enums/ArrangeStartingPosition.cs new file mode 100644 index 0000000..7b56b3a --- /dev/null +++ b/source/ShiftUI/Enums/ArrangeStartingPosition.cs @@ -0,0 +1,39 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +// COMPLETE +using System; + +namespace ShiftUI { + [Flags] + public enum ArrangeStartingPosition { + BottomLeft = 0, + BottomRight = 1, + TopLeft = 2, + TopRight = 3, + Hide = 8 + } +} diff --git a/source/ShiftUI/Enums/ArrowDirection.cs b/source/ShiftUI/Enums/ArrowDirection.cs new file mode 100644 index 0000000..653b3aa --- /dev/null +++ b/source/ShiftUI/Enums/ArrowDirection.cs @@ -0,0 +1,39 @@ +// +// ArrowDirection.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum ArrowDirection + { + Left = 0, + Up = 1, + Right = 16, + Down = 17 + } +} diff --git a/source/ShiftUI/Enums/AutoCompleteMode.cs b/source/ShiftUI/Enums/AutoCompleteMode.cs new file mode 100644 index 0000000..0cfc065 --- /dev/null +++ b/source/ShiftUI/Enums/AutoCompleteMode.cs @@ -0,0 +1,38 @@ +// +// AutoCompleteMode.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public enum AutoCompleteMode + { + None = 0, + Suggest = 1, + Append = 2, + SuggestAppend = 3 + } +} diff --git a/source/ShiftUI/Enums/AutoScaleMode.cs b/source/ShiftUI/Enums/AutoScaleMode.cs new file mode 100644 index 0000000..d4f53a0 --- /dev/null +++ b/source/ShiftUI/Enums/AutoScaleMode.cs @@ -0,0 +1,34 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Dennis Bartok (pbartok@novell.com) +// +// + +namespace ShiftUI { + public enum AutoScaleMode { + None = 0, + Font = 1, + Dpi = 2, + Inherit = 3 + } +} diff --git a/source/ShiftUI/Enums/AutoSizeMode.cs b/source/ShiftUI/Enums/AutoSizeMode.cs new file mode 100644 index 0000000..1811a2d --- /dev/null +++ b/source/ShiftUI/Enums/AutoSizeMode.cs @@ -0,0 +1,37 @@ +// +// AutoSizeMode.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum AutoSizeMode + { + GrowAndShrink = 0, + GrowOnly = 1 + } +} diff --git a/source/ShiftUI/Enums/AutoValidate.cs b/source/ShiftUI/Enums/AutoValidate.cs new file mode 100644 index 0000000..f46ccb2 --- /dev/null +++ b/source/ShiftUI/Enums/AutoValidate.cs @@ -0,0 +1,39 @@ +// +// AutoValidate.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum AutoValidate + { + Inherit = -1, + Disable = 0, + EnablePreventFocusChange = 1, + EnableAllowFocusChange = 2 + } +} diff --git a/source/ShiftUI/Enums/BatteryChargeStatus.cs b/source/ShiftUI/Enums/BatteryChargeStatus.cs new file mode 100644 index 0000000..19b6681 --- /dev/null +++ b/source/ShiftUI/Enums/BatteryChargeStatus.cs @@ -0,0 +1,42 @@ +// +// BatteryChargeStatus.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + [Flags] + public enum BatteryChargeStatus + { + High = 1, + Low = 2, + Critical = 4, + Charging = 8, + NoSystemBattery = 128, + Unknown = 255 + } +} diff --git a/source/ShiftUI/Enums/BindingCompleteState.cs b/source/ShiftUI/Enums/BindingCompleteState.cs new file mode 100644 index 0000000..67adb05 --- /dev/null +++ b/source/ShiftUI/Enums/BindingCompleteState.cs @@ -0,0 +1,38 @@ +// +// BindingCompleteState.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum BindingCompleteState + { + Success = 0, + DataError = 1, + Exception = 2 + } +} diff --git a/source/ShiftUI/Enums/Border3DSide.cs b/source/ShiftUI/Enums/Border3DSide.cs new file mode 100644 index 0000000..5e827ff --- /dev/null +++ b/source/ShiftUI/Enums/Border3DSide.cs @@ -0,0 +1,42 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE +using System; +using System.Runtime.InteropServices; + +namespace ShiftUI { + [ComVisible(true)] + [Flags] + public enum Border3DSide { + Left = 0x00000001, + Top = 0x00000002, + Right = 0x00000004, + Bottom = 0x00000008, + Middle = 0x00000800, + All = 0x0000080F + } +} diff --git a/source/ShiftUI/Enums/Border3DStyle.cs b/source/ShiftUI/Enums/Border3DStyle.cs new file mode 100644 index 0000000..86113fd --- /dev/null +++ b/source/ShiftUI/Enums/Border3DStyle.cs @@ -0,0 +1,45 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +using System.Runtime.InteropServices; + +namespace ShiftUI { + [ComVisible(true)] + public enum Border3DStyle { + RaisedOuter = 1, + SunkenOuter = 2, + RaisedInner = 4, + Raised = 5, + Etched = 6, + SunkenInner = 8, + Bump = 9, + Sunken = 10, + Adjust = 8192, + Flat = 16394 + } +} diff --git a/source/ShiftUI/Enums/BorderStyle.cs b/source/ShiftUI/Enums/BorderStyle.cs new file mode 100644 index 0000000..1611341 --- /dev/null +++ b/source/ShiftUI/Enums/BorderStyle.cs @@ -0,0 +1,37 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + +// COMPLETE + +using System.Runtime.InteropServices; + +namespace ShiftUI { + [ComVisible(true)] + public enum BorderStyle { + None = 0, + FixedSingle = 1, + Fixed3D = 2 + } +} diff --git a/source/ShiftUI/Enums/ButtonBorderStyle.cs b/source/ShiftUI/Enums/ButtonBorderStyle.cs new file mode 100644 index 0000000..fb932b3 --- /dev/null +++ b/source/ShiftUI/Enums/ButtonBorderStyle.cs @@ -0,0 +1,38 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +namespace ShiftUI { + public enum ButtonBorderStyle { + None = 0, + Dotted = 1, + Dashed = 2, + Solid = 3, + Inset = 4, + Outset = 5 + } +} diff --git a/source/ShiftUI/Enums/ButtonState.cs b/source/ShiftUI/Enums/ButtonState.cs new file mode 100644 index 0000000..f11d71c --- /dev/null +++ b/source/ShiftUI/Enums/ButtonState.cs @@ -0,0 +1,41 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE +using System; + +namespace ShiftUI { + + [Flags] + public enum ButtonState { + Normal = 0x00000000, + Inactive = 0x00000100, + Pushed = 0x00000200, + Checked = 0x00000400, + Flat = 0x00004000, + All = 0x00004700 + } +} diff --git a/source/ShiftUI/Enums/CharacterCasing.cs b/source/ShiftUI/Enums/CharacterCasing.cs new file mode 100644 index 0000000..8bdba2b --- /dev/null +++ b/source/ShiftUI/Enums/CharacterCasing.cs @@ -0,0 +1,35 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +// COMPLETE + +namespace ShiftUI { + public enum CharacterCasing { + Normal = 0, + Upper = 1, + Lower = 2 + } +} diff --git a/source/ShiftUI/Enums/CheckState.cs b/source/ShiftUI/Enums/CheckState.cs new file mode 100644 index 0000000..b71f7be --- /dev/null +++ b/source/ShiftUI/Enums/CheckState.cs @@ -0,0 +1,34 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com + + +// COMPLETE + +namespace ShiftUI { + public enum CheckState { + Unchecked = 0, + Checked = 1, + Indeterminate = 2 + } +} diff --git a/source/ShiftUI/Enums/CloseReason.cs b/source/ShiftUI/Enums/CloseReason.cs new file mode 100644 index 0000000..f742ef4 --- /dev/null +++ b/source/ShiftUI/Enums/CloseReason.cs @@ -0,0 +1,42 @@ +// +// CloseReason.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum CloseReason + { + None = 0, + WindowsShutDown = 1, + MdiFormClosing = 2, + UserClosing = 3, + TaskManagerClosing = 4, + FormOwnerClosing = 5, + ApplicationExitCall = 6 + } +} \ No newline at end of file diff --git a/source/ShiftUI/Enums/ColorDepth.cs b/source/ShiftUI/Enums/ColorDepth.cs new file mode 100644 index 0000000..1247141 --- /dev/null +++ b/source/ShiftUI/Enums/ColorDepth.cs @@ -0,0 +1,37 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// + + +// COMPLETE + +namespace ShiftUI { + public enum ColorDepth { + Depth4Bit = 4, + Depth8Bit = 8, + Depth16Bit = 16, + Depth24Bit = 24, + Depth32Bit = 32 + } +} diff --git a/source/ShiftUI/Enums/ComboBoxStyle.cs b/source/ShiftUI/Enums/ComboBoxStyle.cs new file mode 100644 index 0000000..97e9e83 --- /dev/null +++ b/source/ShiftUI/Enums/ComboBoxStyle.cs @@ -0,0 +1,37 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// + +using System; + +namespace ShiftUI { + + public enum ComboBoxStyle + { + Simple = 0, + DropDown = 1, + DropDownList = 2, + + } +} diff --git a/source/ShiftUI/Enums/ControlStyles.cs b/source/ShiftUI/Enums/ControlStyles.cs new file mode 100644 index 0000000..0cc2dab --- /dev/null +++ b/source/ShiftUI/Enums/ControlStyles.cs @@ -0,0 +1,58 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +using System.ComponentModel; +using System; + +namespace ShiftUI { + + [Flags] + public enum Widgetstyles { + ContainerWidget = 0x00000001, + UserPaint = 0x00000002, + Opaque = 0x00000004, + ResizeRedraw = 0x00000010, + FixedWidth = 0x00000020, + FixedHeight = 0x00000040, + StandardClick = 0x00000100, + Selectable = 0x00000200, + UserMouse = 0x00000400, + SupportsTransparentBackColor = 0x00000800, + StandardDoubleClick = 0x00001000, + AllPaintingInWmPaint = 0x00002000, + CacheText = 0x00004000, + EnableNotifyMessage = 0x00008000, + + //[EditorBrowsable (EditorBrowsableState.Never)] + DoubleBuffer = 0x00010000, + + OptimizedDoubleBuffer = 0x00020000, + UseTextForAccessibility = 0x00040000 + } +} diff --git a/source/ShiftUI/Enums/ControlUpdateMode.cs b/source/ShiftUI/Enums/ControlUpdateMode.cs new file mode 100644 index 0000000..ae7df34 --- /dev/null +++ b/source/ShiftUI/Enums/ControlUpdateMode.cs @@ -0,0 +1,37 @@ +// +// ControlUpdateMode.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum ControlUpdateMode + { + OnPropertyChanged = 0, + Never = 1 + } +} diff --git a/source/ShiftUI/Enums/CreateParams.cs b/source/ShiftUI/Enums/CreateParams.cs new file mode 100644 index 0000000..6712874 --- /dev/null +++ b/source/ShiftUI/Enums/CreateParams.cs @@ -0,0 +1,171 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +using System.Collections; +using System.ComponentModel; +using System; + +namespace ShiftUI { + public class CreateParams { + #region Local Variables + private string caption; + private string class_name; + private int class_style; + private int ex_style; + private int x; + private int y; + private int height; + private int width; + private int style; + private object param; + private IntPtr parent; + internal Menu menu; + internal Widget control; + #endregion // Local variables + + #region Public Constructors + public CreateParams() { + } + #endregion // Public Constructors + + #region Public Instance Properties + public string Caption { + get { return caption; } + set { caption = value; } + } + + public string ClassName { + get { return class_name; } + set { class_name = value; } + } + + public int ClassStyle { + get { return class_style; } + set { class_style = value; } + } + + public int ExStyle { + get { return ex_style; } + set { ex_style = value; } + } + + public int X { + get { return x; } + set { x = value; } + } + + public int Y { + get { return y; } + set { y = value; } + } + + public int Width { + get { return width; } + set { width = value; } + } + + public int Height { + get { return height; } + set { height = value; } + } + + public int Style { + get { return style; } + set { style = value; } + } + + public object Param { + get { return param; } + set { param = value; } + } + + public IntPtr Parent { + get { return parent; } + set { parent = value; } + } + #endregion // Public Instance Properties + + #region Internal Instance Methods + internal bool IsSet (WindowStyles Style) { + return (this.style & (int) Style) == (int) Style; + } + + internal bool IsSet (WindowExStyles ExStyle) { + return (this.ex_style & (int) ExStyle) == (int) ExStyle; + } + + internal static bool IsSet (WindowExStyles ExStyle, WindowExStyles Option) { + return (Option & ExStyle) == Option; + } + + internal static bool IsSet (WindowStyles Style, WindowStyles Option) { + return (Option & Style) == Option; + } + + internal bool HasWindowManager { + get { + if (control == null) + return false; + + Form form = control as Form; + + if (form == null) + return false; + + return form.window_manager != null; + } + } + internal WindowExStyles WindowExStyle { + get { + return (WindowExStyles) ex_style; + } + set + { + ex_style = (int)value; + } + } + + internal WindowStyles WindowStyle { + get { + return (WindowStyles) style; + } + set { + style = (int) value; + } + } + #endregion + + #region Public Instance Methods + public override string ToString() { + return string.Format ("CreateParams {{'{0}', '{1}', 0x{2:X}, 0x{3:X}, {{{4}, {5}, {6}, {7}}}}}", + class_name, caption, class_style, ex_style, x, y, width, height); + } + #endregion // Public Instance Methods + + } +} diff --git a/source/ShiftUI/Enums/DataFormats.cs b/source/ShiftUI/Enums/DataFormats.cs new file mode 100644 index 0000000..a70851d --- /dev/null +++ b/source/ShiftUI/Enums/DataFormats.cs @@ -0,0 +1,229 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +using System; +using System.Collections; +using System.Text; + +namespace ShiftUI +{ + public class DataFormats + { + public class Format + { + static readonly object lockobj = new object (); + + private static Format formats; + private string name; + private int id; + private Format next; + internal bool is_serializable; + + public Format (string name, int id) + { + this.name = name; + this.id = id; + + lock (lockobj) { + if (formats == null) + formats = this; + else { + Format f = formats; + while (f.next != null) + f = f.next; + f.next = this; + } + } + } + + #region Public Instance Properties + public int Id { + get { + return this.id; + } + } + + public string Name { + get { + return this.name; + } + } + + internal Format Next { + get { + return this.next; + } + } + #endregion // Public Instance Properties + + #region Private Methods + internal static Format Add (string name) + { + Format f; + + f = Find (name); + if (f == null) { + IntPtr cliphandle; + + cliphandle = XplatUI.ClipboardOpen (false); + f = new Format (name, XplatUI.ClipboardGetID (cliphandle, name)); + XplatUI.ClipboardClose (cliphandle); + } + return f; + } + + internal static Format Add (int id) { + Format f; + + f = Find (id); + if (f == null) + f = new Format("Format" + id.ToString(), id); + return f; + } + + internal static Format Find (int id) { + Format f; + + f = formats; + while ((f != null) && (f.Id != id)) + f = f.next; + return f; + } + + internal static Format Find (string name) { + Format f; + + f = formats; + while ((f != null) && (!f.Name.Equals(name))) + f = f.next; + return f; + } + + internal static Format List { + get { + return formats; + } + } + #endregion // Private Methods + } + + private DataFormats () + { + } + + #region Public Static Fields + public static readonly string Bitmap = "Bitmap"; + public static readonly string CommaSeparatedValue = "Csv"; + public static readonly string Dib = "DeviceIndependentBitmap"; + public static readonly string Dif = "DataInterchangeFormat"; + public static readonly string EnhancedMetafile = "EnhancedMetafile"; + public static readonly string FileDrop = "FileDrop"; + public static readonly string Html = "HTML Format"; + public static readonly string Locale = "Locale"; + public static readonly string MetafilePict = "MetaFilePict"; + public static readonly string OemText = "OEMText"; + public static readonly string Palette = "Palette"; + public static readonly string PenData = "PenData"; + public static readonly string Riff = "RiffAudio"; + public static readonly string Rtf = "Rich Text Format"; + public static readonly string Serializable = "WindowsForms10PersistentObject"; + public static readonly string StringFormat = "System.String"; + public static readonly string SymbolicLink = "SymbolicLink"; + public static readonly string Text = "Text"; + public static readonly string Tiff = "Tiff"; + public static readonly string UnicodeText = "UnicodeText"; + public static readonly string WaveAudio = "WaveAudio"; + #endregion // Public Static Fields + + private static object lock_object = new object (); + private static bool initialized; + + // we don't want to force the creation of a new format + internal static bool ContainsFormat (int id) + { + lock (lock_object) { + if (!initialized) + Init (); + + return Format.Find (id) != null; + } + } + + public static Format GetFormat (int id) + { + lock (lock_object) { + if (!initialized) + Init (); + return Format.Find (id); + } + } + + public static Format GetFormat (string format) + { + lock (lock_object) { + if (!initialized) + Init (); + return Format.Add (format); + } + } + + // Assumes we are locked on the lock_object when it is called + private static void Init () + { + if (initialized) + return; + IntPtr cliphandle = XplatUI.ClipboardOpen(false); + + new Format (Text, XplatUI.ClipboardGetID (cliphandle, Text)); + new Format (Bitmap, XplatUI.ClipboardGetID (cliphandle, Bitmap)); + new Format (MetafilePict, XplatUI.ClipboardGetID (cliphandle, MetafilePict)); + new Format (SymbolicLink, XplatUI.ClipboardGetID (cliphandle, SymbolicLink)); + new Format (Dif, XplatUI.ClipboardGetID (cliphandle, Dif)) ; + new Format (Tiff, XplatUI.ClipboardGetID (cliphandle, Tiff)); + new Format (OemText, XplatUI.ClipboardGetID (cliphandle, OemText)); + new Format (Dib, XplatUI.ClipboardGetID (cliphandle, Dib)); + new Format (Palette, XplatUI.ClipboardGetID (cliphandle, Palette)); + new Format (PenData, XplatUI.ClipboardGetID (cliphandle, PenData)); + new Format (Riff, XplatUI.ClipboardGetID (cliphandle, Riff)); + new Format (WaveAudio, XplatUI.ClipboardGetID (cliphandle, WaveAudio)); + new Format (UnicodeText, XplatUI.ClipboardGetID (cliphandle, UnicodeText)); + new Format (EnhancedMetafile, XplatUI.ClipboardGetID (cliphandle, EnhancedMetafile)); + new Format (FileDrop, XplatUI.ClipboardGetID (cliphandle, FileDrop)); + new Format (Locale, XplatUI.ClipboardGetID (cliphandle, Locale)); + new Format (CommaSeparatedValue, XplatUI.ClipboardGetID (cliphandle, CommaSeparatedValue)); + new Format (Html, XplatUI.ClipboardGetID (cliphandle, Html)); + new Format (Rtf, XplatUI.ClipboardGetID (cliphandle, Rtf)); + new Format (Serializable, XplatUI.ClipboardGetID (cliphandle, Serializable)); + new Format (StringFormat, XplatUI.ClipboardGetID (cliphandle, StringFormat)); + + XplatUI.ClipboardClose (cliphandle); + + initialized = true; + } + } +} diff --git a/source/ShiftUI/Enums/DataSourceUpdateMode.cs b/source/ShiftUI/Enums/DataSourceUpdateMode.cs new file mode 100644 index 0000000..13c2a84 --- /dev/null +++ b/source/ShiftUI/Enums/DataSourceUpdateMode.cs @@ -0,0 +1,38 @@ +// +// DataSourceUpdateMode.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum DataSourceUpdateMode + { + OnValidation = 0, + OnPropertyChanged = 1, + Never = 2 + } +} diff --git a/source/ShiftUI/Enums/DateTimePickerFormat.cs b/source/ShiftUI/Enums/DateTimePickerFormat.cs new file mode 100644 index 0000000..a3f7e12 --- /dev/null +++ b/source/ShiftUI/Enums/DateTimePickerFormat.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Authors: +// John BouAntoun jba-mono@optusnet.com.au +// + +namespace ShiftUI { + public enum DateTimePickerFormat { + Custom = 8, + Long = 1, + Short = 2, + Time = 4 + } +} diff --git a/source/ShiftUI/Enums/DialogResult.cs b/source/ShiftUI/Enums/DialogResult.cs new file mode 100644 index 0000000..6be5ce9 --- /dev/null +++ b/source/ShiftUI/Enums/DialogResult.cs @@ -0,0 +1,46 @@ +// +// ShiftUI.DialogResult.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// + +// COMPLETE + +using System.Runtime.InteropServices; + +namespace ShiftUI { + + [ComVisible(true)] + public enum DialogResult + { + None = 0, + OK = 1, + Cancel = 2, + Abort = 3, + Retry = 4, + Ignore = 5, + Yes = 6, + No = 7 + } +} + diff --git a/source/ShiftUI/Enums/DockStyle.cs b/source/ShiftUI/Enums/DockStyle.cs new file mode 100644 index 0000000..2beaa00 --- /dev/null +++ b/source/ShiftUI/Enums/DockStyle.cs @@ -0,0 +1,41 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +using System.ComponentModel; + +namespace ShiftUI { + //[Editor("ShiftUI.Design.DockEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))] + public enum DockStyle { + None = 0, + Top = 1, + Bottom = 2, + Left = 3, + Right = 4, + Fill = 5 + } +} diff --git a/source/ShiftUI/Enums/DragAction.cs b/source/ShiftUI/Enums/DragAction.cs new file mode 100644 index 0000000..ed52a7d --- /dev/null +++ b/source/ShiftUI/Enums/DragAction.cs @@ -0,0 +1,39 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +using System.Runtime.InteropServices; + +namespace ShiftUI { + [ComVisible(true)] + public enum DragAction { + Continue = 0, + Drop = 1, + Cancel = 2 + } +} diff --git a/source/ShiftUI/Enums/DragDropEffects.cs b/source/ShiftUI/Enums/DragDropEffects.cs new file mode 100644 index 0000000..00698b3 --- /dev/null +++ b/source/ShiftUI/Enums/DragDropEffects.cs @@ -0,0 +1,42 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE +using System; + +namespace ShiftUI { + + [Flags] + public enum DragDropEffects { + None = 0x00000000, + Copy = 0x00000001, + Move = 0x00000002, + Link = 0x00000004, + Scroll = unchecked((int)0x80000000), + All = unchecked((int)0x80000003) + } +} diff --git a/source/ShiftUI/Enums/DrawItemState.cs b/source/ShiftUI/Enums/DrawItemState.cs new file mode 100644 index 0000000..a838cf5 --- /dev/null +++ b/source/ShiftUI/Enums/DrawItemState.cs @@ -0,0 +1,44 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) +using System; + +namespace ShiftUI { + + [Flags] + public enum DrawItemState { + None = 0, + Selected = 1, + Grayed = 2, + Disabled = 4, + Checked = 8, + Focus = 16, + Default = 32, + HotLight = 64, + Inactive = 128, + NoAccelerator = 256, + NoFocusRect = 512, + ComboBoxEdit = 4096 + } +} + diff --git a/source/ShiftUI/Enums/DrawMode.cs b/source/ShiftUI/Enums/DrawMode.cs new file mode 100644 index 0000000..05e996a --- /dev/null +++ b/source/ShiftUI/Enums/DrawMode.cs @@ -0,0 +1,36 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// +// + +namespace ShiftUI +{ + public enum DrawMode + { + Normal = 0, + OwnerDrawFixed = 1, + OwnerDrawVariable = 2, + } +} + diff --git a/source/ShiftUI/Enums/FlatButtonAppearance.cs b/source/ShiftUI/Enums/FlatButtonAppearance.cs new file mode 100644 index 0000000..9b933d6 --- /dev/null +++ b/source/ShiftUI/Enums/FlatButtonAppearance.cs @@ -0,0 +1,165 @@ +// +// FlatButtonAppearance.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Daniel Nauck +// +// Author: +// Daniel Nauck (dna(at)mono-project(dot)de) + + +using System; +using System.ComponentModel; +using System.Drawing; +using ShiftUI; +using System.Globalization; + +namespace ShiftUI +{ + [TypeConverter (typeof (FlatButtonAppearanceConverter))] + public class FlatButtonAppearance + { + private Color borderColor = Color.Empty; + private int borderSize = 1; + private Color checkedBackColor = Color.Empty; + private Color mouseDownBackColor = Color.Empty; + private Color mouseOverBackColor = Color.Empty; + private ButtonBase owner = null; + + internal FlatButtonAppearance (ButtonBase owner) + { + this.owner = owner; + } + + //[EditorBrowsable(EditorBrowsableState.Always)] + [DefaultValue(typeof(Color), "")] + [NotifyParentProperty(true)] + [Browsable(true)] + public Color BorderColor + { + get { return borderColor; } + set { + if(borderColor == value) + return; + + if (value == Color.Transparent) + throw new NotSupportedException ("Cannot have a Transparent border."); + + borderColor = value; + + if(owner != null) + owner.Invalidate (); + } + } + + //[EditorBrowsable(EditorBrowsableState.Always)] + [DefaultValue(1)] + [NotifyParentProperty(true)] + [Browsable(true)] + public int BorderSize + { + get { return borderSize; } + set { + if(borderSize == value) + return; + + if (value < 0) + throw new ArgumentOutOfRangeException ("value", string.Format ("'{0}' is not a valid value for 'BorderSize'. 'BorderSize' must be greater or equal than {1}.", value, 0)); + + borderSize = value; + + if(owner != null) + owner.Invalidate (); + } + } + + //[EditorBrowsable(EditorBrowsableState.Always)] + [DefaultValue(typeof(Color), "")] + [NotifyParentProperty(true)] + [Browsable(true)] + public Color CheckedBackColor + { + get { return checkedBackColor; } + set { + if(checkedBackColor == value) + return; + + checkedBackColor = value; + + if(owner != null) + owner.Invalidate (); + } + } + + //[EditorBrowsable(EditorBrowsableState.Always)] + [DefaultValue(typeof(Color), "")] + [Browsable(true)] + [NotifyParentProperty(true)] + public Color MouseDownBackColor + { + get { return mouseDownBackColor; } + set { + if(mouseDownBackColor == value) + return; + + mouseDownBackColor = value; + + if(owner != null) + owner.Invalidate (); + } + } + + //[EditorBrowsable(EditorBrowsableState.Always)] + [DefaultValue(typeof(Color), "")] + [NotifyParentProperty(true)] + [Browsable(true)] + public Color MouseOverBackColor + { + get { return mouseOverBackColor; } + set { + if(mouseOverBackColor == value) + return; + + mouseOverBackColor = value; + + if(owner != null) + owner.Invalidate (); + } + } + } + + internal class FlatButtonAppearanceConverter : ExpandableObjectConverter + { + public override object ConvertTo (ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof (string)) + return String.Empty; + return base.ConvertTo (context, culture, value, destinationType); + } + + public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof (string)) + return true; + return base.CanConvertTo (context, destinationType); + } + } +} \ No newline at end of file diff --git a/source/ShiftUI/Enums/FlatStyle.cs b/source/ShiftUI/Enums/FlatStyle.cs new file mode 100644 index 0000000..4a40d5b --- /dev/null +++ b/source/ShiftUI/Enums/FlatStyle.cs @@ -0,0 +1,36 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +namespace ShiftUI { + public enum FlatStyle { + Flat = 0, + Popup = 1, + Standard = 2, + System = 3 + } +} diff --git a/source/ShiftUI/Enums/FlowDirection.cs b/source/ShiftUI/Enums/FlowDirection.cs new file mode 100644 index 0000000..1c5d86f --- /dev/null +++ b/source/ShiftUI/Enums/FlowDirection.cs @@ -0,0 +1,39 @@ +// +// FlowDirection.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum FlowDirection + { + LeftToRight = 0, + TopDown = 1, + RightToLeft = 2, + BottomUp = 3 + } +} diff --git a/source/ShiftUI/Enums/FormBorderStyle.cs b/source/ShiftUI/Enums/FormBorderStyle.cs new file mode 100644 index 0000000..53c3fea --- /dev/null +++ b/source/ShiftUI/Enums/FormBorderStyle.cs @@ -0,0 +1,42 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Ravindra (rkumar@novell.com) +// + + +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ComVisible (true)] + public enum FormBorderStyle + { + None = 0, + FixedSingle = 1, + Fixed3D = 2, + FixedDialog = 3, + Sizable = 4, + FixedToolWindow = 5, + SizableToolWindow = 6 + } +} diff --git a/source/ShiftUI/Enums/FrameStyle.cs b/source/ShiftUI/Enums/FrameStyle.cs new file mode 100644 index 0000000..dabcaf0 --- /dev/null +++ b/source/ShiftUI/Enums/FrameStyle.cs @@ -0,0 +1,34 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +// COMPLETE + +namespace ShiftUI { + public enum FrameStyle { + Dashed = 0, + Thick = 1 + } +} diff --git a/source/ShiftUI/Enums/HorizontalAlignment.cs b/source/ShiftUI/Enums/HorizontalAlignment.cs new file mode 100644 index 0000000..b115fc0 --- /dev/null +++ b/source/ShiftUI/Enums/HorizontalAlignment.cs @@ -0,0 +1,37 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// + + +using System.Runtime.InteropServices; + +namespace ShiftUI { + [ComVisible(true)] + public enum HorizontalAlignment { + Left, + Right, + Center + } +} + diff --git a/source/ShiftUI/Enums/ImageLayout.cs b/source/ShiftUI/Enums/ImageLayout.cs new file mode 100644 index 0000000..1452a53 --- /dev/null +++ b/source/ShiftUI/Enums/ImageLayout.cs @@ -0,0 +1,37 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Author: +// Pedro Martínez Juliá +// + + +namespace ShiftUI { + + public enum ImageLayout { + None = 0, + Tile = 1, + Center = 2, + Stretch = 3, + Zoom = 4 + } + +} diff --git a/source/ShiftUI/Enums/ImeMode.cs b/source/ShiftUI/Enums/ImeMode.cs new file mode 100644 index 0000000..6d2d4e7 --- /dev/null +++ b/source/ShiftUI/Enums/ImeMode.cs @@ -0,0 +1,48 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ComVisible(true)] + public enum ImeMode + { + NoControl = 0, + On = 1, + Off = 2, + Disable = 3, + Hiragana = 4, + Katakana = 5, + KatakanaHalf = 6, + AlphaFull = 7, + Alpha = 8, + HangulFull = 9, + Hangul = 10, + Inherit = -1, + Close = 11, + OnHalf = 12 + } +} diff --git a/source/ShiftUI/Enums/ItemActivation.cs b/source/ShiftUI/Enums/ItemActivation.cs new file mode 100644 index 0000000..b6aeb81 --- /dev/null +++ b/source/ShiftUI/Enums/ItemActivation.cs @@ -0,0 +1,39 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Kevin Rector +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Author: +// Kevin Rector (krector@nazmail.com) +// + + +// COMPLETE + +namespace ShiftUI +{ + public enum ItemActivation + { + OneClick = 1, + Standard = 0, + TwoClick = 2 + } +} diff --git a/source/ShiftUI/Enums/ItemBoundsPortion.cs b/source/ShiftUI/Enums/ItemBoundsPortion.cs new file mode 100644 index 0000000..d2c7de9 --- /dev/null +++ b/source/ShiftUI/Enums/ItemBoundsPortion.cs @@ -0,0 +1,36 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Ravindra (rkumar@novell.com) +// + + +namespace ShiftUI +{ + public enum ItemBoundsPortion + { + Entire = 0, + Icon = 1, + Label = 2, + ItemOnly = 3 + } +} diff --git a/source/ShiftUI/Enums/Keys.cs b/source/ShiftUI/Enums/Keys.cs new file mode 100644 index 0000000..c5d01cb --- /dev/null +++ b/source/ShiftUI/Enums/Keys.cs @@ -0,0 +1,235 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +// COMPLETE + +using System.ComponentModel; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + [Flags] + [ComVisible(true)] + [TypeConverter(typeof(KeysConverter))] + //[Editor ("ShiftUI.Design.ShortcutKeysEditor, " + Consts.AssemblySystem_Design, + //"System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)] + public enum Keys { + None = 0x00000000, + LButton = 0x00000001, + RButton = 0x00000002, + Cancel = 0x00000003, + MButton = 0x00000004, + XButton1 = 0x00000005, + XButton2 = 0x00000006, + Back = 0x00000008, + Tab = 0x00000009, + LineFeed = 0x0000000A, + Clear = 0x0000000C, + Return = 0x0000000D, + Enter = 0x0000000D, + ShiftKey = 0x00000010, + ControlKey = 0x00000011, + Menu = 0x00000012, + Pause = 0x00000013, + CapsLock = 0x00000014, + Capital = 0x00000014, + KanaMode = 0x00000015, + HanguelMode = 0x00000015, + HangulMode = 0x00000015, + JunjaMode = 0x00000017, + FinalMode = 0x00000018, + KanjiMode = 0x00000019, + HanjaMode = 0x00000019, + Escape = 0x0000001B, + IMEConvert = 0x0000001C, + IMENonconvert = 0x0000001D, + IMEAceept = 0x0000001E, + IMEModeChange = 0x0000001F, + Space = 0x00000020, + PageUp = 0x00000021, + Prior = 0x00000021, + PageDown = 0x00000022, + Next = 0x00000022, + End = 0x00000023, + Home = 0x00000024, + Left = 0x00000025, + Up = 0x00000026, + Right = 0x00000027, + Down = 0x00000028, + Select = 0x00000029, + Print = 0x0000002A, + Execute = 0x0000002B, + PrintScreen = 0x0000002C, + Snapshot = 0x0000002C, + Insert = 0x0000002D, + Delete = 0x0000002E, + Help = 0x0000002F, + D0 = 0x00000030, + D1 = 0x00000031, + D2 = 0x00000032, + D3 = 0x00000033, + D4 = 0x00000034, + D5 = 0x00000035, + D6 = 0x00000036, + D7 = 0x00000037, + D8 = 0x00000038, + D9 = 0x00000039, + A = 0x00000041, + B = 0x00000042, + C = 0x00000043, + D = 0x00000044, + E = 0x00000045, + F = 0x00000046, + G = 0x00000047, + H = 0x00000048, + I = 0x00000049, + J = 0x0000004A, + K = 0x0000004B, + L = 0x0000004C, + M = 0x0000004D, + N = 0x0000004E, + O = 0x0000004F, + P = 0x00000050, + Q = 0x00000051, + R = 0x00000052, + S = 0x00000053, + T = 0x00000054, + U = 0x00000055, + V = 0x00000056, + W = 0x00000057, + X = 0x00000058, + Y = 0x00000059, + Z = 0x0000005A, + LWin = 0x0000005B, + RWin = 0x0000005C, + Apps = 0x0000005D, + NumPad0 = 0x00000060, + NumPad1 = 0x00000061, + NumPad2 = 0x00000062, + NumPad3 = 0x00000063, + NumPad4 = 0x00000064, + NumPad5 = 0x00000065, + NumPad6 = 0x00000066, + NumPad7 = 0x00000067, + NumPad8 = 0x00000068, + NumPad9 = 0x00000069, + Multiply = 0x0000006A, + Add = 0x0000006B, + Separator = 0x0000006C, + Subtract = 0x0000006D, + Decimal = 0x0000006E, + Divide = 0x0000006F, + F1 = 0x00000070, + F2 = 0x00000071, + F3 = 0x00000072, + F4 = 0x00000073, + F5 = 0x00000074, + F6 = 0x00000075, + F7 = 0x00000076, + F8 = 0x00000077, + F9 = 0x00000078, + F10 = 0x00000079, + F11 = 0x0000007A, + F12 = 0x0000007B, + F13 = 0x0000007C, + F14 = 0x0000007D, + F15 = 0x0000007E, + F16 = 0x0000007F, + F17 = 0x00000080, + F18 = 0x00000081, + F19 = 0x00000082, + F20 = 0x00000083, + F21 = 0x00000084, + F22 = 0x00000085, + F23 = 0x00000086, + F24 = 0x00000087, + NumLock = 0x00000090, + Scroll = 0x00000091, + LShiftKey = 0x000000A0, + RShiftKey = 0x000000A1, + LControlKey = 0x000000A2, + RControlKey = 0x000000A3, + LMenu = 0x000000A4, + RMenu = 0x000000A5, + BrowserBack = 0x000000A6, + BrowserForward = 0x000000A7, + BrowserRefresh = 0x000000A8, + BrowserStop = 0x000000A9, + BrowserSearch = 0x000000AA, + BrowserFavorites= 0x000000AB, + BrowserHome = 0x000000AC, + VolumeMute = 0x000000AD, + VolumeDown = 0x000000AE, + VolumeUp = 0x000000AF, + MediaNextTrack = 0x000000B0, + MediaPreviousTrack= 0x000000B1, + MediaStop = 0x000000B2, + MediaPlayPause = 0x000000B3, + LaunchMail = 0x000000B4, + SelectMedia = 0x000000B5, + LaunchApplication1= 0x000000B6, + LaunchApplication2= 0x000000B7, + OemSemicolon = 0x000000BA, + Oemplus = 0x000000BB, + Oemcomma = 0x000000BC, + OemMinus = 0x000000BD, + OemPeriod = 0x000000BE, + OemQuestion = 0x000000BF, + Oemtilde = 0x000000C0, + OemOpenBrackets = 0x000000DB, + OemPipe = 0x000000DC, + OemCloseBrackets= 0x000000DD, + OemQuotes = 0x000000DE, + Oem8 = 0x000000DF, + OemBackslash = 0x000000E2, + ProcessKey = 0x000000E5, + Attn = 0x000000F6, + Crsel = 0x000000F7, + Exsel = 0x000000F8, + EraseEof = 0x000000F9, + Play = 0x000000FA, + Zoom = 0x000000FB, + NoName = 0x000000FC, + Pa1 = 0x000000FD, + OemClear = 0x000000FE, + KeyCode = 0x0000FFFF, + Shift = 0x00010000, + Widget = 0x00020000, + Alt = 0x00040000, + Modifiers = unchecked((int)0xFFFF0000), + IMEAccept = 0x0000001E, + Oem1 = 0x000000BA, + Oem102 = 0x000000E2, + Oem2 = 0x000000BF, + Oem3 = 0x000000C0, + Oem4 = 0x000000DB, + Oem5 = 0x000000DC, + Oem6 = 0x000000DD, + Oem7 = 0x000000DE, + Packet = 0x000000E7, + Sleep = 0x0000005F + } +} diff --git a/source/ShiftUI/Enums/LeftRightAlignment.cs b/source/ShiftUI/Enums/LeftRightAlignment.cs new file mode 100644 index 0000000..1ecef56 --- /dev/null +++ b/source/ShiftUI/Enums/LeftRightAlignment.cs @@ -0,0 +1,37 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +// COMPLETE + +using System.Runtime.InteropServices; + +namespace ShiftUI { + [ComVisible(true)] + public enum LeftRightAlignment { + Left = 0, + Right = 1 + } +} diff --git a/source/ShiftUI/Enums/ListViewAlignment.cs b/source/ShiftUI/Enums/ListViewAlignment.cs new file mode 100644 index 0000000..67d8314 --- /dev/null +++ b/source/ShiftUI/Enums/ListViewAlignment.cs @@ -0,0 +1,36 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Ravindra (rkumar@novell.com) +// + + +namespace ShiftUI +{ + public enum ListViewAlignment + { + Default = 0, + Left = 1, + Top = 2, + SnapToGrid = 5 + } +} diff --git a/source/ShiftUI/Enums/MergeAction.cs b/source/ShiftUI/Enums/MergeAction.cs new file mode 100644 index 0000000..24b248a --- /dev/null +++ b/source/ShiftUI/Enums/MergeAction.cs @@ -0,0 +1,40 @@ +// +// MergeAction.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum MergeAction + { + Append = 0, + Insert = 1, + Replace = 2, + Remove = 3, + MatchOnly = 4 + } +} diff --git a/source/ShiftUI/Enums/MessageBoxButtons.cs b/source/ShiftUI/Enums/MessageBoxButtons.cs new file mode 100644 index 0000000..5ea0a8c --- /dev/null +++ b/source/ShiftUI/Enums/MessageBoxButtons.cs @@ -0,0 +1,43 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// +// + + +// COMPLETE + + +namespace ShiftUI +{ + public enum MessageBoxButtons + { + OK = 0, + OKCancel = 1, + AbortRetryIgnore = 2, + YesNoCancel = 3, + YesNo = 4, + RetryCancel = 5, + } +} + diff --git a/source/ShiftUI/Enums/MouseButtons.cs b/source/ShiftUI/Enums/MouseButtons.cs new file mode 100644 index 0000000..9025886 --- /dev/null +++ b/source/ShiftUI/Enums/MouseButtons.cs @@ -0,0 +1,17 @@ +/// +/// Mouse Buttons for mouse events +/// + +using System; + +namespace ShiftUI +{ + public enum MouseButtons + { + None, + Left, + Right, + Middle + } +} + diff --git a/source/ShiftUI/Enums/Orientation.cs b/source/ShiftUI/Enums/Orientation.cs new file mode 100644 index 0000000..0417e9b --- /dev/null +++ b/source/ShiftUI/Enums/Orientation.cs @@ -0,0 +1,39 @@ +// +// ShiftUI.Orientation.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// +// Copyright (C) Novell Inc., 2004 +// +// + + +namespace ShiftUI +{ + + public enum Orientation + { + Horizontal = 0, + Vertical = 1, + } +} diff --git a/source/ShiftUI/Enums/PowerLineStatus.cs b/source/ShiftUI/Enums/PowerLineStatus.cs new file mode 100644 index 0000000..00bbc5a --- /dev/null +++ b/source/ShiftUI/Enums/PowerLineStatus.cs @@ -0,0 +1,38 @@ +// +// PowerLineStatus.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum PowerLineStatus + { + Offline = 0, + Online = 1, + Unknown = 255 + } +} diff --git a/source/ShiftUI/Enums/PowerState.cs b/source/ShiftUI/Enums/PowerState.cs new file mode 100644 index 0000000..70e71d2 --- /dev/null +++ b/source/ShiftUI/Enums/PowerState.cs @@ -0,0 +1,37 @@ +// +// PowerState.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum PowerState + { + Suspend = 0, + Hibernate = 1 + } +} diff --git a/source/ShiftUI/Enums/PowerStatus.cs b/source/ShiftUI/Enums/PowerStatus.cs new file mode 100644 index 0000000..be1d12f --- /dev/null +++ b/source/ShiftUI/Enums/PowerStatus.cs @@ -0,0 +1,72 @@ +// +// PowerStatus.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public class PowerStatus + { + private BatteryChargeStatus battery_charge_status; + private int battery_full_lifetime; + private float battery_life_percent; + private int battery_life_remaining; + private PowerLineStatus power_line_status; + + #region Internal Constructor + internal PowerStatus (BatteryChargeStatus batteryChargeStatus, int batteryFullLifetime, float batteryLifePercent, int batteryLifeRemaining, PowerLineStatus powerLineStatus) + { + this.battery_charge_status = batteryChargeStatus; + this.battery_full_lifetime = batteryFullLifetime; + this.battery_life_percent = batteryLifePercent; + this.battery_life_remaining = batteryLifeRemaining; + this.power_line_status = powerLineStatus; + } + #endregion + + #region Public Properties + public BatteryChargeStatus BatteryChargeStatus { + get { return battery_charge_status; } + } + + public int BatteryFullLifetime { + get { return battery_full_lifetime; } + } + + public float BatteryLifePercent { + get { return battery_life_percent; } + } + + public int BatteryLifeRemaining { + get { return battery_life_remaining; } + } + + public PowerLineStatus PowerLineStatus { + get { return power_line_status; } + } + #endregion + } +} diff --git a/source/ShiftUI/Enums/PreProcessControlState.cs b/source/ShiftUI/Enums/PreProcessControlState.cs new file mode 100644 index 0000000..c6c7bb3 --- /dev/null +++ b/source/ShiftUI/Enums/PreProcessControlState.cs @@ -0,0 +1,38 @@ +// +// PreProcessWidgetstate.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum PreProcessWidgetState + { + MessageProcessed = 0, + MessageNeeded = 1, + MessageNotNeeded = 2 + } +} \ No newline at end of file diff --git a/source/ShiftUI/Enums/ProgressBarStyle.cs b/source/ShiftUI/Enums/ProgressBarStyle.cs new file mode 100644 index 0000000..db0f22b --- /dev/null +++ b/source/ShiftUI/Enums/ProgressBarStyle.cs @@ -0,0 +1,35 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Dennis Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +namespace ShiftUI { + public enum ProgressBarStyle { + Blocks = 0, + Continuous = 1, + Marquee = 2 + } +} diff --git a/source/ShiftUI/Enums/RichTextBoxLanguageOptions.cs b/source/ShiftUI/Enums/RichTextBoxLanguageOptions.cs new file mode 100644 index 0000000..189aee2 --- /dev/null +++ b/source/ShiftUI/Enums/RichTextBoxLanguageOptions.cs @@ -0,0 +1,43 @@ +// +// RichTextBoxLanguageOptions.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + [Flags] + public enum RichTextBoxLanguageOptions + { + AutoKeyboard = 1, + AutoFont = 2, + ImeCancelComplete = 4, + ImeAlwaysSendNotify = 8, + AutoFontSizeAdjust = 16, + UIFonts = 32, + DualFont = 128 + } +} diff --git a/source/ShiftUI/Enums/RichTextBoxSelectionTypes.cs b/source/ShiftUI/Enums/RichTextBoxSelectionTypes.cs new file mode 100644 index 0000000..f6d2a75 --- /dev/null +++ b/source/ShiftUI/Enums/RichTextBoxSelectionTypes.cs @@ -0,0 +1,38 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok +// +// + +// COMPLETE +using System; +namespace ShiftUI { + [Flags] + public enum RichTextBoxSelectionTypes { + Empty = 0x00000000, + Text = 0x00000001, + Object = 0x00000002, + MultiChar = 0x00000004, + MultiObject = 0x00000008 + } +} diff --git a/source/ShiftUI/Enums/RichTextBoxStreamType.cs b/source/ShiftUI/Enums/RichTextBoxStreamType.cs new file mode 100644 index 0000000..543bd9c --- /dev/null +++ b/source/ShiftUI/Enums/RichTextBoxStreamType.cs @@ -0,0 +1,37 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok +// +// + +// COMPLETE + +namespace ShiftUI { + public enum RichTextBoxStreamType { + RichText = 0, + PlainText = 1, + RichNoOleObjs = 2, + TextTextOleObjs = 3, + UnicodePlainText= 4 + } +} diff --git a/source/ShiftUI/Enums/RightToLeft.cs b/source/ShiftUI/Enums/RightToLeft.cs new file mode 100644 index 0000000..f7e0d9b --- /dev/null +++ b/source/ShiftUI/Enums/RightToLeft.cs @@ -0,0 +1,36 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +namespace ShiftUI { + public enum RightToLeft { + No = 0, + Yes = 1, + Inherit = 2 + } +} diff --git a/source/ShiftUI/Enums/RowStyle.cs b/source/ShiftUI/Enums/RowStyle.cs new file mode 100644 index 0000000..6970178 --- /dev/null +++ b/source/ShiftUI/Enums/RowStyle.cs @@ -0,0 +1,71 @@ +// +// RowStyle.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Author: +// Miguel de Icaza (miguel@gnome.org) +// +// (C) 2004 Novell, Inc. +// +using System; + +namespace ShiftUI +{ + public class RowStyle : TableLayoutStyle + { + float height; + + public RowStyle () + { + this.height = 0; + } + + public RowStyle (SizeType sizeType) + { + this.height = 0; + base.SizeType = sizeType; + } + + public RowStyle (SizeType sizeType, float height) + { + if (height < 0) + throw new ArgumentOutOfRangeException("height"); + + base.SizeType = sizeType; + this.height = height; + } + + public float Height { + get { return this.height; } + set { + if (value < 0) + throw new ArgumentOutOfRangeException(); + + if (height != value) { + height = value; + if (base.Owner != null) + base.Owner.PerformLayout (); + } + } + } + } +} diff --git a/source/ShiftUI/Enums/ScreenOrientation.cs b/source/ShiftUI/Enums/ScreenOrientation.cs new file mode 100644 index 0000000..9d55dbd --- /dev/null +++ b/source/ShiftUI/Enums/ScreenOrientation.cs @@ -0,0 +1,39 @@ +// +// ScreenOrientation.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum ScreenOrientation + { + Angle0 = 0, + Angle90 = 1, + Angle180 = 2, + Angle270 = 3 + } +} diff --git a/source/ShiftUI/Enums/ScrollBars.cs b/source/ShiftUI/Enums/ScrollBars.cs new file mode 100644 index 0000000..8552190 --- /dev/null +++ b/source/ShiftUI/Enums/ScrollBars.cs @@ -0,0 +1,36 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +namespace ShiftUI { + public enum ScrollBars { + None = 0, + Horizontal = 1, + Vertical = 2, + Both = 3 + } +} diff --git a/source/ShiftUI/Enums/ScrollOrientation.cs b/source/ShiftUI/Enums/ScrollOrientation.cs new file mode 100644 index 0000000..3ea4cfc --- /dev/null +++ b/source/ShiftUI/Enums/ScrollOrientation.cs @@ -0,0 +1,37 @@ +// +// ScrollOrientation.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum ScrollOrientation + { + HorizontalScroll = 0, + VerticalScroll = 1 + } +} \ No newline at end of file diff --git a/source/ShiftUI/Enums/SearchDirectionHint.cs b/source/ShiftUI/Enums/SearchDirectionHint.cs new file mode 100644 index 0000000..3b06c60 --- /dev/null +++ b/source/ShiftUI/Enums/SearchDirectionHint.cs @@ -0,0 +1,39 @@ +// +// SearchDirectionHint.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum SearchDirectionHint + { + Left = 37, + Up = 38, + Right = 39, + Down = 40 + } +} diff --git a/source/ShiftUI/Enums/SelectionMode.cs b/source/ShiftUI/Enums/SelectionMode.cs new file mode 100644 index 0000000..49eec1f --- /dev/null +++ b/source/ShiftUI/Enums/SelectionMode.cs @@ -0,0 +1,42 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// + +//COMPLETE + +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ComVisible(true)] + public enum SelectionMode + { + None = 0, + One = 1, + MultiSimple = 2, + MultiExtended = 3, + + } +} + diff --git a/source/ShiftUI/Enums/SelectionRange.cs b/source/ShiftUI/Enums/SelectionRange.cs new file mode 100644 index 0000000..27ee453 --- /dev/null +++ b/source/ShiftUI/Enums/SelectionRange.cs @@ -0,0 +1,103 @@ +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// John BouAntoun jba-mono@optusnet.com.au +// + +using System.ComponentModel; +using System; + +namespace ShiftUI { + [TypeConverter(typeof(SelectionRangeConverter))] + public sealed class SelectionRange { + #region local members + + DateTime end; + DateTime start; + + #endregion // local members + + #region public constructors + + // default parameterless construcor, use default values + public SelectionRange () { + end = DateTime.MaxValue.Date; + start = DateTime.MinValue.Date; + } + + // constructor that receives another range, copies it's Start and End values + public SelectionRange (SelectionRange range) { + end = range.End; + start = range.Start; + } + + // constructor that receives two dates, uses the lower of the two as start + public SelectionRange (DateTime lower, DateTime upper) { + if (lower <= upper) { + end = upper.Date; + start = lower.Date; + } else { + end = lower.Date; + start = upper.Date; + } + } + + #endregion // public constructors + + #region public properties + + // end date of this range + public DateTime End { + set { + if (end != value) { + end = value; + } + } + get { + return end; + } + } + + // start date of this range + public DateTime Start { + set { + if (start != value) { + start = value; + } + } + get { + return start; + } + } + + #endregion // public properties + + #region public methods + + public override string ToString() { + return "SelectionRange: Start: " + Start.ToString() + ", End: " + End.ToString(); + } + + #endregion // public methods + } +} diff --git a/source/ShiftUI/Enums/Shortcut.cs b/source/ShiftUI/Enums/Shortcut.cs new file mode 100644 index 0000000..170210d --- /dev/null +++ b/source/ShiftUI/Enums/Shortcut.cs @@ -0,0 +1,191 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// +// + +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ComVisible (true)] + public enum Shortcut + { + Alt0 = 0x040030, + Alt1 = 0x040031, + Alt2 = 0x040032, + Alt3 = 0x040033, + Alt4 = 0x040034, + Alt5 = 0x040035, + Alt6 = 0x040036, + Alt7 = 0x040037, + Alt8 = 0x040038, + Alt9 = 0x040039, + AltBksp = 0x040008, + AltDownArrow = 0x040028, + AltF1 = 0x040070, + AltF10 = 0x040079, + AltF11 = 0x04007A, + AltF12 = 0x04007B, + AltF2 = 0x040071, + AltF3 = 0x040072, + AltF4 = 0x040073, + AltF5 = 0x040074, + AltF6 = 0x040075, + AltF7 = 0x040076, + AltF8 = 0x040077, + AltF9 = 0x040078, + AltLeftArrow = 0x040025, + AltRightArrow = 0x040027, + AltUpArrow = 0x040026, + Ctrl0 = 0x020030, + Ctrl1 = 0x020031, + Ctrl2 = 0x020032, + Ctrl3 = 0x020033, + Ctrl4 = 0x020034, + Ctrl5 = 0x020035, + Ctrl6 = 0x020036, + Ctrl7 = 0x020037, + Ctrl8 = 0x020038, + Ctrl9 = 0x020039, + CtrlA = 0x020041, + CtrlB = 0x020042, + CtrlC = 0x020043, + CtrlD = 0x020044, + CtrlDel = 0x02002E, + CtrlE = 0x020045, + CtrlF = 0x020046, + CtrlF1 = 0x020070, + CtrlF10 = 0x020079, + CtrlF11 = 0x02007A, + CtrlF12 = 0x02007B, + CtrlF2 = 0x020071, + CtrlF3 = 0x020072, + CtrlF4 = 0x020073, + CtrlF5 = 0x020074, + CtrlF6 = 0x020075, + CtrlF7 = 0x020076, + CtrlF8 = 0x020077, + CtrlF9 = 0x020078, + CtrlG = 0x020047, + CtrlH = 0x020048, + CtrlI = 0x020049, + CtrlIns = 0x02002D, + CtrlJ = 0x02004A, + CtrlK = 0x02004B, + CtrlL = 0x02004C, + CtrlM = 0x02004D, + CtrlN = 0x02004E, + CtrlO = 0x02004F, + CtrlP = 0x020050, + CtrlQ = 0x020051, + CtrlR = 0x020052, + CtrlS = 0x020053, + CtrlShift0 = 0x030030, + CtrlShift1 = 0x030031, + CtrlShift2 = 0x030032, + CtrlShift3 = 0x030033, + CtrlShift4 = 0x030034, + CtrlShift5 = 0x030035, + CtrlShift6 = 0x030036, + CtrlShift7 = 0x030037, + CtrlShift8 = 0x030038, + CtrlShift9 = 0x030039, + CtrlShiftA = 0x030041, + CtrlShiftB = 0x030042, + CtrlShiftC = 0x030043, + CtrlShiftD = 0x030044, + CtrlShiftE = 0x030045, + CtrlShiftF = 0x030046, + CtrlShiftF1 = 0x030070, + CtrlShiftF10 = 0x030079, + CtrlShiftF11 = 0x03007A, + CtrlShiftF12 = 0x03007B, + CtrlShiftF2 = 0x030071, + CtrlShiftF3 = 0x030072, + CtrlShiftF4 = 0x030073, + CtrlShiftF5 = 0x030074, + CtrlShiftF6 = 0x030075, + CtrlShiftF7 = 0x030076, + CtrlShiftF8 = 0x030077, + CtrlShiftF9 = 0x030078, + CtrlShiftG = 0x030047, + CtrlShiftH = 0x030048, + CtrlShiftI = 0x030049, + CtrlShiftJ = 0x03004A, + CtrlShiftK = 0x03004B, + CtrlShiftL = 0x03004C, + CtrlShiftM = 0x03004D, + CtrlShiftN = 0x03004E, + CtrlShiftO = 0x03004F, + CtrlShiftP = 0x030050, + CtrlShiftQ = 0x030051, + CtrlShiftR = 0x030052, + CtrlShiftS = 0x030053, + CtrlShiftT = 0x030054, + CtrlShiftU = 0x030055, + CtrlShiftV = 0x030056, + CtrlShiftW = 0x030057, + CtrlShiftX = 0x030058, + CtrlShiftY = 0x030059, + CtrlShiftZ = 0x03005A, + CtrlT = 0x020054, + CtrlU = 0x020055, + CtrlV = 0x020056, + CtrlW = 0x020057, + CtrlX = 0x020058, + CtrlY = 0x020059, + CtrlZ = 0x02005A, + Del = 0x00002E, + F1 = 0x000070, + F10 = 0x000079, + F11 = 0x00007A, + F12 = 0x00007B, + F2 = 0x000071, + F3 = 0x000072, + F4 = 0x000073, + F5 = 0x000074, + F6 = 0x000075, + F7 = 0x000076, + F8 = 0x000077, + F9 = 0x000078, + Ins = 0x00002D, + None = 0x000000, + ShiftDel = 65582, + ShiftF1 = 65648, + ShiftF10 = 65657, + ShiftF11 = 65658, + ShiftF12 = 65659, + ShiftF2 = 65649, + ShiftF3 = 65650, + ShiftF4 = 65651, + ShiftF5 = 65652, + ShiftF6 = 65653, + ShiftF7 = 65654, + ShiftF8 = 65655, + ShiftF9 = 65656, + ShiftIns = 65581, + } +} + + diff --git a/source/ShiftUI/Enums/SizeType.cs b/source/ShiftUI/Enums/SizeType.cs new file mode 100644 index 0000000..3210d82 --- /dev/null +++ b/source/ShiftUI/Enums/SizeType.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Author: +// Miguel de Icaza (miguel@gnome.org) +// +// (C) 2004 Novell, Inc. +// + +namespace ShiftUI { + public enum SizeType { + AutoSize = 0, + Absolute = 1, + Percent = 2 + } +} diff --git a/source/ShiftUI/Enums/SortOrder.cs b/source/ShiftUI/Enums/SortOrder.cs new file mode 100644 index 0000000..a6d1730 --- /dev/null +++ b/source/ShiftUI/Enums/SortOrder.cs @@ -0,0 +1,37 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Author: +// Ravindra (rkumar@novell.com) +// + +// COMPLETE + + +namespace ShiftUI +{ + public enum SortOrder + { + None = 0, + Ascending = 1, + Descending = 2 + } +} diff --git a/source/ShiftUI/Enums/StatusBarPanelAutoSize.cs b/source/ShiftUI/Enums/StatusBarPanelAutoSize.cs new file mode 100644 index 0000000..6a36680 --- /dev/null +++ b/source/ShiftUI/Enums/StatusBarPanelAutoSize.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + +namespace ShiftUI { + + public enum StatusBarPanelAutoSize { + None = 1, + Spring, + Contents + } +} + diff --git a/source/ShiftUI/Enums/StatusBarPanelBorderStyle.cs b/source/ShiftUI/Enums/StatusBarPanelBorderStyle.cs new file mode 100644 index 0000000..453c34d --- /dev/null +++ b/source/ShiftUI/Enums/StatusBarPanelBorderStyle.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +namespace ShiftUI { + + public enum StatusBarPanelBorderStyle { + None = 1, + Raised, + Sunken + } +} diff --git a/source/ShiftUI/Enums/StatusBarPanelStyle.cs b/source/ShiftUI/Enums/StatusBarPanelStyle.cs new file mode 100644 index 0000000..1096d44 --- /dev/null +++ b/source/ShiftUI/Enums/StatusBarPanelStyle.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +namespace ShiftUI { + + public enum StatusBarPanelStyle { + Text = 1, + OwnerDraw + } +} + diff --git a/source/ShiftUI/Enums/TabAlignment.cs b/source/ShiftUI/Enums/TabAlignment.cs new file mode 100644 index 0000000..f42b60b --- /dev/null +++ b/source/ShiftUI/Enums/TabAlignment.cs @@ -0,0 +1,35 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +namespace ShiftUI { + + public enum TabAlignment { + Top, + Bottom, + Left, + Right + } +} + diff --git a/source/ShiftUI/Enums/TabAppearance.cs b/source/ShiftUI/Enums/TabAppearance.cs new file mode 100644 index 0000000..a12514a --- /dev/null +++ b/source/ShiftUI/Enums/TabAppearance.cs @@ -0,0 +1,34 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +namespace ShiftUI { + + public enum TabAppearance { + Normal, + Buttons, + FlatButtons + } +} + diff --git a/source/ShiftUI/Enums/TabControlAction.cs b/source/ShiftUI/Enums/TabControlAction.cs new file mode 100644 index 0000000..960b729 --- /dev/null +++ b/source/ShiftUI/Enums/TabControlAction.cs @@ -0,0 +1,39 @@ +// +// TabControlAction.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum TabControlAction + { + Selecting = 0, + Selected = 1, + Deselecting = 2, + Deselected = 3 + } +} diff --git a/source/ShiftUI/Enums/TabDrawMode.cs b/source/ShiftUI/Enums/TabDrawMode.cs new file mode 100644 index 0000000..3964943 --- /dev/null +++ b/source/ShiftUI/Enums/TabDrawMode.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +namespace ShiftUI { + + public enum TabDrawMode { + Normal, + OwnerDrawFixed + } +} + diff --git a/source/ShiftUI/Enums/TabSizeMode.cs b/source/ShiftUI/Enums/TabSizeMode.cs new file mode 100644 index 0000000..6f423c7 --- /dev/null +++ b/source/ShiftUI/Enums/TabSizeMode.cs @@ -0,0 +1,34 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +namespace ShiftUI { + + public enum TabSizeMode { + Normal, + FillToRight, + Fixed + } +} + diff --git a/source/ShiftUI/Enums/TextDataFormat.cs b/source/ShiftUI/Enums/TextDataFormat.cs new file mode 100644 index 0000000..c375d90 --- /dev/null +++ b/source/ShiftUI/Enums/TextDataFormat.cs @@ -0,0 +1,40 @@ +// +// TextDataFormat.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum TextDataFormat + { + Text = 0, + UnicodeText = 1, + Rtf = 2, + Html = 3, + CommaSeparatedValue = 4 + } +} diff --git a/source/ShiftUI/Enums/TextImageRelation.cs b/source/ShiftUI/Enums/TextImageRelation.cs new file mode 100644 index 0000000..d90c76a --- /dev/null +++ b/source/ShiftUI/Enums/TextImageRelation.cs @@ -0,0 +1,40 @@ +// +// TextImageRelation.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum TextImageRelation + { + Overlay = 0, + ImageAboveText = 1, + TextAboveImage = 2, + ImageBeforeText = 4, + TextBeforeImage = 8 + } +} diff --git a/source/ShiftUI/Enums/TickStyle.cs b/source/ShiftUI/Enums/TickStyle.cs new file mode 100644 index 0000000..48a92ee --- /dev/null +++ b/source/ShiftUI/Enums/TickStyle.cs @@ -0,0 +1,40 @@ +// +// ShiftUI.TickStyle.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// +// Copyright (C) Novell Inc., 2004 +// +// + + +namespace ShiftUI +{ + public enum TickStyle + { + None = 0, + TopLeft = 1, + BottomRight = 2, + Both = 3, + } +} diff --git a/source/ShiftUI/Enums/TreeNodeStates.cs b/source/ShiftUI/Enums/TreeNodeStates.cs new file mode 100644 index 0000000..1acd56a --- /dev/null +++ b/source/ShiftUI/Enums/TreeNodeStates.cs @@ -0,0 +1,45 @@ +// +// TreeNodeStates.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + [Flags] + public enum TreeNodeStates + { + Selected = 1, + Grayed = 2, + Checked = 8, + Focused = 16, + Default = 32, + Hot = 64, + Marked = 128, + Indeterminate = 256, + ShowKeyboardCues = 512 + } +} diff --git a/source/ShiftUI/Enums/TreeViewAction.cs b/source/ShiftUI/Enums/TreeViewAction.cs new file mode 100644 index 0000000..63d9ffb --- /dev/null +++ b/source/ShiftUI/Enums/TreeViewAction.cs @@ -0,0 +1,35 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + +namespace ShiftUI { + + public enum TreeViewAction { + Unknown, + ByKeyboard, + ByMouse, + Collapse, + Expand + } +} + diff --git a/source/ShiftUI/Enums/TreeViewDrawMode.cs b/source/ShiftUI/Enums/TreeViewDrawMode.cs new file mode 100644 index 0000000..de01a4c --- /dev/null +++ b/source/ShiftUI/Enums/TreeViewDrawMode.cs @@ -0,0 +1,38 @@ +// +// TreeViewDrawMode.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum TreeViewDrawMode + { + Normal = 0, + OwnerDrawText = 1, + OwnerDrawAll = 2 + } +} \ No newline at end of file diff --git a/source/ShiftUI/Enums/TreeViewHitTestLocations.cs b/source/ShiftUI/Enums/TreeViewHitTestLocations.cs new file mode 100644 index 0000000..9ec253a --- /dev/null +++ b/source/ShiftUI/Enums/TreeViewHitTestLocations.cs @@ -0,0 +1,50 @@ +// +// TreeViewHitTestLocations.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [Flags] + [ComVisible(true)] + public enum TreeViewHitTestLocations + { + None = 1, + Image = 2, + Label = 4, + Indent = 8, + PlusMinus = 16, + RightOfLabel = 32, + StateImage = 64, + AboveClientArea = 256, + BelowClientArea = 512, + RightOfClientArea = 1024, + LeftOfClientArea = 2048 + } +} diff --git a/source/ShiftUI/Enums/UnhandledExceptionMode.cs b/source/ShiftUI/Enums/UnhandledExceptionMode.cs new file mode 100644 index 0000000..059228b --- /dev/null +++ b/source/ShiftUI/Enums/UnhandledExceptionMode.cs @@ -0,0 +1,38 @@ +// +// UnhandledExceptionMode.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum UnhandledExceptionMode + { + Automatic = 0, + ThrowException = 1, + CatchException = 2 + } +} diff --git a/source/ShiftUI/Enums/ValidationConstraints.cs b/source/ShiftUI/Enums/ValidationConstraints.cs new file mode 100644 index 0000000..cc3d721 --- /dev/null +++ b/source/ShiftUI/Enums/ValidationConstraints.cs @@ -0,0 +1,42 @@ +// +// ValidationConstraints.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + [Flags] + public enum ValidationConstraints + { + None = 0, + Selectable = 1, + Enabled = 2, + Visible = 4, + TabStop = 8, + ImmediateChildren = 16 + } +} diff --git a/source/ShiftUI/Enums/View.cs b/source/ShiftUI/Enums/View.cs new file mode 100644 index 0000000..c2cf407 --- /dev/null +++ b/source/ShiftUI/Enums/View.cs @@ -0,0 +1,37 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Ravindra (rkumar@novell.com) +// + + +namespace ShiftUI +{ + public enum View + { + LargeIcon = 0, + Details = 1, + SmallIcon = 2, + List = 3, + Tile = 4 + } +} diff --git a/source/ShiftUI/Events/AccessibleEvents.cs b/source/ShiftUI/Events/AccessibleEvents.cs new file mode 100644 index 0000000..90a9e82 --- /dev/null +++ b/source/ShiftUI/Events/AccessibleEvents.cs @@ -0,0 +1,74 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +// COMPLETE + +namespace ShiftUI { + public enum AccessibleEvents { + SystemSound = 1, + SystemAlert = 2, + SystemForeground = 3, + SystemMenuStart = 4, + SystemMenuEnd = 5, + SystemMenuPopupStart = 6, + SystemMenuPopupEnd = 7, + SystemCaptureStart = 8, + SystemCaptureEnd = 9, + SystemMoveSizeStart = 10, + SystemMoveSizeEnd = 11, + SystemContextHelpStart = 12, + SystemContextHelpEnd = 13, + SystemDragDropStart = 14, + SystemDragDropEnd = 15, + SystemDialogStart = 16, + SystemDialogEnd = 17, + SystemScrollingStart = 18, + SystemScrollingEnd = 19, + SystemSwitchStart = 20, + SystemSwitchEnd = 21, + SystemMinimizeStart = 22, + SystemMinimizeEnd = 23, + Create = 32768, + Destroy = 32769, + Show = 32770, + Hide = 32771, + Reorder = 32772, + Focus = 32773, + Selection = 32774, + SelectionAdd = 32775, + SelectionRemove = 32776, + SelectionWithin = 32777, + StateChange = 32778, + LocationChange = 32779, + NameChange = 32780, + DescriptionChange = 32781, + ValueChange = 32782, + ParentChange = 32783, + HelpChange = 32784, + DefaultActionChange = 32785, + AcceleratorChange = 32786 + } +} diff --git a/source/ShiftUI/Events/BindingCompleteEventArgs.cs b/source/ShiftUI/Events/BindingCompleteEventArgs.cs new file mode 100644 index 0000000..69f8f22 --- /dev/null +++ b/source/ShiftUI/Events/BindingCompleteEventArgs.cs @@ -0,0 +1,101 @@ +// +// BindingCompleteEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.ComponentModel; +using System; + +namespace ShiftUI +{ + public class BindingCompleteEventArgs : CancelEventArgs + { + private Binding binding; + private BindingCompleteState state; + private BindingCompleteContext context; + private string error_text; + private Exception exception; + + #region Public Constructors + public BindingCompleteEventArgs(Binding binding, BindingCompleteState state, BindingCompleteContext context) + : this (binding, state, context, String.Empty, null, false) + { + } + + public BindingCompleteEventArgs(Binding binding, BindingCompleteState state, BindingCompleteContext context, string errorText) + : this (binding, state, context, errorText, null, false) + { + } + + public BindingCompleteEventArgs(Binding binding, BindingCompleteState state, BindingCompleteContext context, string errorText, Exception exception) + : this (binding, state, context, errorText, exception, false) + { + } + + public BindingCompleteEventArgs(Binding binding, BindingCompleteState state, BindingCompleteContext context, string errorText, Exception exception, bool cancel) + : base (cancel) + { + this.binding = binding; + this.state = state; + this.context = context; + this.error_text = errorText; + this.exception = exception; + } + #endregion // Public Constructors + + #region Public Instance Properties + public Binding Binding { + get { return this.binding; } + } + + public BindingCompleteContext BindingCompleteContext { + get { return this.context; } + } + + public BindingCompleteState BindingCompleteState { + get { return this.state; } + } + + public string ErrorText { + get { return this.error_text; } + } + + public Exception Exception { + get { return this.exception; } + } + #endregion // Public Instance Properties + + internal void SetErrorText (string error_text) + { + this.error_text = error_text; + } + + internal void SetException (Exception exception) + { + this.exception = exception; + } + } +} diff --git a/source/ShiftUI/Events/BindingCompleteEventHandler.cs b/source/ShiftUI/Events/BindingCompleteEventHandler.cs new file mode 100644 index 0000000..695ad24 --- /dev/null +++ b/source/ShiftUI/Events/BindingCompleteEventHandler.cs @@ -0,0 +1,32 @@ +// +// BindingCompleteEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void BindingCompleteEventHandler(object sender, BindingCompleteEventArgs e); +} diff --git a/source/ShiftUI/Events/BindingManagerDataErrorEventArgs.cs b/source/ShiftUI/Events/BindingManagerDataErrorEventArgs.cs new file mode 100644 index 0000000..e7fae6a --- /dev/null +++ b/source/ShiftUI/Events/BindingManagerDataErrorEventArgs.cs @@ -0,0 +1,50 @@ +// +// BindingManagerDataErrorEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + public class BindingManagerDataErrorEventArgs : EventArgs + { + + private Exception exception; + + #region Public Constructors + public BindingManagerDataErrorEventArgs(Exception exception) : base () + { + this.exception = exception; + } + #endregion // Public Constructors + + #region Public Instance Properties + public Exception Exception { + get { return this.exception; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/BindingManagerDataErrorEventHandler.cs b/source/ShiftUI/Events/BindingManagerDataErrorEventHandler.cs new file mode 100644 index 0000000..e138980 --- /dev/null +++ b/source/ShiftUI/Events/BindingManagerDataErrorEventHandler.cs @@ -0,0 +1,32 @@ +// +// BindingManagerDataErrorEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void BindingManagerDataErrorEventHandler(object sender, BindingManagerDataErrorEventArgs e); +} diff --git a/source/ShiftUI/Events/CacheVirtualItemsEventArgs.cs b/source/ShiftUI/Events/CacheVirtualItemsEventArgs.cs new file mode 100644 index 0000000..e8ddf64 --- /dev/null +++ b/source/ShiftUI/Events/CacheVirtualItemsEventArgs.cs @@ -0,0 +1,56 @@ +// +// CacheVirtualItemsEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + public class CacheVirtualItemsEventArgs : EventArgs + { + + private int start_index; + private int end_index; + + #region Public Constructors + public CacheVirtualItemsEventArgs(int startIndex, int endIndex) : base () + { + this.start_index = startIndex; + this.end_index = endIndex; + } + #endregion // Public Constructors + + #region Public Instance Properties + public int StartIndex { + get { return this.start_index; } + } + + public int EndIndex { + get { return this.end_index; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/CacheVirtualItemsEventHandler.cs b/source/ShiftUI/Events/CacheVirtualItemsEventHandler.cs new file mode 100644 index 0000000..8100d4d --- /dev/null +++ b/source/ShiftUI/Events/CacheVirtualItemsEventHandler.cs @@ -0,0 +1,32 @@ +// +// CacheVirtualItemsEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void CacheVirtualItemsEventHandler(object sender, CacheVirtualItemsEventArgs e); +} diff --git a/source/ShiftUI/Events/ContentsResizedEventArgs.cs b/source/ShiftUI/Events/ContentsResizedEventArgs.cs new file mode 100644 index 0000000..d233416 --- /dev/null +++ b/source/ShiftUI/Events/ContentsResizedEventArgs.cs @@ -0,0 +1,52 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +using System.Drawing; +using System; + +namespace ShiftUI { + public class ContentsResizedEventArgs : EventArgs { + #region Local Variables + Rectangle rect; + #endregion // Local Variables + + #region Public Constructors + public ContentsResizedEventArgs(Rectangle newRectangle) { + rect = newRectangle; + } + #endregion // Public Constructors + + #region Public Instance Properties + public Rectangle NewRectangle { + get { + return rect; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/ContentsResizedEventHandler.cs b/source/ShiftUI/Events/ContentsResizedEventHandler.cs new file mode 100644 index 0000000..764d2db --- /dev/null +++ b/source/ShiftUI/Events/ContentsResizedEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +namespace ShiftUI { + public delegate void ContentsResizedEventHandler(object sender, ContentsResizedEventArgs e); +} diff --git a/source/ShiftUI/Events/ConvertEventArgs.cs b/source/ShiftUI/Events/ConvertEventArgs.cs new file mode 100644 index 0000000..da2dfb0 --- /dev/null +++ b/source/ShiftUI/Events/ConvertEventArgs.cs @@ -0,0 +1,61 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE +using System; + +namespace ShiftUI { + public class ConvertEventArgs : EventArgs { + private object object_value; + private Type desired_type; + + #region Public Constructors + public ConvertEventArgs(object value, Type desiredType) { + this.object_value=value; + this.desired_type=desiredType; + } + #endregion // Public Constructors + + #region Public Instance Properties + public Type DesiredType { + get { + return this.desired_type; + } + } + + public object Value { + get { + return this.object_value; + } + + set { + this.object_value=value; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/ConvertEventHandler.cs b/source/ShiftUI/Events/ConvertEventHandler.cs new file mode 100644 index 0000000..54c9188 --- /dev/null +++ b/source/ShiftUI/Events/ConvertEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +namespace ShiftUI { + public delegate void ConvertEventHandler (object sender, ConvertEventArgs e); +} diff --git a/source/ShiftUI/Events/DateBoldEventArgs.cs b/source/ShiftUI/Events/DateBoldEventArgs.cs new file mode 100644 index 0000000..3280375 --- /dev/null +++ b/source/ShiftUI/Events/DateBoldEventArgs.cs @@ -0,0 +1,70 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE +using System; + +namespace ShiftUI { + public class DateBoldEventArgs : EventArgs { + #region Local Variables + private int size; + private DateTime start; + private int[] days_to_bold; + #endregion // Local Variables + + #region Internal Constructor + DateBoldEventArgs(DateTime start, int size, int[] daysToBold) { + this.start = start; + this.size = size; + this.days_to_bold = daysToBold; + } + #endregion + + #region Public Instance Properties + public int[] DaysToBold { + get { + return days_to_bold; + } + + set { + days_to_bold = value; + } + } + + public int Size { + get { + return size; + } + } + + public DateTime StartDate { + get { + return start; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/DateBoldEventHandler.cs b/source/ShiftUI/Events/DateBoldEventHandler.cs new file mode 100644 index 0000000..c3f3185 --- /dev/null +++ b/source/ShiftUI/Events/DateBoldEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +namespace ShiftUI { + public delegate void DateBoldEventHandler (object sender, DateBoldEventArgs e); +} diff --git a/source/ShiftUI/Events/DateRangeEventArgs.cs b/source/ShiftUI/Events/DateRangeEventArgs.cs new file mode 100644 index 0000000..2b22d7f --- /dev/null +++ b/source/ShiftUI/Events/DateRangeEventArgs.cs @@ -0,0 +1,67 @@ +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// John BouAntoun jba-mono@optusnet.com.au +// + +using System; +using System.Drawing; + +namespace ShiftUI { + public class DateRangeEventArgs : EventArgs { + #region local members + + DateTime end; + DateTime start; + + #endregion // local members + + #region public constructors + + // constructor that receives two dates, uses the lower of the two as start + public DateRangeEventArgs (DateTime start, DateTime end) { + this.start = start; + this.end = end; + } + + #endregion // public constructors + + #region public properties + + // end date of this range + public DateTime End { + get { + return end; + } + } + + // start date of this range + public DateTime Start { + get { + return start; + } + } + + #endregion // public properties + } +} diff --git a/source/ShiftUI/Events/DateRangeEventHandler.cs b/source/ShiftUI/Events/DateRangeEventHandler.cs new file mode 100644 index 0000000..c8bb443 --- /dev/null +++ b/source/ShiftUI/Events/DateRangeEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// John BouAntoun jba-mono@optusnet.com.au +// + +// COMPLETE + +namespace ShiftUI { + // event handler for when a daterange event is fired (datechanged or dateselected) + public delegate void DateRangeEventHandler(object sender, DateRangeEventArgs e); +} diff --git a/source/ShiftUI/Events/DrawItemEventArgs.cs b/source/ShiftUI/Events/DrawItemEventArgs.cs new file mode 100644 index 0000000..d9131f2 --- /dev/null +++ b/source/ShiftUI/Events/DrawItemEventArgs.cs @@ -0,0 +1,101 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +using System; +using System.Drawing; + +namespace ShiftUI { + + public class DrawItemEventArgs : EventArgs { + + Graphics graphics; + Font font; + Rectangle rect; + int index; + DrawItemState state; + Color fore_color; + Color back_color; + + public DrawItemEventArgs (Graphics graphics, Font font, + Rectangle rect, int index, DrawItemState state) : + this (graphics, font, rect, index, state, + Widget.DefaultForeColor, Widget.DefaultBackColor) + { + + } + + public DrawItemEventArgs (Graphics graphics, Font font, + Rectangle rect, int index, DrawItemState state, + Color foreColor, Color backColor) + { + this.graphics = graphics; + this.font = font; + this.rect = rect; + this.index = index; + this.state = state; + this.fore_color = foreColor; + this.back_color = backColor; + } + + public Graphics Graphics { + get { return graphics; } + } + + public Font Font { + get { return font; } + } + + public Rectangle Bounds { + get { return rect; } + } + + public int Index { + get { return index; } + } + + public DrawItemState State { + get { return state; } + } + + public Color BackColor { + get { return back_color; } + } + + public Color ForeColor { + get { return fore_color; } + } + + public virtual void DrawBackground () + { + ThemeEngine.Current.DrawOwnerDrawBackground (this); + } + + public virtual void DrawFocusRectangle () + { + ThemeEngine.Current.DrawOwnerDrawFocusRectangle (this); + } + } +} + diff --git a/source/ShiftUI/Events/DrawItemEventHandler.cs b/source/ShiftUI/Events/DrawItemEventHandler.cs new file mode 100644 index 0000000..5223b0e --- /dev/null +++ b/source/ShiftUI/Events/DrawItemEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// +// +// COMPLETE + +namespace ShiftUI +{ + public delegate void DrawItemEventHandler (object sender, DrawItemEventArgs e); +} diff --git a/source/ShiftUI/Events/DrawListViewColumnHeaderEventArgs.cs b/source/ShiftUI/Events/DrawListViewColumnHeaderEventArgs.cs new file mode 100644 index 0000000..67ee147 --- /dev/null +++ b/source/ShiftUI/Events/DrawListViewColumnHeaderEventArgs.cs @@ -0,0 +1,133 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Alan McGovern (alan.mcgovern@gmail.com) +// + + +using System.Drawing; +using System.Drawing.Drawing2D; +using System; + +namespace ShiftUI +{ + public class DrawListViewColumnHeaderEventArgs : EventArgs + { + #region Private Fields + + private Color backColor; + private Rectangle bounds; + private int columnIndex; + private bool drawDefault; + private Font font; + private Color foreColor; + private Graphics graphics; + private ColumnHeader header; + private ListViewItemStates state; + + #endregion Private Fields + + + #region Properties + + public Color BackColor { + get { return backColor; } + } + + public Rectangle Bounds { + get { return bounds; } + } + + public int ColumnIndex { + get { return columnIndex; } + } + + public bool DrawDefault { + get { return drawDefault; } + set { drawDefault = value; } + } + + public Font Font { + get { return font; } + } + + public Color ForeColor { + get { return foreColor; } + } + + public Graphics Graphics { + get { return graphics; } + } + + public ColumnHeader Header { + get { return header; } + } + + public ListViewItemStates State { + get { return state; } + } + + #endregion Properties + + + #region Constructors + + public DrawListViewColumnHeaderEventArgs(Graphics graphics, Rectangle bounds, int columnIndex, + ColumnHeader header, ListViewItemStates state, Color foreColor, + Color backColor, Font font) + { + this.backColor = backColor; + this.bounds = bounds; + this.columnIndex = columnIndex; + this.font = font; + this.foreColor = foreColor; + this.graphics = graphics; + this.header = header; + this.state = state; + } + + #endregion Constructors + + + #region Methods + + public void DrawBackground () + { + // Always draw a non-pushed button + ThemeEngine.Current.CPDrawButton (graphics, bounds, ButtonState.Normal); + } + + public void DrawText () + { + DrawText (TextFormatFlags.EndEllipsis | TextFormatFlags.SingleLine); + } + + public void DrawText (TextFormatFlags flags) + { + // Text adjustments + Rectangle text_bounds = new Rectangle (bounds.X + 8, bounds.Y, bounds.Width - 13, bounds.Height); + TextRenderer.DrawText (graphics, header.Text, font, text_bounds, foreColor, flags); + } + + #endregion Methods + } +} diff --git a/source/ShiftUI/Events/DrawListViewColumnHeaderEventHandler.cs b/source/ShiftUI/Events/DrawListViewColumnHeaderEventHandler.cs new file mode 100644 index 0000000..f1dae4a --- /dev/null +++ b/source/ShiftUI/Events/DrawListViewColumnHeaderEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Rolf Bjarne Kvinge +// +// +// COMPLETE + +namespace ShiftUI +{ + public delegate void DrawListViewColumnHeaderEventHandler(object sender, DrawListViewColumnHeaderEventArgs e); +} diff --git a/source/ShiftUI/Events/DrawListViewItemEventArgs.cs b/source/ShiftUI/Events/DrawListViewItemEventArgs.cs new file mode 100644 index 0000000..346d64b --- /dev/null +++ b/source/ShiftUI/Events/DrawListViewItemEventArgs.cs @@ -0,0 +1,116 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Alan McGovern (alan.mcgovern@gmail.com) +// + + +using System.Drawing; +using System; + +namespace ShiftUI +{ + public class DrawListViewItemEventArgs : EventArgs + { + #region Private Fields + + private Rectangle bounds; + private bool drawDefault; + private Graphics graphics; + private ListViewItem item; + private int itemIndex; + private ListViewItemStates state; + + #endregion Private Fields + + + #region Properties + + public bool DrawDefault { + get { return drawDefault; } + set { drawDefault = value; } + } + + public Rectangle Bounds { + get { return bounds; } + } + + public Graphics Graphics { + get { return graphics; } + } + + public ListViewItem Item { + get { return item; } + } + + public int ItemIndex { + get { return itemIndex; } + } + + public ListViewItemStates State { + get { return state; } + } + + #endregion Properties + + + #region Constructors + + public DrawListViewItemEventArgs (Graphics graphics, ListViewItem item, + Rectangle bounds, int itemIndex, ListViewItemStates state) + { + this.graphics = graphics; + this.item = item; + this.bounds = bounds; + this.itemIndex = itemIndex; + this.state = state; + } + + #endregion Constructors + + + #region Public Methods + + public void DrawBackground () + { + graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (item.BackColor), bounds); + } + + public void DrawFocusRectangle () + { + if ((state & ListViewItemStates.Focused) != 0) + ThemeEngine.Current.CPDrawFocusRectangle (graphics, bounds, item.ListView.ForeColor, item.ListView.BackColor); + } + + public void DrawText () + { + DrawText (TextFormatFlags.Default); + } + + public void DrawText (TextFormatFlags flags) + { + TextRenderer.DrawText (graphics, item.Text, item.Font, bounds, item.ForeColor, flags); + } + + #endregion Public Methods + } +} diff --git a/source/ShiftUI/Events/DrawListViewItemEventHandler.cs b/source/ShiftUI/Events/DrawListViewItemEventHandler.cs new file mode 100644 index 0000000..d54a185 --- /dev/null +++ b/source/ShiftUI/Events/DrawListViewItemEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Rolf Bjarne Kvinge +// +// +// COMPLETE + +namespace ShiftUI +{ + public delegate void DrawListViewItemEventHandler (object sender, DrawListViewItemEventArgs e); +} diff --git a/source/ShiftUI/Events/DrawListViewSubItemEventArgs.cs b/source/ShiftUI/Events/DrawListViewSubItemEventArgs.cs new file mode 100644 index 0000000..9c509d0 --- /dev/null +++ b/source/ShiftUI/Events/DrawListViewSubItemEventArgs.cs @@ -0,0 +1,140 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Alan McGovern (alan.mcgovern@gmail.com) +// + + +using System.Drawing; +using System; + +namespace ShiftUI +{ + public class DrawListViewSubItemEventArgs : EventArgs + { + #region Private Fields + + private Rectangle bounds; + private int columnIndex; + private bool drawDefault; + private Graphics graphics; + private ColumnHeader header; + private ListViewItem item; + private int itemIndex; + private ListViewItemStates itemState; + private ListViewItem.ListViewSubItem subItem; + + #endregion Private Fields + + + #region Properties + + public Rectangle Bounds { + get { return bounds; } + } + + public int ColumnIndex { + get { return columnIndex; } + } + + public bool DrawDefault { + get { return drawDefault; } + set { drawDefault = value; } + } + + public Graphics Graphics { + get { return graphics; } + } + + public ColumnHeader Header { + get { return header; } + } + + public ListViewItem Item { + get { return item; } + } + + public int ItemIndex { + get { return itemIndex; } + } + + public ListViewItemStates ItemState { + get { return itemState; } + } + + public ListViewItem.ListViewSubItem SubItem { + get { return this.subItem; } + } + + #endregion Properties + + + #region Constructors + + public DrawListViewSubItemEventArgs(Graphics graphics, Rectangle bounds, + ListViewItem item, ListViewItem.ListViewSubItem subItem, + int itemIndex, int columnIndex, + ColumnHeader header, ListViewItemStates itemState) + { + this.bounds = bounds; + this.columnIndex = columnIndex; + this.graphics = graphics; + this.header = header; + this.item = item; + this.itemIndex = itemIndex; + this.itemState = itemState; + this.subItem = subItem; + } + + #endregion Constructors + + + #region Public Methods + + public void DrawBackground () + { + graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (subItem.BackColor), bounds); + } + + public void DrawFocusRectangle (Rectangle bounds) + { + if ((itemState & ListViewItemStates.Focused) != 0) { + Rectangle rect = new Rectangle (bounds.X + 1, bounds.Y + 1, bounds.Width - 1, bounds.Height - 1); + ThemeEngine.Current.CPDrawFocusRectangle (graphics, rect, subItem.ForeColor, subItem.BackColor); + } + } + + public void DrawText () + { + DrawText (TextFormatFlags.EndEllipsis | TextFormatFlags.HorizontalCenter); + } + + public void DrawText (TextFormatFlags flags) + { + // Text adjustments + Rectangle text_bounds = new Rectangle (bounds.X + 8, bounds.Y, bounds.Width - 13, bounds.Height); + TextRenderer.DrawText (graphics, subItem.Text, subItem.Font, text_bounds, subItem.ForeColor, flags); + } + + #endregion Public Methods + } +} diff --git a/source/ShiftUI/Events/DrawListViewSubItemEventHandler.cs b/source/ShiftUI/Events/DrawListViewSubItemEventHandler.cs new file mode 100644 index 0000000..cd43c92 --- /dev/null +++ b/source/ShiftUI/Events/DrawListViewSubItemEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Rolf Bjarne Kvinge +// +// +// COMPLETE + +namespace ShiftUI +{ + public delegate void DrawListViewSubItemEventHandler (object sender, DrawListViewSubItemEventArgs e); +} diff --git a/source/ShiftUI/Events/DrawTreeNodeEventArgs.cs b/source/ShiftUI/Events/DrawTreeNodeEventArgs.cs new file mode 100644 index 0000000..82b9784 --- /dev/null +++ b/source/ShiftUI/Events/DrawTreeNodeEventArgs.cs @@ -0,0 +1,80 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Chambers +// +// Authors: +// Jonathan Chambers (joncham@gmail.com) +// + + +using System.Drawing; +using System; + +namespace ShiftUI +{ + public class DrawTreeNodeEventArgs : EventArgs + { + private Rectangle bounds; + private bool draw_default; + private Graphics graphics; + private TreeNode node; + private TreeNodeStates state; + + #region Public Constructors + public DrawTreeNodeEventArgs (Graphics graphics, TreeNode node, + Rectangle bounds, TreeNodeStates state) + { + this.bounds = bounds; + this.draw_default = false; + this.graphics = graphics; + this.node = node; + this.state = state; + } + #endregion // Public Constructors + + #region Public Instance Properties + public Rectangle Bounds + { + get { return bounds; } + } + + public bool DrawDefault + { + get { return draw_default; } + set { draw_default = value; } + } + + public Graphics Graphics + { + get { return graphics; } + } + + public TreeNode Node + { + get { return node; } + } + + public TreeNodeStates State + { + get { return state; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/DrawTreeNodeEventHandler.cs b/source/ShiftUI/Events/DrawTreeNodeEventHandler.cs new file mode 100644 index 0000000..a737183 --- /dev/null +++ b/source/ShiftUI/Events/DrawTreeNodeEventHandler.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// + + +using System; + +namespace ShiftUI { + + public delegate void DrawTreeNodeEventHandler (object sender, DrawTreeNodeEventArgs e); + +} diff --git a/source/ShiftUI/Events/GiveFeedbackEventArgs.cs b/source/ShiftUI/Events/GiveFeedbackEventArgs.cs new file mode 100644 index 0000000..50c5c11 --- /dev/null +++ b/source/ShiftUI/Events/GiveFeedbackEventArgs.cs @@ -0,0 +1,63 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + [ComVisible(true)] + public class GiveFeedbackEventArgs : EventArgs { + internal DragDropEffects effect; + internal bool use_default_cursors; + + #region Public Constructors + public GiveFeedbackEventArgs(DragDropEffects effect, bool useDefaultCursors) { + this.effect=effect; + this.use_default_cursors=useDefaultCursors; + } + #endregion // Public Constructors + + #region Public Instance Properties + public DragDropEffects Effect { + get { + return this.effect; + } + } + + public bool UseDefaultCursors { + get { + return this.use_default_cursors; + } + + set { + this.use_default_cursors=value; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/GiveFeedbackEventHandler.cs b/source/ShiftUI/Events/GiveFeedbackEventHandler.cs new file mode 100644 index 0000000..84c0710 --- /dev/null +++ b/source/ShiftUI/Events/GiveFeedbackEventHandler.cs @@ -0,0 +1,32 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +namespace ShiftUI { + public delegate void GiveFeedbackEventHandler (object sender, GiveFeedbackEventArgs e); +} diff --git a/source/ShiftUI/Events/HelpEventArgs.cs b/source/ShiftUI/Events/HelpEventArgs.cs new file mode 100644 index 0000000..916cf12 --- /dev/null +++ b/source/ShiftUI/Events/HelpEventArgs.cs @@ -0,0 +1,65 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +using System.Drawing; + +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + [ComVisible(true)] + public class HelpEventArgs : EventArgs { + private Point mouse_position; + private bool event_handled; + + #region Public Constructors + public HelpEventArgs(System.Drawing.Point mousePos) { + this.mouse_position=mousePos; + this.event_handled=false; + } + #endregion // Public Constructors + + #region Public Instance Properties + public bool Handled { + get { + return this.event_handled; + } + + set { + this.event_handled=value; + } + } + + public Point MousePos { + get { + return this.mouse_position; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/HelpEventHandler.cs b/source/ShiftUI/Events/HelpEventHandler.cs new file mode 100644 index 0000000..8333d2a --- /dev/null +++ b/source/ShiftUI/Events/HelpEventHandler.cs @@ -0,0 +1,30 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + +// COMPLETE + +namespace ShiftUI { + public delegate void HelpEventHandler (object sender, HelpEventArgs hlpevent); +} diff --git a/source/ShiftUI/Events/InputLanguageChangedEventArgs.cs b/source/ShiftUI/Events/InputLanguageChangedEventArgs.cs new file mode 100644 index 0000000..fe3115d --- /dev/null +++ b/source/ShiftUI/Events/InputLanguageChangedEventArgs.cs @@ -0,0 +1,73 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +using System.Globalization; +using System; + +namespace ShiftUI { + public class InputLanguageChangedEventArgs : EventArgs { + private CultureInfo culture; + private byte charset; + private InputLanguage input_language; + + #region Public Constructors + public InputLanguageChangedEventArgs(System.Globalization.CultureInfo culture, byte charSet) { + this.culture = culture; + this.charset = charSet; + this.input_language = InputLanguage.FromCulture(culture); + } + + public InputLanguageChangedEventArgs(InputLanguage inputLanguage, byte charSet) { + this.culture = inputLanguage.Culture; + this.charset = charSet; + this.input_language = inputLanguage; + } + #endregion // Public Constructors + + #region Public Instance Properties + public byte CharSet { + get { + return this.charset; + } + } + + public CultureInfo Culture { + get { + return this.culture; + } + } + + public InputLanguage InputLanguage { + get { + return this.input_language; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/InputLanguageChangedEventHandler.cs b/source/ShiftUI/Events/InputLanguageChangedEventHandler.cs new file mode 100644 index 0000000..a4a981a --- /dev/null +++ b/source/ShiftUI/Events/InputLanguageChangedEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +// COMPLETE + +namespace ShiftUI { + public delegate void InputLanguageChangedEventHandler(object sender, InputLanguageChangedEventArgs e); +} diff --git a/source/ShiftUI/Events/InputLanguageChangingEventArgs.cs b/source/ShiftUI/Events/InputLanguageChangingEventArgs.cs new file mode 100644 index 0000000..1ca5f44 --- /dev/null +++ b/source/ShiftUI/Events/InputLanguageChangingEventArgs.cs @@ -0,0 +1,74 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +using System; +using System.ComponentModel; +using System.Globalization; + +namespace ShiftUI { + public class InputLanguageChangingEventArgs : System.ComponentModel.CancelEventArgs { + private CultureInfo culture; + private bool system_charset; + private InputLanguage input_language; + + #region Public Constructors + public InputLanguageChangingEventArgs (System.Globalization.CultureInfo culture, bool sysCharSet) { + this.culture = culture; + this.system_charset = sysCharSet; + this.input_language = InputLanguage.FromCulture(culture); + } + + public InputLanguageChangingEventArgs (InputLanguage inputLanguage, bool sysCharSet) { + this.culture = inputLanguage.Culture; + this.system_charset = sysCharSet; + this.input_language = inputLanguage; + } + #endregion // Public Constructors + + #region Public Instance Properties + public bool SysCharSet { + get { + return this.system_charset; + } + } + + public CultureInfo Culture { + get { + return this.culture; + } + } + + public InputLanguage InputLanguage { + get { + return this.input_language; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/InputLanguageChangingEventHandler.cs b/source/ShiftUI/Events/InputLanguageChangingEventHandler.cs new file mode 100644 index 0000000..2127a6c --- /dev/null +++ b/source/ShiftUI/Events/InputLanguageChangingEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +namespace ShiftUI { + public delegate void InputLanguageChangingEventHandler(object sender, InputLanguageChangingEventArgs e); +} diff --git a/source/ShiftUI/Events/InvalidateEventArgs.cs b/source/ShiftUI/Events/InvalidateEventArgs.cs new file mode 100644 index 0000000..f92a9f6 --- /dev/null +++ b/source/ShiftUI/Events/InvalidateEventArgs.cs @@ -0,0 +1,50 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +using System.Drawing; +using System; + +namespace ShiftUI { + public class InvalidateEventArgs : EventArgs { + private Rectangle invalidated_rectangle; + + #region Public Constructors + public InvalidateEventArgs(System.Drawing.Rectangle invalidRect) { + this.invalidated_rectangle=invalidRect; + } + #endregion // Public Constructors + + #region Public Instance Properties + public Rectangle InvalidRect { + get { + return this.invalidated_rectangle; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/InvalidateEventHandler.cs b/source/ShiftUI/Events/InvalidateEventHandler.cs new file mode 100644 index 0000000..395e64f --- /dev/null +++ b/source/ShiftUI/Events/InvalidateEventHandler.cs @@ -0,0 +1,32 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +namespace ShiftUI { + public delegate void InvalidateEventHandler (object sender, InvalidateEventArgs e); +} diff --git a/source/ShiftUI/Events/ItemChangedEventArgs.cs b/source/ShiftUI/Events/ItemChangedEventArgs.cs new file mode 100644 index 0000000..ceafef4 --- /dev/null +++ b/source/ShiftUI/Events/ItemChangedEventArgs.cs @@ -0,0 +1,50 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Author: +// Ravindra (rkumar@novell.com) +// + +// COMPLETE + + +using System; + +namespace ShiftUI +{ + public class ItemChangedEventArgs : EventArgs + { + private int index; + + #region Internal Constructors + internal ItemChangedEventArgs (int index) + { + this.index = index; + } + #endregion // Internal Constructors + + #region Public Instance Properties + public int Index { + get { return index; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/ItemChangedEventHandler.cs b/source/ShiftUI/Events/ItemChangedEventHandler.cs new file mode 100644 index 0000000..2b3e136 --- /dev/null +++ b/source/ShiftUI/Events/ItemChangedEventHandler.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Author: +// Ravindra (rkumar@novell.com) +// + + +// COMPLETE + + +namespace ShiftUI +{ + public delegate void ItemChangedEventHandler (object sender, ItemChangedEventArgs e); +} diff --git a/source/ShiftUI/Events/ItemCheckEventArgs.cs b/source/ShiftUI/Events/ItemCheckEventArgs.cs new file mode 100644 index 0000000..6296c5a --- /dev/null +++ b/source/ShiftUI/Events/ItemCheckEventArgs.cs @@ -0,0 +1,65 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Author: +// Ravindra (rkumar@novell.com) +// + +// COMPLETE + + +using System; +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ComVisible (true)] + public class ItemCheckEventArgs : EventArgs + { + private CheckState currentValue; + private int index; + private CheckState newValue; + + #region Public Constructors + public ItemCheckEventArgs (int index, CheckState newCheckValue, CheckState currentValue) + { + this.index = index; + this.newValue = newCheckValue; + this.currentValue = currentValue; + } + #endregion // Public Constructors + + #region Public Instance Properties + public CheckState CurrentValue { + get { return currentValue; } + } + + public int Index { + get { return index; } + } + + public CheckState NewValue { + get { return newValue; } + set { newValue = value; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/ItemCheckEventHandler.cs b/source/ShiftUI/Events/ItemCheckEventHandler.cs new file mode 100644 index 0000000..b88e66c --- /dev/null +++ b/source/ShiftUI/Events/ItemCheckEventHandler.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Author: +// Ravindra (rkumar@novell.com) +// + + +// COMPLETE + + +namespace ShiftUI +{ + public delegate void ItemCheckEventHandler (object sender, ItemCheckEventArgs e); +} diff --git a/source/ShiftUI/Events/ItemCheckedEventArgs.cs b/source/ShiftUI/Events/ItemCheckedEventArgs.cs new file mode 100644 index 0000000..b6f2309 --- /dev/null +++ b/source/ShiftUI/Events/ItemCheckedEventArgs.cs @@ -0,0 +1,49 @@ +// +// ItemCheckedEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + public class ItemCheckedEventArgs : EventArgs + { + private ListViewItem item; + + #region Public Constructors + public ItemCheckedEventArgs (ListViewItem item) : base () + { + this.item = item; + } + #endregion // Public Constructors + + #region Public Instance Properties + public ListViewItem Item { + get { return this.item; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/ItemCheckedEventHandler.cs b/source/ShiftUI/Events/ItemCheckedEventHandler.cs new file mode 100644 index 0000000..ebc45e9 --- /dev/null +++ b/source/ShiftUI/Events/ItemCheckedEventHandler.cs @@ -0,0 +1,32 @@ +// +// ItemCheckedEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ItemCheckedEventHandler (object sender, ItemCheckedEventArgs e); +} diff --git a/source/ShiftUI/Events/ItemDragEventArgs.cs b/source/ShiftUI/Events/ItemDragEventArgs.cs new file mode 100644 index 0000000..4104c81 --- /dev/null +++ b/source/ShiftUI/Events/ItemDragEventArgs.cs @@ -0,0 +1,63 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Author: +// Ravindra (rkumar@novell.com) +// + +// COMPLETE + + +using System; +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ComVisible (true)] + public class ItemDragEventArgs : EventArgs + { + private MouseButtons button; + private object item; + + #region Public Constructors + public ItemDragEventArgs (MouseButtons button) + { + this.button = button; + } + + public ItemDragEventArgs (MouseButtons button, object item) + { + this.button = button; + this.item = item; + } + #endregion // Public Constructors + + #region Public Instance Properties + public MouseButtons Button { + get { return button; } + } + + public object Item { + get { return item; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/ItemDragEventHandler.cs b/source/ShiftUI/Events/ItemDragEventHandler.cs new file mode 100644 index 0000000..5c7f35d --- /dev/null +++ b/source/ShiftUI/Events/ItemDragEventHandler.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Author: +// Ravindra (rkumar@novell.com) +// + + +// COMPLETE + + +namespace ShiftUI +{ + public delegate void ItemDragEventHandler (object sender, ItemDragEventArgs e); +} diff --git a/source/ShiftUI/Events/LabelEditEventArgs.cs b/source/ShiftUI/Events/LabelEditEventArgs.cs new file mode 100644 index 0000000..23ac0a0 --- /dev/null +++ b/source/ShiftUI/Events/LabelEditEventArgs.cs @@ -0,0 +1,73 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Author: +// Ravindra (rkumar@novell.com) +// + + +// COMPLETE + + +using System; + +namespace ShiftUI +{ + public class LabelEditEventArgs : EventArgs + { + private int item; + private string label; + private bool cancelEdit = false; + + #region Public Constructors + public LabelEditEventArgs (int item) + { + this.item = item; + } + + public LabelEditEventArgs (int item, string label) + { + this.item = item; + this.label = label; + } + #endregion // Public Constructors + + #region Public Instance Properties + public bool CancelEdit { + get { return cancelEdit; } + set { cancelEdit = value; } + } + + public int Item { + get { return item; } + } + + public string Label { + get { return label; } + } + #endregion // Public Instance Properties + + internal void SetLabel (string label) + { + this.label = label; + } + } +} diff --git a/source/ShiftUI/Events/LabelEditEventHandler.cs b/source/ShiftUI/Events/LabelEditEventHandler.cs new file mode 100644 index 0000000..dbdef96 --- /dev/null +++ b/source/ShiftUI/Events/LabelEditEventHandler.cs @@ -0,0 +1,34 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Author: +// Ravindra (rkumar@novell.com) +// + + + +// COMPLETE + + +namespace ShiftUI +{ + public delegate void LabelEditEventHandler (object sender, LabelEditEventArgs e); +} diff --git a/source/ShiftUI/Events/LayoutEventArgs.cs b/source/ShiftUI/Events/LayoutEventArgs.cs new file mode 100644 index 0000000..7599987 --- /dev/null +++ b/source/ShiftUI/Events/LayoutEventArgs.cs @@ -0,0 +1,70 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +using System.ComponentModel; +using System; + +namespace ShiftUI { + public sealed class LayoutEventArgs : EventArgs { + private Widget affected_control; + private string affected_property; + private IComponent affected_component; + + #region Public Constructors + public LayoutEventArgs(Widget affectedControl, string affectedProperty) { + this.affected_control = affectedControl; + this.affected_property = affectedProperty; + } + + public LayoutEventArgs (IComponent affectedComponent, string affectedProperty) + { + this.affected_component = affectedComponent; + this.affected_property = affectedProperty; + } + #endregion // Public Constructors + + #region Public Instance Properties + public IComponent AffectedComponent { + get { return this.affected_component; } + } + + public Widget AffectedControl { + get { + return this.affected_control; + } + } + + public string AffectedProperty { + get { + return this.affected_property; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/LayoutEventHandler.cs b/source/ShiftUI/Events/LayoutEventHandler.cs new file mode 100644 index 0000000..82e8630 --- /dev/null +++ b/source/ShiftUI/Events/LayoutEventHandler.cs @@ -0,0 +1,32 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +namespace ShiftUI { + public delegate void LayoutEventHandler (object sender, LayoutEventArgs e); +} diff --git a/source/ShiftUI/Events/ListControlConvertEventArgs.cs b/source/ShiftUI/Events/ListControlConvertEventArgs.cs new file mode 100644 index 0000000..fb40872 --- /dev/null +++ b/source/ShiftUI/Events/ListControlConvertEventArgs.cs @@ -0,0 +1,50 @@ +// +// ListControlConvertEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + public class ListWidgetConvertEventArgs : ConvertEventArgs + { + private object list_item; + + #region Public Constructors + public ListWidgetConvertEventArgs (object value, Type desiredType, object listItem) + : base (value, desiredType) + { + this.list_item = listItem; + } + #endregion // Public Constructors + + #region Public Instance Properties + public object ListItem { + get { return this.list_item; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/ListControlConvertEventHandler.cs b/source/ShiftUI/Events/ListControlConvertEventHandler.cs new file mode 100644 index 0000000..847e0b9 --- /dev/null +++ b/source/ShiftUI/Events/ListControlConvertEventHandler.cs @@ -0,0 +1,32 @@ +// +// ListControlConvertEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ListWidgetConvertEventHandler (object sender, ListWidgetConvertEventArgs e); +} diff --git a/source/ShiftUI/Events/MeasureItemEventArgs.cs b/source/ShiftUI/Events/MeasureItemEventArgs.cs new file mode 100644 index 0000000..eca771b --- /dev/null +++ b/source/ShiftUI/Events/MeasureItemEventArgs.cs @@ -0,0 +1,77 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// +// + +using System.Drawing; +using System; + +namespace ShiftUI +{ + public class MeasureItemEventArgs : EventArgs + { + private Graphics graphics; + private int index; + private int itemHeight; + private int itemWidth = 0; + + public MeasureItemEventArgs (Graphics graphics, int index) + { + this.graphics = graphics; + this.index = index; + this.itemHeight = 0; + } + + public MeasureItemEventArgs (Graphics graphics, int index, int itemHeight) + { + this.graphics = graphics; + this.index = index; + this.itemHeight = itemHeight; + } + + #region Public Properties + + public Graphics Graphics { + get { return graphics;} + } + + public int Index { + get { return index;} + } + + public int ItemHeight { + get { return itemHeight;} + set { itemHeight = value;} + } + + public int ItemWidth { + get { return itemWidth;} + set { itemWidth = value;} + } + + #endregion Public Properties + } + +} + diff --git a/source/ShiftUI/Events/MeasureItemEventHandler.cs b/source/ShiftUI/Events/MeasureItemEventHandler.cs new file mode 100644 index 0000000..55ccade --- /dev/null +++ b/source/ShiftUI/Events/MeasureItemEventHandler.cs @@ -0,0 +1,30 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// +// + +namespace ShiftUI +{ + public delegate void MeasureItemEventHandler (object sender, MeasureItemEventArgs e); +} diff --git a/source/ShiftUI/Events/NodeLabelEditEventArgs.cs b/source/ShiftUI/Events/NodeLabelEditEventArgs.cs new file mode 100644 index 0000000..5d28858 --- /dev/null +++ b/source/ShiftUI/Events/NodeLabelEditEventArgs.cs @@ -0,0 +1,71 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +using System; + +namespace ShiftUI { + + public class NodeLabelEditEventArgs : EventArgs { + + private TreeNode node; + private string label; + private bool cancel; + + public NodeLabelEditEventArgs (TreeNode node) + { + this.node = node; + } + + public NodeLabelEditEventArgs (TreeNode node, string label) : this (node) + { + this.label = label; + } + + public bool CancelEdit { + get { return cancel; } + set { + cancel = value; + + if (cancel) + node.EndEdit (true); + } + } + + public TreeNode Node { + get { return node; } + } + + public string Label { + get { return label; } + } + + internal void SetLabel (string label) + { + this.label = label; + } + } + +} + diff --git a/source/ShiftUI/Events/NodeLabelEditEventHandler.cs b/source/ShiftUI/Events/NodeLabelEditEventHandler.cs new file mode 100644 index 0000000..b9de87e --- /dev/null +++ b/source/ShiftUI/Events/NodeLabelEditEventHandler.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +using System; + +namespace ShiftUI { + + public delegate void NodeLabelEditEventHandler (object sender, NodeLabelEditEventArgs e); + +} + diff --git a/source/ShiftUI/Events/PreviewKeyDownEventArgs.cs b/source/ShiftUI/Events/PreviewKeyDownEventArgs.cs new file mode 100644 index 0000000..4da9775 --- /dev/null +++ b/source/ShiftUI/Events/PreviewKeyDownEventArgs.cs @@ -0,0 +1,79 @@ +// +// PreviewKeyDownEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + public class PreviewKeyDownEventArgs : EventArgs + { + private Keys key_data; + private bool is_input_key; + + #region Public Constructors + public PreviewKeyDownEventArgs (Keys keyData) : base () + { + this.key_data = keyData; + } + #endregion // Public Constructors + + #region Public Instance Properties + public bool Alt { + get { return (this.key_data & Keys.Alt) != 0; } + } + + public bool Widget { + get { return (this.key_data & Keys.Widget) != 0; } + } + + public bool IsInputKey { + get { return this.is_input_key; } + set { this.is_input_key = value; } + } + + public Keys KeyCode { + get { return (this.key_data & Keys.KeyCode); } + } + + public Keys KeyData { + get { return this.key_data; } + } + + public int KeyValue { + get { return Convert.ToInt32 (this.key_data); } + } + + public Keys Modifiers { + get { return (this.key_data & Keys.Modifiers); } + } + + public bool Shift { + get { return (this.key_data & Keys.Shift) != 0; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/PreviewKeyDownEventHandler.cs b/source/ShiftUI/Events/PreviewKeyDownEventHandler.cs new file mode 100644 index 0000000..88c4cf9 --- /dev/null +++ b/source/ShiftUI/Events/PreviewKeyDownEventHandler.cs @@ -0,0 +1,32 @@ +// +// PreviewKeyDownEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void PreviewKeyDownEventHandler (object sender, PreviewKeyDownEventArgs e); +} diff --git a/source/ShiftUI/Events/QueryAccessibilityHelpEventArgs.cs b/source/ShiftUI/Events/QueryAccessibilityHelpEventArgs.cs new file mode 100644 index 0000000..4f0c1a6 --- /dev/null +++ b/source/ShiftUI/Events/QueryAccessibilityHelpEventArgs.cs @@ -0,0 +1,85 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + [ComVisible(true)] + public class QueryAccessibilityHelpEventArgs : EventArgs { + private string help_namespace; + private string help_string; + private string help_keyword; + + #region Public Constructors + public QueryAccessibilityHelpEventArgs() { + this.help_namespace = null; + this.help_string = null; + this.help_keyword = null; + } + + public QueryAccessibilityHelpEventArgs(string helpNamespace, string helpString, string helpKeyword) { + this.help_namespace=helpNamespace; + this.help_string=helpString; + this.help_keyword=helpKeyword; + } + #endregion // Public Constructors + + #region Public Instance Properties + public string HelpKeyword { + get { + return this.help_keyword; + } + + set { + this.help_keyword = value; + } + } + + public string HelpNamespace { + get { + return this.help_namespace; + } + + set { + this.help_namespace = value; + } + } + + public string HelpString { + get { + return this.help_string; + } + + set { + this.help_string = value; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/QueryAccessibilityHelpEventHandler.cs b/source/ShiftUI/Events/QueryAccessibilityHelpEventHandler.cs new file mode 100644 index 0000000..b55372f --- /dev/null +++ b/source/ShiftUI/Events/QueryAccessibilityHelpEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +namespace ShiftUI { + public delegate void QueryAccessibilityHelpEventHandler (object sender, QueryAccessibilityHelpEventArgs e); +} diff --git a/source/ShiftUI/Events/QueryContinueDragEventArgs.cs b/source/ShiftUI/Events/QueryContinueDragEventArgs.cs new file mode 100644 index 0000000..e11cbec --- /dev/null +++ b/source/ShiftUI/Events/QueryContinueDragEventArgs.cs @@ -0,0 +1,72 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + [ComVisible(true)] + public class QueryContinueDragEventArgs : EventArgs { + internal int key_state; + internal bool escape_pressed; + internal DragAction drag_action; + + #region Public Constructors + public QueryContinueDragEventArgs(int keyState, bool escapePressed, DragAction action) { + this.key_state = keyState; + this.escape_pressed = escapePressed; + this.drag_action = action; + } + #endregion // Public Constructors + + #region Public Instance Properties + public DragAction Action { + get { + return this.drag_action; + } + + set { + this.drag_action=value; + } + } + + public bool EscapePressed { + get { + return this.escape_pressed; + } + } + + public int KeyState { + get { + return this.key_state; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/QueryContinueDragEventHandler.cs b/source/ShiftUI/Events/QueryContinueDragEventHandler.cs new file mode 100644 index 0000000..e20e29c --- /dev/null +++ b/source/ShiftUI/Events/QueryContinueDragEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +namespace ShiftUI { + public delegate void QueryContinueDragEventHandler (object sender, QueryContinueDragEventArgs e); +} diff --git a/source/ShiftUI/Events/RetrieveVirtualItemEventArgs.cs b/source/ShiftUI/Events/RetrieveVirtualItemEventArgs.cs new file mode 100644 index 0000000..ba3c499 --- /dev/null +++ b/source/ShiftUI/Events/RetrieveVirtualItemEventArgs.cs @@ -0,0 +1,55 @@ +// +// RetrieveVirtualItemEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + public class RetrieveVirtualItemEventArgs : EventArgs + { + private ListViewItem item; + private int item_index; + + #region Public Constructors + public RetrieveVirtualItemEventArgs (int itemIndex) : base () + { + this.item_index = itemIndex; + } + #endregion // Public Constructors + + #region Public Instance Properties + public ListViewItem Item { + get { return this.item; } + set { this.item = value; } + } + + public int ItemIndex { + get { return this.item_index; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/RetrieveVirtualItemEventHandler.cs b/source/ShiftUI/Events/RetrieveVirtualItemEventHandler.cs new file mode 100644 index 0000000..3c4e05d --- /dev/null +++ b/source/ShiftUI/Events/RetrieveVirtualItemEventHandler.cs @@ -0,0 +1,32 @@ +// +// RetrieveVirtualItemEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void RetrieveVirtualItemEventHandler (object sender, RetrieveVirtualItemEventArgs e); +} diff --git a/source/ShiftUI/Events/ScrollEventArgs.cs b/source/ShiftUI/Events/ScrollEventArgs.cs new file mode 100644 index 0000000..52f87e5 --- /dev/null +++ b/source/ShiftUI/Events/ScrollEventArgs.cs @@ -0,0 +1,95 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + [ComVisible(true)] + public class ScrollEventArgs : EventArgs { + #region Local Variables + private ScrollEventType type; + private int new_value; + private int old_value; + private ScrollOrientation scroll_orientation; + #endregion + + #region Public Constructors + public ScrollEventArgs(ScrollEventType type, int newValue) : + this (type, -1, newValue, ScrollOrientation.HorizontalScroll) + { + } + + public ScrollEventArgs (ScrollEventType type, int oldValue, int newValue) : + this (type, oldValue, newValue, ScrollOrientation.HorizontalScroll) + { + } + + public ScrollEventArgs (ScrollEventType type, int newValue, ScrollOrientation scroll) : + this (type, -1, newValue, scroll) + { + } + + + public ScrollEventArgs (ScrollEventType type, int oldValue, int newValue, ScrollOrientation scroll) + { + this.new_value = newValue; + this.old_value = oldValue; + this.scroll_orientation = scroll; + this.type = type; + } + + #endregion // Public Constructors + + #region Public Instance Properties + public int NewValue { + get { + return new_value; + } + + set { + new_value = value; + } + } + + public int OldValue { + get { return old_value; } + } + + public ScrollOrientation ScrollOrientation { + get { return scroll_orientation; } + } + + public ScrollEventType Type { + get { + return type; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/ScrollEventHandler.cs b/source/ShiftUI/Events/ScrollEventHandler.cs new file mode 100644 index 0000000..ba4e1c6 --- /dev/null +++ b/source/ShiftUI/Events/ScrollEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +namespace ShiftUI { + public delegate void ScrollEventHandler(object sender, ScrollEventArgs e); +} diff --git a/source/ShiftUI/Events/ScrollEventType.cs b/source/ShiftUI/Events/ScrollEventType.cs new file mode 100644 index 0000000..1ba8a6f --- /dev/null +++ b/source/ShiftUI/Events/ScrollEventType.cs @@ -0,0 +1,44 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +using System.Runtime.InteropServices; + +namespace ShiftUI { + [ComVisible(true)] + public enum ScrollEventType { + SmallDecrement = 0, + SmallIncrement = 1, + LargeDecrement = 2, + LargeIncrement = 3, + ThumbPosition = 4, + ThumbTrack = 5, + First = 6, + Last = 7, + EndScroll = 8 + } +} diff --git a/source/ShiftUI/Events/SearchForVirtualItemEventArgs.cs b/source/ShiftUI/Events/SearchForVirtualItemEventArgs.cs new file mode 100644 index 0000000..42a9bdc --- /dev/null +++ b/source/ShiftUI/Events/SearchForVirtualItemEventArgs.cs @@ -0,0 +1,97 @@ +// +// SearchForVirtualItemEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System; + +namespace ShiftUI +{ + public class SearchForVirtualItemEventArgs : EventArgs + { + private SearchDirectionHint direction; + private bool include_sub_items_in_search; + private int index; + private bool is_prefix_search; + private bool is_text_search; + private int start_index; + private Point starting_point; + private string text; + + #region Public Constructors + public SearchForVirtualItemEventArgs (bool isTextSearch, bool isPrefixSearch, + bool includeSubItemsInSearch, string text, Point startingPoint, + SearchDirectionHint direction, int startIndex) : base () + { + this.is_text_search = isTextSearch; + this.is_prefix_search = isPrefixSearch; + this.include_sub_items_in_search = includeSubItemsInSearch; + this.text = text; + this.starting_point = startingPoint; + this.direction = direction; + this.start_index = startIndex; + this.index = -1; + } + #endregion // Public Constructors + + #region Public Instance Properties + public SearchDirectionHint Direction { + get { return this.direction; } + } + + public bool IncludeSubItemsInSearch { + get { return this.include_sub_items_in_search; } + } + + public int Index { + get { return this.index; } + set { this.index = value; } + } + + public bool IsPrefixSearch { + get { return this.is_prefix_search; } + } + + public bool IsTextSearch { + get { return this.is_text_search; } + } + + public int StartIndex { + get { return this.start_index; } + } + + public Point StartingPoint { + get { return this.starting_point; } + } + + public string Text { + get { return this.text; } + } + + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/SearchForVirtualItemEventHandler.cs b/source/ShiftUI/Events/SearchForVirtualItemEventHandler.cs new file mode 100644 index 0000000..12acc83 --- /dev/null +++ b/source/ShiftUI/Events/SearchForVirtualItemEventHandler.cs @@ -0,0 +1,32 @@ +// +// SearchForVirtualItemEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void SearchForVirtualItemEventHandler (object sender, SearchForVirtualItemEventArgs e); +} diff --git a/source/ShiftUI/Events/SplitterCancelEventArgs.cs b/source/ShiftUI/Events/SplitterCancelEventArgs.cs new file mode 100644 index 0000000..332e1b0 --- /dev/null +++ b/source/ShiftUI/Events/SplitterCancelEventArgs.cs @@ -0,0 +1,70 @@ +// +// SplitterCancelEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.ComponentModel; + +namespace ShiftUI +{ + public class SplitterCancelEventArgs : CancelEventArgs + { + private int mouse_cursor_x; + private int mouse_cursor_y; + private int split_x; + private int split_y; + + #region Public Constructors + public SplitterCancelEventArgs (int mouseCursorX, int mouseCursorY, int splitX, int splitY) : base() + { + this.mouse_cursor_x = mouseCursorX; + this.mouse_cursor_y = mouseCursorY; + this.split_x = splitX; + this.split_y = splitY; + } + #endregion // Public Constructors + + #region Public Instance Properties + public int MouseCursorX { + get { return this.mouse_cursor_x; } + } + + public int MouseCursorY { + get { return this.mouse_cursor_y; } + } + + public int SplitX { + get { return this.split_x; } + set { this.split_x = value; } + } + + public int SplitY { + get { return this.split_y; } + set { this.split_y = value; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/SplitterCancelEventHandler.cs b/source/ShiftUI/Events/SplitterCancelEventHandler.cs new file mode 100644 index 0000000..630637b --- /dev/null +++ b/source/ShiftUI/Events/SplitterCancelEventHandler.cs @@ -0,0 +1,32 @@ +// +// SplitterCancelEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void SplitterCancelEventHandler (object sender, SplitterCancelEventArgs e); +} diff --git a/source/ShiftUI/Events/SplitterEventArgs.cs b/source/ShiftUI/Events/SplitterEventArgs.cs new file mode 100644 index 0000000..be522a7 --- /dev/null +++ b/source/ShiftUI/Events/SplitterEventArgs.cs @@ -0,0 +1,79 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Aleksandar Dezelin adezelin@beotel.net +// Peter Dennis Bartok pbartok@novell.com +// + +using System; +using System.Runtime.InteropServices; + +namespace ShiftUI { + [ComVisible(true)] + public class SplitterEventArgs : EventArgs + { + #region Private fields + + internal int split_x; + internal int split_y; + internal int x; + internal int y; + + #endregion + + #region Constructors + + public SplitterEventArgs(int x, int y, int splitX, int splitY) + { + this.x = x; + this.y = y; + SplitX = splitX; + SplitY = splitY; + } + + #endregion + + #region Properties + + public int SplitX { + get { return split_x; } + set { split_x = value; } + } + + public int SplitY { + get { return split_y; } + set { split_y = value; } + } + + public int X { + get { return x; } + } + + public int Y { + get { return y; } + } + + #endregion + } +} + + diff --git a/source/ShiftUI/Events/SplitterEventHandler.cs b/source/ShiftUI/Events/SplitterEventHandler.cs new file mode 100644 index 0000000..002dc43 --- /dev/null +++ b/source/ShiftUI/Events/SplitterEventHandler.cs @@ -0,0 +1,32 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Aleksandar Dezelin adezelin@beotel.net +// + +using System; + +namespace ShiftUI +{ + public delegate void SplitterEventHandler(object sender, SplitterEventArgs e); +} + diff --git a/source/ShiftUI/Events/StatusBarDrawItemEventArgs.cs b/source/ShiftUI/Events/StatusBarDrawItemEventArgs.cs new file mode 100644 index 0000000..675a1e6 --- /dev/null +++ b/source/ShiftUI/Events/StatusBarDrawItemEventArgs.cs @@ -0,0 +1,57 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +using System; +using System.Drawing; + + +namespace ShiftUI { + + public class StatusBarDrawItemEventArgs : DrawItemEventArgs { + + private StatusBarPanel panel; + + public StatusBarDrawItemEventArgs (Graphics g, Font font, Rectangle r, + int itemId, DrawItemState itemState, StatusBarPanel panel) : + this (g, font, r, itemId, itemState, panel, Widget.DefaultForeColor, + Widget.DefaultBackColor) + + { + } + + public StatusBarDrawItemEventArgs (Graphics g, Font font, Rectangle r, + int itemId, DrawItemState itemState, StatusBarPanel panel, + Color foreColor, Color backColor) : base (g, font, r, + itemId, itemState) + { + this.panel = panel; + } + + public StatusBarPanel Panel { + get { return panel; } + } + } +} + diff --git a/source/ShiftUI/Events/StatusBarDrawItemEventHandler.cs b/source/ShiftUI/Events/StatusBarDrawItemEventHandler.cs new file mode 100644 index 0000000..b1a48f0 --- /dev/null +++ b/source/ShiftUI/Events/StatusBarDrawItemEventHandler.cs @@ -0,0 +1,36 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +using System; +using System.Drawing; + +namespace ShiftUI { + + public delegate void StatusBarDrawItemEventHandler (object sender, + StatusBarDrawItemEventArgs sbdevent); + +} + + diff --git a/source/ShiftUI/Events/StatusBarPanelClickEventArgs.cs b/source/ShiftUI/Events/StatusBarPanelClickEventArgs.cs new file mode 100644 index 0000000..e935ce8 --- /dev/null +++ b/source/ShiftUI/Events/StatusBarPanelClickEventArgs.cs @@ -0,0 +1,46 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +using System; + +namespace ShiftUI { + + public class StatusBarPanelClickEventArgs : MouseEventArgs { + + private StatusBarPanel panel; + + public StatusBarPanelClickEventArgs (StatusBarPanel statusBarPanel, + MouseButtons button, int clicks, int x, int y) : + base (button, clicks, x, y, 0) + { + this.panel = statusBarPanel; + } + + public StatusBarPanel StatusBarPanel { + get { return panel; } + } + } +} + diff --git a/source/ShiftUI/Events/StatusBarPanelClickEventHandler.cs b/source/ShiftUI/Events/StatusBarPanelClickEventHandler.cs new file mode 100644 index 0000000..615cc7d --- /dev/null +++ b/source/ShiftUI/Events/StatusBarPanelClickEventHandler.cs @@ -0,0 +1,32 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +namespace ShiftUI { + + public delegate void StatusBarPanelClickEventHandler (object sender, + StatusBarPanelClickEventArgs e); + +} + diff --git a/source/ShiftUI/Events/TabControlCancelEventArgs.cs b/source/ShiftUI/Events/TabControlCancelEventArgs.cs new file mode 100644 index 0000000..cbc5dd8 --- /dev/null +++ b/source/ShiftUI/Events/TabControlCancelEventArgs.cs @@ -0,0 +1,63 @@ +// +// TabControlCancelEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.ComponentModel; + +namespace ShiftUI +{ + public class TabControlCancelEventArgs : CancelEventArgs + { + private TabControlAction action; + private TabPage tab_page; + private int tab_page_index; + + #region Public Constructors + public TabControlCancelEventArgs (TabPage tabPage, int tabPageIndex, bool cancel, TabControlAction action) + : base (cancel) + { + this.tab_page = tabPage; + this.tab_page_index = tabPageIndex; + this.action = action; + } + #endregion // Public Constructors + + #region Public Instance Properties + public TabControlAction Action { + get { return this.action; } + } + + public TabPage TabPage { + get { return this.tab_page; } + } + + public int TabPageIndex { + get { return this.tab_page_index; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/TabControlCancelEventHandler.cs b/source/ShiftUI/Events/TabControlCancelEventHandler.cs new file mode 100644 index 0000000..0377cca --- /dev/null +++ b/source/ShiftUI/Events/TabControlCancelEventHandler.cs @@ -0,0 +1,32 @@ +// +// TabControlCancelEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void TabControlCancelEventHandler (object sender, TabControlCancelEventArgs e); +} diff --git a/source/ShiftUI/Events/TabControlEventArgs.cs b/source/ShiftUI/Events/TabControlEventArgs.cs new file mode 100644 index 0000000..f3e22c4 --- /dev/null +++ b/source/ShiftUI/Events/TabControlEventArgs.cs @@ -0,0 +1,64 @@ +// +// TabControlEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + public class TabControlEventArgs : EventArgs + { + private TabControlAction action; + private TabPage tab_page; + private int tab_page_index; + + #region Public Constructors + public TabControlEventArgs (TabPage tabPage, int tabPageIndex, TabControlAction action) : base () + { + this.tab_page = tabPage; + this.tab_page_index = tabPageIndex; + this.action = action; + } + #endregion // Public Constructors + + #region Public Instance Properties + public TabControlAction Action + { + get { return this.action; } + } + + public TabPage TabPage + { + get { return this.tab_page; } + } + + public int TabPageIndex + { + get { return this.tab_page_index; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/TabControlEventHandler.cs b/source/ShiftUI/Events/TabControlEventHandler.cs new file mode 100644 index 0000000..146367e --- /dev/null +++ b/source/ShiftUI/Events/TabControlEventHandler.cs @@ -0,0 +1,32 @@ +// +// TabControlEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void TabControlEventHandler (object sender, TabControlEventArgs e); +} diff --git a/source/ShiftUI/Events/TableLayoutCellPaintEventArgs.cs b/source/ShiftUI/Events/TableLayoutCellPaintEventArgs.cs new file mode 100644 index 0000000..e29dc93 --- /dev/null +++ b/source/ShiftUI/Events/TableLayoutCellPaintEventArgs.cs @@ -0,0 +1,64 @@ +// +// TableLayoutCellPaintEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; + +namespace ShiftUI +{ + public class TableLayoutCellPaintEventArgs : PaintEventArgs + { + private Rectangle cell_bounds; + private int column; + private int row; + + #region Public Constructors + public TableLayoutCellPaintEventArgs (Graphics g, Rectangle clipRectangle, + Rectangle cellBounds, int column, int row) + : base (g, clipRectangle) + { + this.cell_bounds = cellBounds; + this.column = column; + this.row = row; + } + #endregion // Public Constructors + + #region Public Instance Properties + public Rectangle CellBounds { + get { return this.cell_bounds; } + } + + public int Column { + get { return this.column; } + } + + public int Row { + get { return this.row; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/TableLayoutCellPaintEventHandler.cs b/source/ShiftUI/Events/TableLayoutCellPaintEventHandler.cs new file mode 100644 index 0000000..80aa4ae --- /dev/null +++ b/source/ShiftUI/Events/TableLayoutCellPaintEventHandler.cs @@ -0,0 +1,32 @@ +// +// TableLayoutCellPaintEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void TableLayoutCellPaintEventHandler (object sender, TableLayoutCellPaintEventArgs e); +} diff --git a/source/ShiftUI/Events/TableLayoutColumnStyleCollection.cs b/source/ShiftUI/Events/TableLayoutColumnStyleCollection.cs new file mode 100644 index 0000000..4949103 --- /dev/null +++ b/source/ShiftUI/Events/TableLayoutColumnStyleCollection.cs @@ -0,0 +1,75 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Author: +// Miguel de Icaza (miguel@gnome.org) +// +// Copyright 2004-2006 Novell, Inc. +// + +using System; +using System.ComponentModel; +using System.Collections; +using ShiftUI.Layout; + +namespace ShiftUI { + + public class TableLayoutColumnStyleCollection : TableLayoutStyleCollection { + + internal TableLayoutColumnStyleCollection (TableLayoutPanel panel) : base (panel) + { + } + + public int Add (ColumnStyle columnStyle) + { + return base.Add (columnStyle); + } + + public bool Contains (ColumnStyle columnStyle) + { + return ((IList)this).Contains (columnStyle); + } + + public int IndexOf (ColumnStyle columnStyle) + { + return ((IList)this).IndexOf (columnStyle); + } + + public void Insert (int index, ColumnStyle columnStyle) + { + ((IList)this).Insert (index, columnStyle); + } + + public void Remove (ColumnStyle columnStyle) + { + ((IList)this).Remove (columnStyle); + } + + public new ColumnStyle this [int index] { + get { + return (ColumnStyle) base [index]; + } + + set { + base [index] = value; + } + } + } +} diff --git a/source/ShiftUI/Events/TableLayoutControlCollection.cs b/source/ShiftUI/Events/TableLayoutControlCollection.cs new file mode 100644 index 0000000..16c6ae3 --- /dev/null +++ b/source/ShiftUI/Events/TableLayoutControlCollection.cs @@ -0,0 +1,66 @@ +// +// TableLayoutControlCollection.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.ComponentModel; +using System.ComponentModel.Design.Serialization; + +namespace ShiftUI +{ + //[DesignerSerializer ("ShiftUI.Design.TableLayoutControlCollectionCodeDomSerializer, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)] + [ListBindable (false)] + public class TableLayoutControlCollection : Widget.WidgetCollection + { + private TableLayoutPanel panel; + + #region Public Constructor + public TableLayoutControlCollection (TableLayoutPanel container) : base (container) + { + this.panel = container; + } + #endregion + + #region Public Property + public TableLayoutPanel Container { get { return this.panel; } } + #endregion + + #region Public Method + public virtual void Add (Widget control, int column, int row) + { + if (column < -1) + throw new ArgumentException ("column"); + if (row < -1) + throw new ArgumentException ("row"); + + base.Add (control); + + panel.SetCellPosition (control, new TableLayoutPanelCellPosition (column, row)); + } + #endregion + } +} diff --git a/source/ShiftUI/Events/TableLayoutPanelCellBorderStyle.cs b/source/ShiftUI/Events/TableLayoutPanelCellBorderStyle.cs new file mode 100644 index 0000000..a0c3922 --- /dev/null +++ b/source/ShiftUI/Events/TableLayoutPanelCellBorderStyle.cs @@ -0,0 +1,42 @@ +// +// TableLayoutPanelCellBorderStyle.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum TableLayoutPanelCellBorderStyle + { + None = 0, + Single = 1, + Inset = 2, + InsetDouble = 3, + Outset = 4, + OutsetDouble = 5, + OutsetPartial = 6 + } +} diff --git a/source/ShiftUI/Events/TableLayoutPanelCellPosition.cs b/source/ShiftUI/Events/TableLayoutPanelCellPosition.cs new file mode 100644 index 0000000..009a903 --- /dev/null +++ b/source/ShiftUI/Events/TableLayoutPanelCellPosition.cs @@ -0,0 +1,99 @@ +// +// TableLayoutPanelCellPosition.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Miguel de Icaza (miguel@novell.com) +// + + +using System.ComponentModel; +using System; + +namespace ShiftUI +{ + [TypeConverter (typeof (TableLayoutPanelCellPositionTypeConverter))] + public struct TableLayoutPanelCellPosition { + int column, row; + + public TableLayoutPanelCellPosition (int column, int row) + { + this.column = column; + this.row = row; + } + + public int Column { + get { + return column; + } + + set { + column = value; + } + } + + public int Row { + get { + return row; + } + + set { + row = value; + } + } + + public override string ToString () + { + return String.Concat (column.ToString (), ",", row.ToString ()); + } + + public override int GetHashCode () + { + return column.GetHashCode () ^ row.GetHashCode (); + } + + public static bool operator == (TableLayoutPanelCellPosition p1, TableLayoutPanelCellPosition p2) + { + return p1.column == p2.column && p1.row == p2.row; + } + + public static bool operator != (TableLayoutPanelCellPosition p1, TableLayoutPanelCellPosition p2) + { + return !(p1.column == p2.column && p1.row == p2.row); + } + + public override bool Equals (object other) + { + if (other == null) + return false; + if (!(other is TableLayoutPanelCellPosition)) + return false; + TableLayoutPanelCellPosition o = (TableLayoutPanelCellPosition) other; + return o.column == column && o.row == row; + } + } + + internal class TableLayoutPanelCellPositionTypeConverter : TypeConverter + { + } +} diff --git a/source/ShiftUI/Events/TableLayoutPanelGrowStyle.cs b/source/ShiftUI/Events/TableLayoutPanelGrowStyle.cs new file mode 100644 index 0000000..4795db7 --- /dev/null +++ b/source/ShiftUI/Events/TableLayoutPanelGrowStyle.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Author: +// Miguel de Icaza (miguel@gnome.org) +// +// (C) 2004 Novell, Inc. +// + +namespace ShiftUI { + public enum TableLayoutPanelGrowStyle { + FixedSize, + AddRows, + AddColumns, + } +} diff --git a/source/ShiftUI/Events/TableLayoutRowStyleCollection.cs b/source/ShiftUI/Events/TableLayoutRowStyleCollection.cs new file mode 100644 index 0000000..b57acc8 --- /dev/null +++ b/source/ShiftUI/Events/TableLayoutRowStyleCollection.cs @@ -0,0 +1,75 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Author: +// Miguel de Icaza (miguel@gnome.org) +// +// Copyright 2004-2006 Novell, Inc. +// + +using System; +using System.ComponentModel; +using System.Collections; +using ShiftUI.Layout; + +namespace ShiftUI { + + public class TableLayoutRowStyleCollection : TableLayoutStyleCollection { + + internal TableLayoutRowStyleCollection (TableLayoutPanel panel) : base (panel) + { + } + + public int Add (RowStyle rowStyle) + { + return base.Add (rowStyle); + } + + public bool Contains (RowStyle rowStyle) + { + return ((IList)this).Contains (rowStyle); + } + + public int IndexOf (RowStyle rowStyle) + { + return ((IList)this).IndexOf (rowStyle); + } + + public void Insert (int index, RowStyle rowStyle) + { + ((IList)this).Insert (index, rowStyle); + } + + public void Remove (RowStyle rowStyle) + { + ((IList)this).Remove (rowStyle); + } + + public new RowStyle this [int index] { + get { + return (RowStyle) base [index]; + } + + set { + base [index] = value; + } + } + } +} diff --git a/source/ShiftUI/Events/TableLayoutStyle.cs b/source/ShiftUI/Events/TableLayoutStyle.cs new file mode 100644 index 0000000..61b0187 --- /dev/null +++ b/source/ShiftUI/Events/TableLayoutStyle.cs @@ -0,0 +1,62 @@ +// +// TableLayoutStyle.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.ComponentModel; + +namespace ShiftUI +{ + [TypeConverter (typeof (TableLayoutSettings.StyleConverter))] + public abstract class TableLayoutStyle + { + private SizeType size_type; + private TableLayoutPanel owner; + + protected TableLayoutStyle () + { + size_type = SizeType.AutoSize; + } + + [DefaultValue (SizeType.AutoSize)] + public SizeType SizeType { + get { return this.size_type; } + set { + if (size_type != value) { + size_type = value; + if (owner != null) + owner.PerformLayout (); + } + } + } + + internal TableLayoutPanel Owner { + get { return owner; } + set { owner = value; } + } + } +} diff --git a/source/ShiftUI/Events/TableLayoutStyleCollection.cs b/source/ShiftUI/Events/TableLayoutStyleCollection.cs new file mode 100644 index 0000000..c4e7cea --- /dev/null +++ b/source/ShiftUI/Events/TableLayoutStyleCollection.cs @@ -0,0 +1,178 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Author: +// Miguel de Icaza (miguel@gnome.org) +// +// Copyright 2004-2006 Novell, Inc. +// + +using System; +using System.ComponentModel; +using System.Collections; +using ShiftUI.Layout; + +namespace ShiftUI { + //[Editor ("ShiftUI.Design.StyleCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + public abstract class TableLayoutStyleCollection : IList, ICollection, IEnumerable + { + ArrayList al = new ArrayList (); + TableLayoutPanel table; + + internal TableLayoutStyleCollection (TableLayoutPanel table) + { + if (table == null) + throw new ArgumentNullException("table"); + + this.table = table; + } + + public int Add (TableLayoutStyle style) + { + return ((IList)this).Add (style); + } + + public void Clear () + { + foreach (TableLayoutStyle style in al) + style.Owner = null; + al.Clear (); + table.PerformLayout (); + } + + public int Count { + get { return al.Count; } + } + + public void RemoveAt (int index) + { + ((TableLayoutStyle)al[index]).Owner = null; + al.RemoveAt (index); + table.PerformLayout (); + } + +#region IList methods + // + // The IList methods will later be implemeneted, this is to get us started + // + int IList.Add (object style) + { + TableLayoutStyle layoutStyle = (TableLayoutStyle) style; + if (layoutStyle.Owner != null) + throw new ArgumentException ("Style is already owned"); + + layoutStyle.Owner = table; + int result = al.Add (layoutStyle); + + if (table != null) + table.PerformLayout (); + + return result; + } + + bool IList.Contains (object style) + { + return al.Contains ((TableLayoutStyle) style); + } + + int IList.IndexOf (object style) + { + return al.IndexOf ((TableLayoutStyle) style); + } + + void IList.Insert (int index, object style) + { + if (((TableLayoutStyle)style).Owner != null) + throw new ArgumentException ("Style is already owned"); + ((TableLayoutStyle)style).Owner = table; + al.Insert (index, (TableLayoutStyle) style); + table.PerformLayout (); + } + + void IList.Remove (object style) + { + ((TableLayoutStyle)style).Owner = null; + al.Remove ((TableLayoutStyle) style); + table.PerformLayout (); + } + + bool IList.IsFixedSize { + get { + return al.IsFixedSize; + } + } + + bool IList.IsReadOnly { + get { + return al.IsReadOnly; + } + } + + object IList.this [int index] { + get { + return al [index]; + } + set { + if (((TableLayoutStyle)value).Owner != null) + throw new ArgumentException ("Style is already owned"); + ((TableLayoutStyle)value).Owner = table; + al [index] = value; + table.PerformLayout (); + } + } +#endregion + +#region ICollection methods + void ICollection.CopyTo (Array array, int startIndex) + { + al.CopyTo (array, startIndex); + } + + object ICollection.SyncRoot { + get { + return al.SyncRoot; + } + } + + bool ICollection.IsSynchronized { + get { + return al.IsSynchronized; + } + } +#endregion + +#region IEnumerable methods + IEnumerator IEnumerable.GetEnumerator () + { + return al.GetEnumerator (); + } +#endregion + public TableLayoutStyle this [int index] { + get { + return (TableLayoutStyle) ((IList)this)[index]; + } + + set { + ((IList)this)[index] = value; + } + } + } + +} diff --git a/source/ShiftUI/Events/TreeNodeMouseClickEventArgs.cs b/source/ShiftUI/Events/TreeNodeMouseClickEventArgs.cs new file mode 100644 index 0000000..b33bc6e --- /dev/null +++ b/source/ShiftUI/Events/TreeNodeMouseClickEventArgs.cs @@ -0,0 +1,49 @@ +// +// TreeNodeMouseClickEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public class TreeNodeMouseClickEventArgs : MouseEventArgs + { + private TreeNode node; + + #region Public Constructors + public TreeNodeMouseClickEventArgs (TreeNode node, MouseButtons button, int clicks, int x, int y) + : base (button, clicks, x, y, 0) + { + this.node = node; + } + #endregion // Public Constructors + + #region Public Instance Properties + public TreeNode Node { + get { return this.node; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/TreeNodeMouseClickEventHandler.cs b/source/ShiftUI/Events/TreeNodeMouseClickEventHandler.cs new file mode 100644 index 0000000..b5ec525 --- /dev/null +++ b/source/ShiftUI/Events/TreeNodeMouseClickEventHandler.cs @@ -0,0 +1,32 @@ +// +// TreeNodeMouseClickEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void TreeNodeMouseClickEventHandler (object sender, TreeNodeMouseClickEventArgs e); +} diff --git a/source/ShiftUI/Events/TreeNodeMouseHoverEventArgs.cs b/source/ShiftUI/Events/TreeNodeMouseHoverEventArgs.cs new file mode 100644 index 0000000..768cdee --- /dev/null +++ b/source/ShiftUI/Events/TreeNodeMouseHoverEventArgs.cs @@ -0,0 +1,52 @@ +// +// TreeNodeMouseHoverEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI +{ + [ComVisible (true)] + public class TreeNodeMouseHoverEventArgs : EventArgs + { + private TreeNode node; + + #region Public Constructors + public TreeNodeMouseHoverEventArgs (TreeNode node) : base () + { + this.node = node; + } + #endregion // Public Constructors + + #region Public Instance Properties + public TreeNode Node { + get { return this.node; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/TreeNodeMouseHoverEventHandler.cs b/source/ShiftUI/Events/TreeNodeMouseHoverEventHandler.cs new file mode 100644 index 0000000..fde795d --- /dev/null +++ b/source/ShiftUI/Events/TreeNodeMouseHoverEventHandler.cs @@ -0,0 +1,32 @@ +// +// TreeNodeMouseHoverEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void TreeNodeMouseHoverEventHandler (object sender, TreeNodeMouseHoverEventArgs e); +} diff --git a/source/ShiftUI/Events/TreeViewCancelEventArgs.cs b/source/ShiftUI/Events/TreeViewCancelEventArgs.cs new file mode 100644 index 0000000..330052b --- /dev/null +++ b/source/ShiftUI/Events/TreeViewCancelEventArgs.cs @@ -0,0 +1,52 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +using System; +using System.ComponentModel; + + +namespace ShiftUI { + + public class TreeViewCancelEventArgs : CancelEventArgs { + + private TreeNode node; + private TreeViewAction action; + + public TreeViewCancelEventArgs (TreeNode node, bool cancel, TreeViewAction action) : base (cancel) + { + this.node = node; + this.action = action; + } + + public TreeNode Node { + get { return node; } + } + + public TreeViewAction Action { + get { return action; } + } + } +} + diff --git a/source/ShiftUI/Events/TreeViewCancelEventHandler.cs b/source/ShiftUI/Events/TreeViewCancelEventHandler.cs new file mode 100644 index 0000000..0e03a8b --- /dev/null +++ b/source/ShiftUI/Events/TreeViewCancelEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +namespace ShiftUI { + + public delegate void TreeViewCancelEventHandler (object sender, TreeViewCancelEventArgs e); + +} + diff --git a/source/ShiftUI/Events/TreeViewEventArgs.cs b/source/ShiftUI/Events/TreeViewEventArgs.cs new file mode 100644 index 0000000..9f1a82f --- /dev/null +++ b/source/ShiftUI/Events/TreeViewEventArgs.cs @@ -0,0 +1,52 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) +using System; + +namespace ShiftUI { + + public class TreeViewEventArgs : EventArgs { + + private TreeNode node; + private TreeViewAction action; + + public TreeViewEventArgs (TreeNode node) + { + this.node = node; + } + + public TreeViewEventArgs (TreeNode node, TreeViewAction action) : this (node) + { + this.action = action; + } + + public TreeViewAction Action { + get { return action; } + } + + public TreeNode Node { + get { return node; } + } + } +} + diff --git a/source/ShiftUI/Events/TreeViewEventHandler.cs b/source/ShiftUI/Events/TreeViewEventHandler.cs new file mode 100644 index 0000000..d2bc2df --- /dev/null +++ b/source/ShiftUI/Events/TreeViewEventHandler.cs @@ -0,0 +1,30 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + +namespace ShiftUI { + + public delegate void TreeViewEventHandler (object sender, TreeViewEventArgs e); + +} + diff --git a/source/ShiftUI/Events/UICues.cs b/source/ShiftUI/Events/UICues.cs new file mode 100644 index 0000000..d2f4ca4 --- /dev/null +++ b/source/ShiftUI/Events/UICues.cs @@ -0,0 +1,42 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE +using System; + +namespace ShiftUI { + + [Flags] + public enum UICues { + None = 0x00000000, + ShowFocus = 0x00000001, + ShowKeyboard = 0x00000002, + Shown = 0x00000003, + ChangeFocus = 0x00000004, + ChangeKeyboard = 0x00000008, + Changed = 0x0000000C + } +} diff --git a/source/ShiftUI/Events/UICuesEventArgs.cs b/source/ShiftUI/Events/UICuesEventArgs.cs new file mode 100644 index 0000000..fede8a8 --- /dev/null +++ b/source/ShiftUI/Events/UICuesEventArgs.cs @@ -0,0 +1,88 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE +using System; + +namespace ShiftUI { + public class UICuesEventArgs : EventArgs { + private UICues cues; + + #region Public Constructors + public UICuesEventArgs(UICues uicues) { + this.cues = uicues; + } + #endregion + + #region Public Instance Properties + public UICues Changed { + get { + return (cues & UICues.Changed); + } + } + + public bool ChangeFocus { + get { + if ((cues & UICues.ChangeFocus)==0) { + return false; + } else { + return true; + } + } + } + + public bool ChangeKeyboard { + get { + if ((cues & UICues.ChangeKeyboard)==0) { + return false; + } else { + return true; + } + } + } + + public bool ShowFocus { + get { + if ((cues & UICues.ShowFocus)==0) { + return false; + } else { + return true; + } + } + } + + public bool ShowKeyboard { + get { + if ((cues & UICues.ShowKeyboard)==0) { + return false; + } else { + return true; + } + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Events/UICuesEventHandler.cs b/source/ShiftUI/Events/UICuesEventHandler.cs new file mode 100644 index 0000000..0c81f02 --- /dev/null +++ b/source/ShiftUI/Events/UICuesEventHandler.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE +using System; + +namespace ShiftUI { + public delegate void UICuesEventHandler (Object sender, UICuesEventArgs e); +} diff --git a/source/ShiftUI/Form/Form.cs b/source/ShiftUI/Form/Form.cs new file mode 100644 index 0000000..6cda945 --- /dev/null +++ b/source/ShiftUI/Form/Form.cs @@ -0,0 +1,3491 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + +// NOT COMPLETE + +using System; +using System.Drawing; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.ComponentModel.Design.Serialization; +using System.Collections; +using System.Runtime.InteropServices; +using System.Threading; +using System.Collections.Generic; + +namespace ShiftUI { + [DesignerCategory("Form")] + [DesignTimeVisible(false)] + [Designer("ShiftUI.Design.FormDocumentDesigner, " + Consts.AssemblySystem_Design, typeof(IRootDesigner))] + [DefaultEvent("Load")] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [InitializationEvent ("Load")] + [ComVisible (true)] + [ToolboxItemFilter ("Widget.TopLevel")] + [ToolboxItem(false)] + public class Form : ContainerWidget { + + public static readonly int BodyTag = 0x0AA40CE; //"Jonathan Ladouceur in hexadecimal + leetspeak because I can't think of another tag people won't use to muck up my designer. + + private void drag_start(object s, MouseEventArgs a) + { + loc_last_x = a.Location.X; + loc_last_y = a.Location.Y; + } + + private void drag_and_drop(object s, MouseEventArgs a) + { + if (a.Button == MouseButtons.Left && this.WindowState == FormWindowState.Normal) + { + this.Left += a.Location.X - loc_last_x; + this.Top += a.Location.Y - loc_last_y; + + } + } + + #region Local Variables + internal List border_widgets; + internal int loc_last_x; + internal int loc_last_y; + internal bool closing; + private bool closed; + FormBorderStyle form_border_style; + private bool is_active; + private bool autoscale; + private Size clientsize_set; + private Size autoscale_base_size; + private bool allow_transparency; + private static Icon default_icon; + internal bool is_modal; + internal FormWindowState window_state; + private bool Widget_box; + private bool minimize_box; + private bool maximize_box; + private bool help_button; + private bool show_in_taskbar; + private bool topmost; + private IButtonWidget accept_button; + private IButtonWidget cancel_button; + private DialogResult dialog_result; + private FormStartPosition start_position; + private Form owner; + private Form.WidgetCollection owned_forms; + private MdiClient mdi_container; + internal InternalWindowManager window_manager; + private Form mdi_parent; + private bool key_preview; + private MainMenu menu; + private Icon icon; + private Size maximum_size; + private Size minimum_size; + private SizeGripStyle size_grip_style; + private SizeGrip size_grip; + private Rectangle maximized_bounds; + private Rectangle default_maximized_bounds; + private double opacity; + internal ApplicationContext context; + Color transparency_key; + private bool is_loaded; + internal int is_changing_visible_state; + internal bool has_been_visible; + private bool shown_raised; + private bool close_raised; + private bool is_clientsize_set; + internal bool suppress_closing_events; + internal bool waiting_showwindow; // for XplatUIX11 + private bool is_minimizing; + private bool show_icon = true; + private MenuStrip main_menu_strip; + private bool right_to_left_layout; + private Rectangle restore_bounds; + private bool autoscale_base_size_set; + internal ArrayList disabled_by_showdialog = new ArrayList(); + internal static ArrayList modal_dialogs = new ArrayList(); + private Panel close_button; + private Panel minimize_button; + private Panel maximize_button; + private Panel titlebar; + private Panel titlebar_left; + private Panel titlebar_right; + private Panel border_left; + private Panel border_right; + private Panel border_bottom; + private Panel border_bottom_left; + private Panel border_bottom_right; + private Label title_text; + private PictureBox title_icon; + private Panel body; + private readonly string border_guid = Guid.NewGuid().ToString(); //distinguish border widgets from others + + #endregion // Local Variables + + #region Private & Internal Methods + static Form () + { + default_icon = null; + } + + internal bool IsLoaded { + get { return is_loaded; } + } + + internal bool IsActive { + get { + return is_active; + } + set { + if (is_active == value || IsRecreating) { + return; + } + + is_active = value; + if (is_active) { + Application.AddForm (this); + OnActivated (EventArgs.Empty); + } else { + OnDeactivate (EventArgs.Empty); + } + } + } + + // warning: this is only hooked up when an mdi container is created. + private void WidgetAddedHandler (object sender, WidgetEventArgs e) + { + if (mdi_container != null) { + mdi_container.SendToBack (); + } + } + + // Convenience method for fire BOTH OnClosing and OnFormClosing events + // Returns the value of Cancel, so true means the Close was cancelled, + // and you shouldn't close the form. + internal bool FireClosingEvents (CloseReason reason, bool cancel) + { + CancelEventArgs cea = new CancelEventArgs (cancel); + this.OnClosing (cea); + + FormClosingEventArgs fcea = new FormClosingEventArgs (reason, cea.Cancel); + this.OnFormClosing (fcea); + return fcea.Cancel; + } + + // Convenience method for fire BOTH OnClosed and OnFormClosed events + private void FireClosedEvents (CloseReason reason) + { + this.OnClosed (EventArgs.Empty); + this.OnFormClosed (new FormClosedEventArgs (reason)); + } + + internal override Size GetPreferredSizeCore (Size proposedSize) + { + Size retsize = Size.Empty; + + foreach (Widget child in Widgets) { + Size child_preferred_size; + if (child.AutoSize) + child_preferred_size = child.PreferredSize; + else + child_preferred_size = child.ExplicitBounds.Size; + int child_right = child.Bounds.X + child_preferred_size.Width; + int child_bottom = child.Bounds.Y + child_preferred_size.Height; + + if (child.Dock == DockStyle.Fill) { + if (child_right > retsize.Width) + retsize.Width = child_right; + } + else if (child.Dock != DockStyle.Top && child.Dock != DockStyle.Bottom && child_right > retsize.Width) + retsize.Width = child_right + child.Margin.Right; + + if (child.Dock == DockStyle.Fill) { + if (child_bottom > retsize.Height) + retsize.Height = child_bottom; + } + else if (child.Dock != DockStyle.Left && child.Dock != DockStyle.Right && child_bottom > retsize.Height) + retsize.Height = child_bottom + child.Margin.Bottom; + } + + if (retsize == Size.Empty) { // no child Widgets + retsize.Height += this.Padding.Top; + retsize.Width += this.Padding.Left; + } + retsize.Height += this.Padding.Bottom; + retsize.Width += this.Padding.Right; + + return SizeFromClientSize (retsize); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override Rectangle GetScaledBounds (Rectangle bounds, SizeF factor, BoundsSpecified specified) + { + if ((specified & BoundsSpecified.Width) == BoundsSpecified.Width) { + int border = Size.Width - ClientSize.Width; + bounds.Width = (int)Math.Round ((bounds.Width - border) * factor.Width) + border; + } + if ((specified & BoundsSpecified.Height) == BoundsSpecified.Height) { + int border = Size.Height - ClientSize.Height; + bounds.Height = (int)Math.Round ((bounds.Height - border) * factor.Height) + border; + } + + return bounds; + } + + protected override bool ProcessMnemonic (char charCode) + { + return base.ProcessMnemonic (charCode); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void ScaleWidget (SizeF factor, BoundsSpecified specified) + { + base.ScaleWidget (factor, specified); + } + + internal void OnActivatedInternal () + { + OnActivated (EventArgs.Empty); + } + + internal void OnDeactivateInternal () + { + OnDeactivate (EventArgs.Empty); + } + + internal override void UpdateWindowText () + { + if (!IsHandleCreated) { + return; + } + + if (shown_raised) { + /* we need to call .SetWindowStyle here instead of just .Text + because the presence/absence of Text (== "" or not) can cause + other window style things to appear/disappear */ + XplatUI.SetWindowStyle (window.Handle, CreateParams); + } + + XplatUI.Text (Handle, Text.Replace (Environment.NewLine, string.Empty)); + } + + internal void SelectActiveWidget () + { + if (this.IsMdiContainer) { + mdi_container.SendFocusToActiveChild (); + return; + } + + if (this.ActiveWidget == null) { + bool visible; + + // This visible hack is to work around CanSelect always being false if one of the parents + // is not visible; and we by default create Form invisible... + visible = this.is_visible; + this.is_visible = true; + + if (SelectNextWidget (this, true, true, true, true) == false) { + Select (this); + } + + this.is_visible = visible; + } else { + Select (ActiveWidget); + } + } + + private new void UpdateSizeGripVisible () + { + // Following link explains when to show size grip: + // http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=138687&SiteID=1 + // if SizeGripStyle.Auto, only shown if form is shown using ShowDialog and is sizable + // if SizeGripStyle.Show, only shown if form is sizable + + bool show = false; + + switch (size_grip_style) { + case SizeGripStyle.Auto: + show = is_modal && (form_border_style == FormBorderStyle.Sizable || form_border_style == FormBorderStyle.SizableToolWindow); + break; + case SizeGripStyle.Hide: + show = false; + break; + case SizeGripStyle.Show: + show = (form_border_style == FormBorderStyle.Sizable || form_border_style == FormBorderStyle.SizableToolWindow); + break; + } + + if (!show) { + if (size_grip != null && size_grip.Visible) + size_grip.Visible = false; + } else { + if (size_grip == null) { + size_grip = new SizeGrip (this); + size_grip.Virtual = true; + size_grip.FillBackground = false; + } + size_grip.Visible = true; + } + } + + internal void ChangingParent (Widget new_parent) + { + if (IsMdiChild) { + return; + } + + bool recreate_necessary = false; + + if (new_parent == null) { + window_manager = null; + } else if (new_parent is MdiClient) { + window_manager = new MdiWindowManager (this, (MdiClient) new_parent); + } else { + window_manager = new FormWindowManager (this); + recreate_necessary = true; + } + + if (recreate_necessary) { + if (IsHandleCreated) { + if (new_parent != null && new_parent.IsHandleCreated) { + RecreateHandle (); + } else { + DestroyHandle (); + } + } + } else { + if (IsHandleCreated) { + IntPtr new_handle = IntPtr.Zero; + if (new_parent != null && new_parent.IsHandleCreated) { + new_handle = new_parent.Handle; + } + XplatUI.SetParent (Handle, new_handle); + } + } + + if (window_manager != null) { + window_manager.UpdateWindowState (window_state, window_state, true); + } + } + + internal override bool FocusInternal (bool skip_check) + { + if (IsMdiChild) { + // MS always creates handles when Focus () is called for mdi clients. + if (!IsHandleCreated) + CreateHandle (); + } + return base.FocusInternal (skip_check); + } + #endregion // Private & Internal Methods + + #region Public Classes + [ComVisible (false)] + public new class WidgetCollection : Widget.WidgetCollection { + Form form_owner; + + public WidgetCollection(Form owner) : base(owner) { + this.form_owner = owner; + } + + public override void Add(Widget value) { + if (Contains (value)) + return; + AddToList (value); + ((Form)value).owner=form_owner; + } + + public override void Remove(Widget value) { + ((Form)value).owner = null; + base.Remove (value); + } + } + #endregion // Public Classes + + public Widget[] BorderWidgets + { + get + { + return border_widgets.ToArray(); + } + } + + /// + /// Gets the body panel of the form. + /// + public Panel Body + { + get { return body; } + } + + #region Public Constructor & Destructor + public Form () + { + SizeF current_scale = GetAutoScaleSize (Font); + + autoscale = true; + autoscale_base_size = new Size ((int)Math.Round (current_scale.Width), (int)Math.Round(current_scale.Height)); + allow_transparency = false; + closing = false; + is_modal = false; + dialog_result = DialogResult.None; + start_position = FormStartPosition.WindowsDefaultLocation; + form_border_style = FormBorderStyle.Sizable; + window_state = FormWindowState.Normal; + key_preview = false; + opacity = 1D; + menu = null; + icon = default_icon; + minimum_size = Size.Empty; + maximum_size = Size.Empty; + clientsize_set = Size.Empty; + Widget_box = true; + minimize_box = true; + maximize_box = true; + help_button = false; + show_in_taskbar = true; + is_visible = false; + is_toplevel = true; + size_grip_style = SizeGripStyle.Auto; + maximized_bounds = Rectangle.Empty; + default_maximized_bounds = Rectangle.Empty; + owned_forms = new Form.WidgetCollection(this); + transparency_key = Color.Empty; + CreateDockPadding (); + InternalClientSize = new Size (this.Width - (SystemInformation.FrameBorderSize.Width * 2), this.Height - (SystemInformation.FrameBorderSize.Height * 2) - SystemInformation.CaptionHeight); + restore_bounds = Bounds; + BorderStyle = FormBorderStyle.None; + titlebar = new Panel(); + this.Widgets.Add(titlebar); + titlebar.Dock = DockStyle.Top; + titlebar.Height = 24; + titlebar.BackColor = Color.Gray; + titlebar.Tag = border_guid; + border_widgets = new List(); + border_widgets.Add(titlebar); + + titlebar_left = new Panel(); + titlebar_left.Dock = DockStyle.Left; + titlebar.Widgets.Add(titlebar_left); + titlebar_left.Show(); + titlebar_right = new Panel(); + titlebar_right.Dock = DockStyle.Right; + titlebar.Widgets.Add(titlebar_right); + titlebar_right.Show(); + + title_text = new Label(); + titlebar.Widgets.Add(title_text); + title_text.Show(); + + border_left = new Panel(); + border_left.Dock = DockStyle.Left; + border_left.Tag = border_guid; + border_widgets.Add(border_left); + this.Widgets.Add(border_left); + border_left.Show(); + + border_right = new Panel(); + border_right.Dock = DockStyle.Right; + border_right.Tag = border_guid; + this.Widgets.Add(border_right); + border_right.Show(); + border_widgets.Add(border_right); + + border_bottom = new Panel(); + border_bottom.Dock = DockStyle.Bottom; + border_bottom.Tag = border_guid; + this.Widgets.Add(border_bottom); + border_bottom.Show(); + border_widgets.Add(border_bottom); + + body = new Panel(); + body.Dock = DockStyle.Fill; + body.Tag = border_guid; + body.Tag = Form.BodyTag; + body.Show(); + body.BringToFront(); + body.BringToFront(); + close_button = new Panel(); + close_button.MouseDown += (o, a) => + { + if (a.Button == MouseButtons.Left) + { + this.Close(); + } + }; + body.Name = "Body"; + minimize_button = new Panel(); + minimize_button.Click += (o, a) => + { + this.WindowState = FormWindowState.Minimized; + }; + titlebar.Widgets.Add(minimize_button); + minimize_button.Show(); + + maximize_button = new Panel(); + maximize_button.Click += (o, a) => + { + if (this.WindowState == FormWindowState.Maximized) + this.WindowState = FormWindowState.Normal; + else + this.WindowState = FormWindowState.Maximized; + }; + titlebar.Widgets.Add(maximize_button); + maximize_button.Show(); + + titlebar.Widgets.Add(close_button); + close_button.Show(); + + this.Widgets.Add(body); + body.BringToFront(); + this.WidgetAdded += (o, a) => + { + if ((string)a.Widget.Tag != border_guid && a.Widget != body) + { + this.Widgets.Remove(a.Widget); + body.Widgets.Add(a.Widget); + a.Widget.Show(); + } + + }; + titlebar.MouseMove += new MouseEventHandler(this.drag_and_drop); + title_text.MouseMove += new MouseEventHandler(this.drag_and_drop); + titlebar.MouseDown += new MouseEventHandler(this.drag_start); + title_text.MouseDown += new MouseEventHandler(this.drag_start); + + ResetSkin(); + } + #endregion // Public Constructor & Destructor + + #region Public Static Properties + + public static Form ActiveForm { + get { + Widget active; + + active = FromHandle(XplatUI.GetActive()); + + if (active != null) { + if ( !(active is Form)) { + Widget parent; + + parent = active.Parent; + while (parent != null) { + if (parent is Form) { + return (Form)parent; + } + parent = parent.Parent; + } + } else { + return (Form)active; + } + } + return null; + } + } + + #endregion // Public Static Properties + + #region Public Instance Properties + [DefaultValue(null)] + public IButtonWidget AcceptButton { + get { + return accept_button; + } + + set { + if (accept_button != null) + accept_button.NotifyDefault (false); + + accept_button = value; + if (accept_button != null) + accept_button.NotifyDefault (true); + + CheckAcceptButton (); + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool AllowTransparency { + get { + return allow_transparency; + } + + set { + if (value == allow_transparency) { + return; + } + + allow_transparency = value; + + if (value) { + if (IsHandleCreated) { + if ((XplatUI.SupportsTransparency() & TransparencySupport.Set) != 0) { + XplatUI.SetWindowTransparency(Handle, Opacity, TransparencyKey); + } + } else { + UpdateStyles(); // Remove the WS_EX_LAYERED style + } + } + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + [Obsolete ("This property has been deprecated in favor of AutoScaleMode.")] + [MWFCategory("Layout")] + public bool AutoScale { + get { + return autoscale; + } + + set { + if (value) + AutoScaleMode = AutoScaleMode.None; + + autoscale = value; + } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[EditorBrowsable(EditorBrowsableState.Never)] + [Localizable(true)] + [Browsable(false)] + public virtual Size AutoScaleBaseSize { + get { + return autoscale_base_size; + } + [MonoTODO ("Setting this is probably unintentional and can cause Forms to be improperly sized. See http://www.mono-project.com/FAQ:_Winforms#My_forms_are_sized_improperly for details.")] + set { + autoscale_base_size = value; + autoscale_base_size_set = true; + } + } + + [Localizable(true)] + public override bool AutoScroll { + get { + return base.AutoScroll; + } + set { + base.AutoScroll = value; + } + } + + internal bool ShouldSerializeAutoScroll () + { + return this.AutoScroll != false; + } + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)] + public override bool AutoSize { + get { return base.AutoSize; } + set { + if (base.AutoSize != value) { + base.AutoSize = value; + PerformLayout (this, "AutoSize"); + } + } + } + + internal bool ShouldSerializeAutoSize () + { + return this.AutoSize != false; + } + + [Browsable (true)] + [Localizable (true)] + [DefaultValue (AutoSizeMode.GrowOnly)] + public AutoSizeMode AutoSizeMode { + get { return base.GetAutoSizeMode (); } + set { + if (base.GetAutoSizeMode () != value) { + if (!Enum.IsDefined (typeof (AutoSizeMode), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for AutoSizeMode", value)); + + base.SetAutoSizeMode (value); + PerformLayout (this, "AutoSizeMode"); + } + } + } + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public override AutoValidate AutoValidate { + get { return base.AutoValidate; } + set { base.AutoValidate = value; } + } + + public override Color BackColor { + get { + /* we don't let parents override our + default background color for forms. + this fixes the default color for mdi + children. */ + if (background_color.IsEmpty) + return DefaultBackColor; + else + return background_color; + } + set { + base.BackColor = value; + } + } + + [DefaultValue(null)] + public IButtonWidget CancelButton { + get { + return cancel_button; + } + + set { + cancel_button = value; + if (cancel_button != null && cancel_button.DialogResult == DialogResult.None) + cancel_button.DialogResult = DialogResult.Cancel; + } + } + + // new property so we can change the DesignerSerializationVisibility + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + [Localizable(true)] + public new Size ClientSize { + get { return base.ClientSize; } + set { + is_clientsize_set = true; + base.ClientSize = value; + } + } + + [DefaultValue(true)] + [MWFCategory("Window Style")] + public bool WidgetBox { + get { + return Widget_box; + } + + set { + if (Widget_box != value) { + Widget_box = value; + UpdateStyles(); + } + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Rectangle DesktopBounds { + get { + return new Rectangle(Location, Size); + } + + set { + Bounds = value; + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Point DesktopLocation { + get { + return Location; + } + + set { + Location = value; + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public DialogResult DialogResult { + get { + return dialog_result; + } + + set { + if (value < DialogResult.None || value > DialogResult.No) + throw new InvalidEnumArgumentException ("value", (int) value, + typeof (DialogResult)); + + dialog_result = value; + if (dialog_result != DialogResult.None && is_modal) + RaiseCloseEvents (false, false); // .Net doesn't send WM_CLOSE here. + } + } + + private FormBorderStyle custom_border_style = FormBorderStyle.Sizable; + + public FormBorderStyle FormBorderStyle + { + get { return custom_border_style; } + set { custom_border_style = value; ResetSkin(); } + } + + private FormBorderStyle BorderStyle { + get { + return form_border_style; + } + set { + form_border_style = value; + + if (window_manager == null) { + if (IsHandleCreated) { + XplatUI.SetBorderStyle(window.Handle, form_border_style); + } + } else { + window_manager.UpdateBorderStyle (value); + } + + Size current_client_size = ClientSize; + UpdateStyles(); + + if (this.IsHandleCreated) { + this.Size = InternalSizeFromClientSize (current_client_size); + XplatUI.InvalidateNC (this.Handle); + } else if (is_clientsize_set) { + this.Size = InternalSizeFromClientSize (current_client_size); + } + } + } + + [DefaultValue(false)] + [MWFCategory("Window Style")] + public bool HelpButton { + get { + return help_button; + } + + set { + if (help_button != value) { + help_button = value; + UpdateStyles(); + } + } + } + + [Localizable(true)] + [AmbientValue(null)] + [MWFCategory("Window Style")] + public Icon Icon { + get { + return icon; + } + + set { + if (value == null) + value = default_icon; + if (icon == value) + return; + icon = value; + if (IsHandleCreated) + XplatUI.SetIcon (Handle, icon); + } + } + + internal bool ShouldSerializeIcon () + { + return this.Icon != default_icon; + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsMdiChild { + get { + return mdi_parent != null; + } + } + + [DefaultValue(false)] + [MWFCategory("Window Style")] + public bool IsMdiContainer { + get { + return mdi_container != null; + } + + set { + if (value && mdi_container == null) { + mdi_container = new MdiClient (); + Widgets.Add(mdi_container); + WidgetAdded += new WidgetEventHandler (WidgetAddedHandler); + mdi_container.SendToBack (); + mdi_container.SetParentText (true); + } else if (!value && mdi_container != null) { + Widgets.Remove(mdi_container); + mdi_container = null; + } + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Form ActiveMdiChild { + get { + if (!IsMdiContainer) + return null; + return (Form) mdi_container.ActiveMdiChild; + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public bool IsRestrictedWindow { + get { + return false; + } + } + + [DefaultValue(false)] + public bool KeyPreview { + get { + return key_preview; + } + + set { + key_preview = value; + } + } + + [DefaultValue (null)] + [TypeConverter (typeof (ReferenceConverter))] + public MenuStrip MainMenuStrip { + get { return this.main_menu_strip; } + set { + if (this.main_menu_strip != value) { + this.main_menu_strip = value; + this.main_menu_strip.RefreshMdiItems (); + } + } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public new Padding Margin { + get { return base.Margin; } + set { base.Margin = value; } + } + + [Obsolete("Minimize, Maximize and Close buttons are dealt with by the skin system.")] + [DefaultValue(true)] + [MWFCategory("Obsolete")] + public bool MaximizeBox { + get { + return maximize_box; + } + set { + if (maximize_box != value) { + maximize_box = value; + UpdateStyles(); + } + } + } + + [DefaultValue(typeof (Size),"0, 0")] + [Localizable(true)] + [RefreshProperties(RefreshProperties.Repaint)] + [MWFCategory("Layout")] + public override Size MaximumSize { + get { + return maximum_size; + } + + set { + if (maximum_size != value) { + maximum_size = value; + + // If this is smaller than the min, adjust the min + if (!minimum_size.IsEmpty) { + if (maximum_size.Width <= minimum_size.Width) + minimum_size.Width = maximum_size.Width; + if (maximum_size.Height <= minimum_size.Height) + minimum_size.Height = maximum_size.Height; + } + + OnMaximumSizeChanged(EventArgs.Empty); + if (IsHandleCreated) { + XplatUI.SetWindowMinMax(Handle, maximized_bounds, minimum_size, maximum_size); + } + } + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Form[] MdiChildren { + get { + if (mdi_container != null) + return mdi_container.MdiChildren; + else + return new Form[0]; + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Form MdiParent { + get { + return mdi_parent; + } + + set { + if (value == mdi_parent) + return; + + if (value != null && !value.IsMdiContainer) + throw new ArgumentException ("Form that was specified to be " + + "the MdiParent for this form is not an MdiContainer."); + + if (mdi_parent != null) { + mdi_parent.MdiContainer.Widgets.Remove (this); + } + + if (value != null) { + mdi_parent = value; + if (window_manager == null) { + window_manager = new MdiWindowManager (this, mdi_parent.MdiContainer); + } + + mdi_parent.MdiContainer.Widgets.Add (this); + mdi_parent.MdiContainer.Widgets.SetChildIndex (this, 0); + + if (IsHandleCreated) + RecreateHandle (); + } else if (mdi_parent != null) { + mdi_parent = null; + + // Create a new window manager + window_manager = null; + FormBorderStyle = form_border_style; + + if (IsHandleCreated) + RecreateHandle (); + } + is_toplevel = mdi_parent == null; + } + } + + internal MdiClient MdiContainer { + get { return mdi_container; } + } + + internal InternalWindowManager WindowManager { + get { return window_manager; } + } + + [Browsable (false)] + [TypeConverter (typeof (ReferenceConverter))] + [DefaultValue(null)] + [MWFCategory("Window Style")] + public MainMenu Menu { + get { + return menu; + } + + set { + if (menu != value) { + menu = value; + + if (menu != null && !IsMdiChild) { + menu.SetForm (this); + + if (IsHandleCreated) { + XplatUI.SetMenu (window.Handle, menu); + } + + if (clientsize_set != Size.Empty) { + SetClientSizeCore(clientsize_set.Width, clientsize_set.Height); + } else { + UpdateBounds (bounds.X, bounds.Y, bounds.Width, bounds.Height, ClientSize.Width, ClientSize.Height - + ThemeEngine.Current.CalcMenuBarSize (DeviceContext, menu, ClientSize.Width)); + } + } else + UpdateBounds (); + + // UIA Framework Event: Menu Changed + OnUIAMenuChanged (EventArgs.Empty); + } + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public MainMenu MergedMenu { + get { + if (!IsMdiChild || window_manager == null) + return null; + return ((MdiWindowManager) window_manager).MergedMenu; + } + } + + // This is the menu in display and being used because of merging this can + // be different then the menu that is actually assosciated with the form + internal MainMenu ActiveMenu { + get { + if (IsMdiChild) + return null; + + if (IsMdiContainer && mdi_container.Widgets.Count > 0 && + ((Form) mdi_container.Widgets [0]).WindowState == FormWindowState.Maximized) { + MdiWindowManager wm = (MdiWindowManager) ((Form) mdi_container.Widgets [0]).WindowManager; + return wm.MaximizedMenu; + } + + Form amc = ActiveMdiChild; + if (amc == null || amc.Menu == null) + return menu; + return amc.MergedMenu; + } + } + + internal MdiWindowManager ActiveMaximizedMdiChild { + get { + Form child = ActiveMdiChild; + if (child == null) + return null; + if (child.WindowManager == null || child.window_state != FormWindowState.Maximized) + return null; + return (MdiWindowManager) child.WindowManager; + } + } + + [DefaultValue(true)] + [MWFCategory("Window Style")] + public bool MinimizeBox { + get { + return minimize_box; + } + set { + if (minimize_box != value) { + minimize_box = value; + UpdateStyles(); + } + } + } + + [Localizable(true)] + [RefreshProperties(RefreshProperties.Repaint)] + [MWFCategory("Layout")] + public override Size MinimumSize { + get { + return minimum_size; + } + + set { + if (minimum_size != value) { + minimum_size = value; + + // If this is bigger than the max, adjust the max + if (!maximum_size.IsEmpty) { + if (minimum_size.Width >= maximum_size.Width) + maximum_size.Width = minimum_size.Width; + if (minimum_size.Height >= maximum_size.Height) + maximum_size.Height = minimum_size.Height; + } + + if ((Size.Width < value.Width) || (Size.Height < value.Height)) { + Size = new Size(Math.Max(Size.Width, value.Width), Math.Max(Size.Height, value.Height)); + } + + + OnMinimumSizeChanged(EventArgs.Empty); + if (IsHandleCreated) { + XplatUI.SetWindowMinMax(Handle, maximized_bounds, minimum_size, maximum_size); + } + } + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool Modal { + get { + return is_modal; + } + } + + [DefaultValue(1D)] + [TypeConverter(typeof(OpacityConverter))] + [MWFCategory("Window Style")] + public double Opacity { + get { + if (IsHandleCreated) { + if ((XplatUI.SupportsTransparency () & TransparencySupport.Get) != 0) + return XplatUI.GetWindowTransparency (Handle); + } + + return opacity; + } + + set { + opacity = value; + + if (opacity < 0) + opacity = 0; + + if (opacity > 1) + opacity = 1; + + AllowTransparency = true; + + if (IsHandleCreated) { + UpdateStyles(); + if ((XplatUI.SupportsTransparency () & TransparencySupport.Set) != 0) + XplatUI.SetWindowTransparency(Handle, opacity, TransparencyKey); + } + } + } + + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Form[] OwnedForms { + get { + Form[] form_list; + + form_list = new Form[owned_forms.Count]; + + for (int i=0; i (); + foreach (Form form in Application.OpenForms) + if (form.Enabled) + disable.Add (form); + foreach (Form form in disable){ + disabled_by_showdialog.Add (form); + form.Enabled = false; + } + modal_dialogs.Add(this); + +#if not + // Commented out; we instead let the Visible=true inside the runloop create the Widget + // otherwise setting DialogResult inside any of the events that are triggered by the + // create will not actually cause the form to not be displayed. + // Leaving this comment here in case there was an actual purpose to creating the Widget + // in here. + if (!IsHandleCreated) { + CreateWidget(); + } +#endif + + Application.RunLoop(true, new ApplicationContext(this)); + + if (this.owner != null) { + // Cannot use Activate(), it has a check for the current active window... + XplatUI.Activate(this.owner.window.Handle); + } + + if (IsHandleCreated) { + DestroyHandle (); + } + + if (DialogResult == DialogResult.None) { + DialogResult = DialogResult.Cancel; + } + + return DialogResult; + } + + public override string ToString() { + return GetType().FullName + ", Text: " + Text; + } + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public override bool ValidateChildren () + { + return base.ValidateChildren (); + } + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public override bool ValidateChildren (ValidationConstraints validationConstraints) + { + return base.ValidateChildren (validationConstraints); + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + protected void ActivateMdiChild(Form form) { + if (!IsMdiContainer) + return; + mdi_container.ActivateChild (form); + OnMdiChildActivate(EventArgs.Empty); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void AdjustFormScrollbars(bool displayScrollbars) { + base.AdjustFormScrollbars (displayScrollbars); + } + + //[EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete ("This method has been deprecated")] // XXX what to use instead? + protected void ApplyAutoScaling() + { + SizeF current_size_f = GetAutoScaleSize (Font); + Size current_size = new Size ((int)Math.Round (current_size_f.Width), (int)Math.Round (current_size_f.Height)); + float dx; + float dy; + + if (current_size == autoscale_base_size) + return; + + if (Environment.GetEnvironmentVariable ("MONO_MWF_SCALING") == "disable"){ + return; + } + + // + // I tried applying the Fudge height factor from: + // http://blogs.msdn.com/mharsh/archive/2004/01/25/62621.aspx + // but it makes things larger without looking better. + // + if (current_size.Width != AutoScaleBaseSize.Width) { + dx = (float)current_size.Width / AutoScaleBaseSize.Width + 0.08f; + } else { + dx = 1; + } + + if (current_size.Height != AutoScaleBaseSize.Height) { + dy = (float)current_size.Height / AutoScaleBaseSize.Height + 0.08f; + } else { + dy = 1; + } + + Scale (dx, dy); + + AutoScaleBaseSize = current_size; + } + + protected void CenterToParent() { + Widget ctl; + int w; + int h; + + // MS creates the handle here. + if (TopLevel) { + if (!IsHandleCreated) + CreateHandle (); + } + + if (Width > 0) { + w = Width; + } else { + w = DefaultSize.Width; + } + + if (Height > 0) { + h = Height; + } else { + h = DefaultSize.Height; + } + + ctl = null; + if (Parent != null) { + ctl = Parent; + } else if (owner != null) { + ctl = owner; + } + + if (owner != null) { + this.Location = new Point(ctl.Left + ctl.Width / 2 - w /2, ctl.Top + ctl.Height / 2 - h / 2); + } + } + + protected void CenterToScreen() { + int w; + int h; + + // MS creates the handle here. + if (TopLevel) { + if (!IsHandleCreated) + CreateHandle (); + } + + if (Width > 0) { + w = Width; + } else { + w = DefaultSize.Width; + } + + if (Height > 0) { + h = Height; + } else { + h = DefaultSize.Height; + } + + Rectangle workingArea; + if (Owner == null) { + workingArea = Screen.FromPoint (MousePosition).WorkingArea; + } else { + workingArea = Screen.FromControl (Owner).WorkingArea; + } + this.Location = new Point (workingArea.Left + workingArea.Width / 2 - w / 2, + workingArea.Top + workingArea.Height / 2 - h / 2); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override Widget.WidgetCollection CreateWidgetsInstance() { + return base.CreateWidgetsInstance (); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void CreateHandle() { + base.CreateHandle (); + + if (!IsHandleCreated) { + return; + } + + UpdateBounds(); + + if ((XplatUI.SupportsTransparency() & TransparencySupport.Set) != 0) { + if (allow_transparency) { + XplatUI.SetWindowTransparency(Handle, opacity, TransparencyKey); + } + } + + XplatUI.SetWindowMinMax(window.Handle, maximized_bounds, minimum_size, maximum_size); + + if (show_icon && (FormBorderStyle != FormBorderStyle.FixedDialog) && (icon != null)) { + XplatUI.SetIcon(window.Handle, icon); + } + + if ((owner != null) && (owner.IsHandleCreated)) { + XplatUI.SetOwner(window.Handle, owner.window.Handle); + } + + if (topmost) { + XplatUI.SetTopmost(window.Handle, topmost); + } + + for (int i = 0; i < owned_forms.Count; i++) { + if (owned_forms[i].IsHandleCreated) + XplatUI.SetOwner(owned_forms[i].window.Handle, window.Handle); + } + + if (window_manager != null) { + if (IsMdiChild && VisibleInternal) { + MdiWindowManager wm; + // Loop through all the other mdi siblings and raise Deactivate events. + if (MdiParent != null) { + foreach (Form form in MdiParent.MdiChildren) { + wm = form.window_manager as MdiWindowManager; + if (wm != null && form != this) { + // This will only raise deactivate once, and only if activate has + // already been raised. + wm.RaiseDeactivate (); + } + } + } + + wm = window_manager as MdiWindowManager; + wm.RaiseActivated (); + + // We need to tell everyone who may have just been deactivated to redraw their titlebar + if (MdiParent != null) + foreach (Form form in MdiParent.MdiChildren) + if (form != this && form.IsHandleCreated) + XplatUI.InvalidateNC (form.Handle); + } + + if (window_state != FormWindowState.Normal) { + window_manager.SetWindowState ((FormWindowState) int.MaxValue, window_state); + } + XplatUI.RequestNCRecalc (window.Handle); + } + + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void DefWndProc(ref Message m) { + base.DefWndProc (ref m); + } + + protected override void Dispose(bool disposing) + { + if (owned_forms != null) { + for (int i = 0; i < owned_forms.Count; i++) + ((Form)owned_forms[i]).Owner = null; + + owned_forms.Clear (); + } + Owner = null; + base.Dispose (disposing); + + Application.RemoveForm (this); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void OnActivated(EventArgs e) + { + EventHandler eh = (EventHandler)(Events [ActivatedEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void OnClosed(EventArgs e) { + EventHandler eh = (EventHandler)(Events [ClosedEvent]); + if (eh != null) + eh (this, e); + } + + // Consider calling FireClosingEvents instead of calling this directly. + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnClosing(System.ComponentModel.CancelEventArgs e) { + CancelEventHandler eh = (CancelEventHandler)(Events [ClosingEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void OnCreateWidget() { + base.OnCreateWidget (); + + if (menu != null) { + XplatUI.SetMenu(window.Handle, menu); + } + + OnLoadInternal (EventArgs.Empty); + + // Send initial location + OnLocationChanged(EventArgs.Empty); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void OnDeactivate(EventArgs e) { + EventHandler eh = (EventHandler)(Events [DeactivateEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void OnFontChanged(EventArgs e) { + base.OnFontChanged (e); + + if (!autoscale_base_size_set) { + SizeF sizef = Form.GetAutoScaleSize (Font); + autoscale_base_size = new Size ((int)Math.Round (sizef.Width), (int)Math.Round (sizef.Height)); + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void OnHandleCreated(EventArgs e) { + XplatUI.SetBorderStyle(window.Handle, form_border_style); + base.OnHandleCreated (e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void OnHandleDestroyed(EventArgs e) { + Application.RemoveForm (this); + base.OnHandleDestroyed (e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void OnInputLanguageChanged(InputLanguageChangedEventArgs e) { + InputLanguageChangedEventHandler eh = (InputLanguageChangedEventHandler)(Events [InputLanguageChangedEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void OnInputLanguageChanging(InputLanguageChangingEventArgs e) { + InputLanguageChangingEventHandler eh = (InputLanguageChangingEventHandler)(Events [InputLanguageChangingEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void OnLoad (EventArgs e){ + Application.AddForm (this); + + EventHandler eh = (EventHandler)(Events[LoadEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void OnMaximizedBoundsChanged(EventArgs e) { + EventHandler eh = (EventHandler)(Events [MaximizedBoundsChangedEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void OnMaximumSizeChanged(EventArgs e) { + EventHandler eh = (EventHandler)(Events [MaximumSizeChangedEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void OnMdiChildActivate(EventArgs e) { + EventHandler eh = (EventHandler)(Events [MdiChildActivateEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected internal virtual void OnMenuComplete(EventArgs e) { + EventHandler eh = (EventHandler)(Events [MenuCompleteEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void OnMenuStart(EventArgs e) { + EventHandler eh = (EventHandler)(Events [MenuStartEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void OnMinimumSizeChanged(EventArgs e) { + EventHandler eh = (EventHandler)(Events [MinimumSizeChangedEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void OnPaint (PaintEventArgs e) { + base.OnPaint (e); + + if (size_grip != null) { + size_grip.HandlePaint (this, e); + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void OnResize(EventArgs e) { + base.OnResize(e); + + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void OnStyleChanged(EventArgs e) { + base.OnStyleChanged (e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void OnTextChanged(EventArgs e) { + base.OnTextChanged (e); + + if (mdi_container != null) + mdi_container.SetParentText(true); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void OnVisibleChanged(EventArgs e) { + base.OnVisibleChanged (e); + + if (Visible) { + if (window_manager != null) + if (WindowState == FormWindowState.Normal) + window_manager.SetWindowState (WindowState, WindowState); + else + // We don't really have an old_state, and if we pass the same thing, + // it may not really change the state for us + window_manager.SetWindowState ((FormWindowState)(-1), WindowState); + } + } + + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { + if (base.ProcessCmdKey (ref msg, keyData)) { + return true; + } + + // Handle keyboard cues state. + if ((keyData & Keys.Alt) != 0) { + Widget toplevel = TopLevelWidget; + if (toplevel != null) { + IntPtr param = MakeParam ((int) MsgUIState.UIS_CLEAR, (int) MsgUIState.UISF_HIDEACCEL); + XplatUI.SendMessage (toplevel.Handle, Msg.WM_CHANGEUISTATE, param, IntPtr.Zero); + } + } + + // Give our menu a shot + if (ActiveMenu != null) { + if (ActiveMenu.ProcessCmdKey (ref msg, keyData)) + return true; + } + + + if (IsMdiChild) { + switch (keyData) + { + case Keys.Widget | Keys.F4: + case Keys.Widget | Keys.Shift | Keys.F4: + Close (); + return true; + case Keys.Widget | Keys.Tab: + case Keys.Widget | Keys.F6: + MdiParent.MdiContainer.ActivateNextChild (); + return true; + case Keys.Widget | Keys.Shift | Keys.Tab: + case Keys.Widget | Keys.Shift | Keys.F6: + MdiParent.MdiContainer.ActivatePreviousChild (); + return true; + case Keys.Alt | Keys.OemMinus: + case Keys.Alt | Keys.Subtract: + (this.WindowManager as MdiWindowManager).ShowPopup (Point.Empty); + return true; + } + } + + return false; + } + + // LAMESPEC - Not documented that Form overrides ProcessDialogChar; class-status showed + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override bool ProcessDialogChar(char charCode) { + return base.ProcessDialogChar (charCode); + } + + protected override bool ProcessDialogKey(Keys keyData) { + if ((keyData & Keys.Modifiers) == 0) { + if (keyData == Keys.Enter) { + IntPtr window = XplatUI.GetFocus (); + Widget c = Widget.FromHandle (window); + if (c is Button && c.FindForm () == this) { + ((Button)c).PerformClick (); + return true; + } + else if (accept_button != null) { + // Set ActiveWidget to force any Validation to take place. + ActiveWidget = (accept_button as Widget); + if (ActiveWidget == accept_button) // else Validation failed + accept_button.PerformClick(); + return true; + } + } else if (keyData == Keys.Escape && cancel_button != null) { + cancel_button.PerformClick(); + return true; + } + } + return base.ProcessDialogKey(keyData); + } + + protected override bool ProcessKeyPreview(ref Message m) { + if (key_preview) { + if (ProcessKeyEventArgs(ref m)) { + return true; + } + } + return base.ProcessKeyPreview (ref m); + } + + protected override bool ProcessTabKey(bool forward) { + bool need_refresh = !show_focus_cues; + show_focus_cues = true; + + bool Widget_activated = SelectNextWidget(ActiveWidget, forward, true, true, true); + + if (need_refresh && ActiveWidget != null) + ActiveWidget.Invalidate (); + + return Widget_activated; + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + protected override void ScaleCore (float x, float y) + { + base.ScaleCore (x, y); + } + + protected override void Select(bool directed, bool forward) { + Form parent; + + + // MS causes the handle to be created here. + if (!IsHandleCreated) + if (!IsHandleCreated) + CreateHandle (); + + if (directed) { + base.SelectNextWidget(null, forward, true, true, true); + } + + parent = this.ParentForm; + if (parent != null) { + parent.ActiveWidget = this; + } + + Activate(); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) { + Size min_size; + + if (WindowState == FormWindowState.Minimized) + min_size = SystemInformation.MinimizedWindowSize; + else + switch (FormBorderStyle) { + case FormBorderStyle.None: + min_size = XplatUI.MinimumNoBorderWindowSize; + break; + case FormBorderStyle.FixedToolWindow: + min_size = XplatUI.MinimumFixedToolWindowSize; + break; + case FormBorderStyle.SizableToolWindow: + min_size = XplatUI.MinimumSizeableToolWindowSize; + break; + default: + min_size = SystemInformation.MinimumWindowSize; + break; + } + + if ((specified & BoundsSpecified.Width) == BoundsSpecified.Width) + width = Math.Max (width, min_size.Width); + if ((specified & BoundsSpecified.Height) == BoundsSpecified.Height) + height = Math.Max (height, min_size.Height); + + base.SetBoundsCore (x, y, width, height, specified); + + int restore_x = (specified & BoundsSpecified.X) == BoundsSpecified.X ? x : restore_bounds.X; + int restore_y = (specified & BoundsSpecified.Y) == BoundsSpecified.Y ? y : restore_bounds.Y; + int restore_w = (specified & BoundsSpecified.Width) == BoundsSpecified.Width ? width : restore_bounds.Width; + int restore_h = (specified & BoundsSpecified.Height) == BoundsSpecified.Height ? height : restore_bounds.Height; + restore_bounds = new Rectangle (restore_x, restore_y, restore_w, restore_h); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void SetClientSizeCore(int x, int y) { + if ((minimum_size.Width != 0) && (x < minimum_size.Width)) { + x = minimum_size.Width; + } else if ((maximum_size.Width != 0) && (x > maximum_size.Width)) { + x = maximum_size.Width; + } + + if ((minimum_size.Height != 0) && (y < minimum_size.Height)) { + y = minimum_size.Height; + } else if ((maximum_size.Height != 0) && (y > maximum_size.Height)) { + y = maximum_size.Height; + } + + Rectangle ClientRect = new Rectangle(0, 0, x, y); + Rectangle WindowRect; + CreateParams cp = this.CreateParams; + + clientsize_set = new Size(x, y); + + if (XplatUI.CalculateWindowRect(ref ClientRect, cp, cp.menu, out WindowRect)) { + SetBounds(bounds.X, bounds.Y, WindowRect.Width, WindowRect.Height, BoundsSpecified.Size); + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void SetVisibleCore(bool value) + { + if (value) + close_raised = false; + + if (IsMdiChild && !MdiParent.Visible) { + if (value != Visible) { + MdiWindowManager wm = (MdiWindowManager) window_manager; + wm.IsVisiblePending = value; + OnVisibleChanged (EventArgs.Empty); + return; + } + } else { + is_changing_visible_state++; + has_been_visible = value || has_been_visible; + base.SetVisibleCore (value); + if (value) { + Application.AddForm (this); + } + + if (value && WindowState != FormWindowState.Normal) + XplatUI.SendMessage (Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero); + + is_changing_visible_state--; + } + + if (value && IsMdiContainer) { + Form [] children = MdiChildren; + for (int i = 0; i < children.Length; i++) { + Form child = children [i]; + MdiWindowManager wm = (MdiWindowManager) child.window_manager; + if (!child.IsHandleCreated && wm.IsVisiblePending) { + wm.IsVisiblePending = false; + child.Visible = true; + } + } + } + + if (value && IsMdiChild){ + PerformLayout (); + ThemeEngine.Current.ManagedWindowSetButtonLocations (window_manager); + } + + // Shown event is only called once, the first time the form is made visible + if (value && !shown_raised) { + this.OnShown (EventArgs.Empty); + shown_raised = true; + } + + if (value && !IsMdiChild) { + if (ActiveWidget == null) + SelectNextWidget (null, true, true, true, false); + if (ActiveWidget != null) + SendWidgetFocus (ActiveWidget); + else + this.Focus (); + } + } + + protected override void UpdateDefaultButton() { + base.UpdateDefaultButton (); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void WndProc(ref Message m) { +#if debug + Console.WriteLine(DateTime.Now.ToLongTimeString () + " Form {0} ({2}) received message {1}", window.Handle == IntPtr.Zero ? this.Text : XplatUI.Window(window.Handle), m.ToString (), Text); +#endif + + if (window_manager != null && window_manager.WndProc (ref m)) { + return; + } + + switch ((Msg)m.Msg) { + case Msg.WM_DESTROY: { + WmDestroy (ref m); + return; + } + + case Msg.WM_CLOSE: { + WmClose (ref m); + return; + } + + case Msg.WM_WINDOWPOSCHANGED: { + WmWindowPosChanged (ref m); + return; + } + + case Msg.WM_SYSCOMMAND: { + WmSysCommand (ref m); + break; + } + + case Msg.WM_ACTIVATE: { + WmActivate (ref m); + return; + } + + case Msg.WM_KILLFOCUS: { + WmKillFocus (ref m); + return; + } + + case Msg.WM_SETFOCUS: { + WmSetFocus (ref m); + return; + } + + // Menu drawing + case Msg.WM_NCHITTEST: { + WmNcHitTest (ref m); + return; + } + + case Msg.WM_NCLBUTTONDOWN: { + WmNcLButtonDown (ref m); + return; + } + + case Msg.WM_NCLBUTTONUP: { + WmNcLButtonUp (ref m); + return; + } + + case Msg.WM_NCMOUSELEAVE: { + WmNcMouseLeave (ref m); + return; + } + + case Msg.WM_NCMOUSEMOVE: { + WmNcMouseMove (ref m); + return; + } + + case Msg.WM_NCPAINT: { + WmNcPaint (ref m); + return; + } + + case Msg.WM_NCCALCSIZE: { + WmNcCalcSize (ref m); + break; + } + + case Msg.WM_GETMINMAXINFO: { + WmGetMinMaxInfo (ref m); + break; + } + + case Msg.WM_ENTERSIZEMOVE: { + OnResizeBegin (EventArgs.Empty); + break; + } + + case Msg.WM_EXITSIZEMOVE: { + OnResizeEnd (EventArgs.Empty); + break; + } + + default: { + base.WndProc (ref m); + break; + } + } + } + #endregion // Protected Instance Methods + +#region WM methods + + private void WmDestroy (ref Message m) + { + if (!RecreatingHandle) + this.closing = true; + + base.WndProc (ref m); + } + + internal bool RaiseCloseEvents (bool last_check, bool cancel) + { + if (last_check && Visible) { + Hide (); + } + + if (close_raised || (last_check && closed)) { + return false; + } + + close_raised = true; + bool cancelled = FireClosingEvents (CloseReason.UserClosing, cancel); + if (!cancelled) { + if (!last_check || DialogResult != DialogResult.None) { + if (mdi_container != null) + foreach (Form mdi_child in mdi_container.MdiChildren) + mdi_child.FireClosedEvents (CloseReason.UserClosing); + + FireClosedEvents (CloseReason.UserClosing); + } + closing = true; + shown_raised = false; + } else { + DialogResult = DialogResult.None; + closing = false; + close_raised = false; + } + + return cancelled; + } + + private void WmClose (ref Message m) + { + if (this.Enabled == false) + return; // prevent closing a disabled form. + + Form act = Form.ActiveForm; + // Don't close this form if there's another modal form visible. + if (act != null && act != this && act.Modal == true) { + // Check if any of the parents up the tree is the modal form, + // in which case we can still close this form. + Widget current = this; + while (current != null && current.Parent != act) { + current = current.Parent; + } + if (current == null || current.Parent != act) { + return; + } + } + + bool mdi_cancel = false; + + // Give any MDI children the opportunity to cancel the close + if (mdi_container != null) + foreach (Form mdi_child in mdi_container.MdiChildren) + mdi_cancel = mdi_child.FireClosingEvents (CloseReason.MdiFormClosing, mdi_cancel); + + bool validate_cancel = false; + if (!suppress_closing_events) + validate_cancel = !ValidateChildren (); + + if (suppress_closing_events || + !RaiseCloseEvents (false, validate_cancel || mdi_cancel)) { + if (is_modal) { + Hide (); + } else { + Dispose (); + if (act != null && act != this) + act.SelectActiveWidget (); + } + mdi_parent = null; + } else { + if (is_modal) { + DialogResult = DialogResult.None; + } + closing = false; + } + } + + private void WmWindowPosChanged (ref Message m) + { + // When a form is minimized/restored: + // * Win32: X and Y are set to negative values/restored, + // size remains the same. + // * X11: Location and Size remain the same. + // + // In both cases we have to fire Resize explicitly here, + // because of the unmodified Size due to which Widget + // doesn't fire it. + // + if (window_state != FormWindowState.Minimized && WindowState != FormWindowState.Minimized) + base.WndProc (ref m); + else { // minimized or restored + if (!is_minimizing) { + // Avoid recursive calls here as code in OnSizeChanged might + // cause a WM_WINDOWPOSCHANGED to be sent. + is_minimizing = true; + OnSizeChanged (EventArgs.Empty); + is_minimizing = false; + } + } + + if (WindowState == FormWindowState.Normal) + restore_bounds = Bounds; + } + + private void WmSysCommand (ref Message m) + { + // Let *Strips know the app's title bar was clicked + if (XplatUI.IsEnabled (Handle)) + ToolStripManager.FireAppClicked (); + + base.WndProc (ref m); + } + + private void WmActivate (ref Message m) + { + if (!this.Enabled && modal_dialogs.Count > 0) + { + (modal_dialogs[modal_dialogs.Count -1] as Form).Activate (); + return; // prevent Activating of disabled form. + } + + if (m.WParam != (IntPtr)WindowActiveFlags.WA_INACTIVE) { + if (is_loaded) { + SelectActiveWidget (); + + if (ActiveWidget != null && !ActiveWidget.Focused) + SendWidgetFocus (ActiveWidget); + } + + IsActive = true; + } else { + if (XplatUI.IsEnabled (Handle) && XplatUI.GetParent (m.LParam) != Handle) + ToolStripManager.FireAppFocusChanged (this); + IsActive = false; + } + } + + private void WmKillFocus (ref Message m) + { + base.WndProc (ref m); + } + + private void WmSetFocus (ref Message m) + { + if (ActiveWidget != null && ActiveWidget != this) { + ActiveWidget.Focus (); + return; // FIXME - do we need to run base.WndProc, even though we just changed focus? + } + if (IsMdiContainer) { + mdi_container.SendFocusToActiveChild (); + return; + } + base.WndProc (ref m); + } + + private void WmNcHitTest (ref Message m) + { + if (XplatUI.IsEnabled (Handle) && ActiveMenu != null) { + int x = LowOrder ((int)m.LParam.ToInt32 ()); + int y = HighOrder ((int)m.LParam.ToInt32 ()); + + XplatUI.ScreenToMenu (ActiveMenu.Wnd.window.Handle, ref x, ref y); + + // If point is under menu return HTMENU, it prevents Win32 to return HTMOVE. + if ((x > 0) && (y > 0) && (x < ActiveMenu.Rect.Width) && (y < ActiveMenu.Rect.Height)) { + m.Result = new IntPtr ((int)HitTest.HTMENU); + return; + } + } + + base.WndProc (ref m); + } + + private void WmNcLButtonDown (ref Message m) + { + if (XplatUI.IsEnabled (Handle) && ActiveMenu != null) { + ActiveMenu.OnMouseDown (this, new MouseEventArgs (FromParamToMouseButtons ((int)m.WParam.ToInt32 ()), mouse_clicks, Widget.MousePosition.X, Widget.MousePosition.Y, 0)); + } + + if (ActiveMaximizedMdiChild != null && ActiveMenu != null) { + if (ActiveMaximizedMdiChild.HandleMenuMouseDown (ActiveMenu, + LowOrder ((int)m.LParam.ToInt32 ()), + HighOrder ((int)m.LParam.ToInt32 ()))) { + // Don't let base process this message, otherwise we won't + // get a WM_NCLBUTTONUP. + return; + } + } + base.WndProc (ref m); + } + + private void WmNcLButtonUp (ref Message m) + { + if (ActiveMaximizedMdiChild != null && ActiveMenu != null) { + ActiveMaximizedMdiChild.HandleMenuMouseUp (ActiveMenu, + LowOrder ((int)m.LParam.ToInt32 ()), + HighOrder ((int)m.LParam.ToInt32 ())); + } + base.WndProc (ref m); + } + + private void WmNcMouseLeave (ref Message m) + { + if (ActiveMaximizedMdiChild != null && ActiveMenu != null) { + ActiveMaximizedMdiChild.HandleMenuMouseLeave (ActiveMenu, + LowOrder ((int)m.LParam.ToInt32 ()), + HighOrder ((int)m.LParam.ToInt32 ())); + } + base.WndProc (ref m); + } + + private void WmNcMouseMove (ref Message m) + { + if (XplatUI.IsEnabled (Handle) && ActiveMenu != null) { + ActiveMenu.OnMouseMove (this, new MouseEventArgs (FromParamToMouseButtons ((int)m.WParam.ToInt32 ()), mouse_clicks, LowOrder ((int)m.LParam.ToInt32 ()), HighOrder ((int)m.LParam.ToInt32 ()), 0)); + } + + if (ActiveMaximizedMdiChild != null && ActiveMenu != null) { + XplatUI.RequestAdditionalWM_NCMessages (Handle, false, true); + ActiveMaximizedMdiChild.HandleMenuMouseMove (ActiveMenu, + LowOrder ((int)m.LParam.ToInt32 ()), + HighOrder ((int)m.LParam.ToInt32 ())); + } + base.WndProc (ref m); + } + + private void WmNcPaint (ref Message m) + { + if (ActiveMenu != null) { + PaintEventArgs pe = XplatUI.PaintEventStart (ref m, Handle, false); + Point pnt = XplatUI.GetMenuOrigin (window.Handle); + + // The entire menu has to be in the clip rectangle because the + // Widget buttons are right-aligned and otherwise they would + // stay painted when the window gets resized. + Rectangle clip = new Rectangle (pnt.X, pnt.Y, ClientSize.Width, 0); + clip = Rectangle.Union (clip, pe.ClipRectangle); + pe.SetClip (clip); + pe.Graphics.SetClip (clip); + + ActiveMenu.Draw (pe, new Rectangle (pnt.X, pnt.Y, ClientSize.Width, 0)); + + if (ActiveMaximizedMdiChild != null) + ActiveMaximizedMdiChild.DrawMaximizedButtons (ActiveMenu, pe); + + XplatUI.PaintEventEnd (ref m, Handle, false); + } + + base.WndProc (ref m); + } + + private void WmNcCalcSize (ref Message m) + { + XplatUIWin32.NCCALCSIZE_PARAMS ncp; + + if ((ActiveMenu != null) && (m.WParam == (IntPtr)1)) { + ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure (m.LParam, typeof (XplatUIWin32.NCCALCSIZE_PARAMS)); + + // Adjust for menu + ncp.rgrc1.top += ThemeEngine.Current.CalcMenuBarSize (DeviceContext, ActiveMenu, ClientSize.Width); + Marshal.StructureToPtr (ncp, m.LParam, true); + } + DefWndProc (ref m); + } + + private void WmGetMinMaxInfo (ref Message m) + { + MINMAXINFO mmi; + + if (m.LParam != IntPtr.Zero) { + mmi = (MINMAXINFO)Marshal.PtrToStructure (m.LParam, typeof (MINMAXINFO)); + + default_maximized_bounds = new Rectangle (mmi.ptMaxPosition.x, mmi.ptMaxPosition.y, mmi.ptMaxSize.x, mmi.ptMaxSize.y); + if (maximized_bounds != Rectangle.Empty) { + mmi.ptMaxPosition.x = maximized_bounds.Left; + mmi.ptMaxPosition.y = maximized_bounds.Top; + mmi.ptMaxSize.x = maximized_bounds.Width; + mmi.ptMaxSize.y = maximized_bounds.Height; + } + + if (minimum_size != Size.Empty) { + mmi.ptMinTrackSize.x = minimum_size.Width; + mmi.ptMinTrackSize.y = minimum_size.Height; + } + + if (maximum_size != Size.Empty) { + mmi.ptMaxTrackSize.x = maximum_size.Width; + mmi.ptMaxTrackSize.y = maximum_size.Height; + } + Marshal.StructureToPtr (mmi, m.LParam, false); + } + } +#endregion + + #region Internal / Private Methods + internal void ActivateFocusCues () + { + bool need_refresh = !show_focus_cues; + show_focus_cues = true; + + if (need_refresh) + ActiveWidget.Invalidate (); + } + + internal override void FireEnter () + { + // do nothing - forms don't generate OnEnter + } + + internal override void FireLeave () + { + // do nothing - forms don't generate OnLeave + } + + internal void RemoveWindowManager () + { + window_manager = null; + } + + internal override void CheckAcceptButton () + { + if (accept_button != null) { + Button a_button = accept_button as Button; + + if (ActiveWidget == a_button) + return; + + // If the accept_button isn't a Button, we don't need to do + // the rest of this. + if (a_button == null) + return; + + if (ActiveWidget is Button) + a_button.paint_as_acceptbutton = false; + else + a_button.paint_as_acceptbutton = true; + + a_button.Invalidate (); + } + } + + internal override bool ActivateOnShow { get { return !this.ShowWithoutActivation; } } + + private void OnLoadInternal (EventArgs e) + { + if (AutoScale) { + ApplyAutoScaling (); + AutoScale = false; + } + + if (!IsDisposed) { + OnSizeInitializedOrChanged (); + + // We do this here because when we load the MainForm, + // it happens before the exception catcher in NativeWindow, + // so the user can error in handling Load and we wouldn't catch it. + try { + OnLoad (e); + } + catch (Exception ex) { + Application.OnThreadException (ex); + } + + if (!IsDisposed) + is_visible = true; + } + + if (!IsMdiChild && !IsDisposed) { + switch (StartPosition) { + case FormStartPosition.CenterScreen: + this.CenterToScreen (); + break; + case FormStartPosition.CenterParent: + this.CenterToParent (); + break; + case FormStartPosition.Manual: + Left = CreateParams.X; + Top = CreateParams.Y; + break; + } + } + + is_loaded = true; + } + #endregion + + #region Events + static object ActivatedEvent = new object (); + static object ClosedEvent = new object (); + static object ClosingEvent = new object (); + static object DeactivateEvent = new object (); + static object InputLanguageChangedEvent = new object (); + static object InputLanguageChangingEvent = new object (); + static object LoadEvent = new object (); + static object MaximizedBoundsChangedEvent = new object (); + static object MaximumSizeChangedEvent = new object (); + static object MdiChildActivateEvent = new object (); + static object MenuCompleteEvent = new object (); + static object MenuStartEvent = new object (); + static object MinimumSizeChangedEvent = new object (); + + public event EventHandler Activated { + add { Events.AddHandler (ActivatedEvent, value); } + remove { Events.RemoveHandler (ActivatedEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public event EventHandler Closed { + add { Events.AddHandler (ClosedEvent, value); } + remove { Events.RemoveHandler (ClosedEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public event CancelEventHandler Closing { + add { Events.AddHandler (ClosingEvent, value); } + remove { Events.RemoveHandler (ClosingEvent, value); } + } + + public event EventHandler Deactivate { + add { Events.AddHandler (DeactivateEvent, value); } + remove { Events.RemoveHandler (DeactivateEvent, value); } + } + + public event InputLanguageChangedEventHandler InputLanguageChanged { + add { Events.AddHandler (InputLanguageChangedEvent, value); } + remove { Events.RemoveHandler (InputLanguageChangedEvent, value); } + } + + public event InputLanguageChangingEventHandler InputLanguageChanging { + add { Events.AddHandler (InputLanguageChangingEvent, value); } + remove { Events.RemoveHandler (InputLanguageChangingEvent, value); } + } + + public event EventHandler Load { + add { Events.AddHandler (LoadEvent, value); } + remove { Events.RemoveHandler (LoadEvent, value); } + } + + public event EventHandler MaximizedBoundsChanged { + add { Events.AddHandler (MaximizedBoundsChangedEvent, value); } + remove { Events.RemoveHandler (MaximizedBoundsChangedEvent, value); } + } + + public event EventHandler MaximumSizeChanged { + add { Events.AddHandler (MaximumSizeChangedEvent, value); } + remove { Events.RemoveHandler (MaximumSizeChangedEvent, value); } + } + + public event EventHandler MdiChildActivate { + add { Events.AddHandler (MdiChildActivateEvent, value); } + remove { Events.RemoveHandler (MdiChildActivateEvent, value); } + } + + [Browsable (false)] + public event EventHandler MenuComplete { + add { Events.AddHandler (MenuCompleteEvent, value); } + remove { Events.RemoveHandler (MenuCompleteEvent, value); } + } + + [Browsable (false)] + public event EventHandler MenuStart { + add { Events.AddHandler (MenuStartEvent, value); } + remove { Events.RemoveHandler (MenuStartEvent, value); } + } + + public event EventHandler MinimumSizeChanged { + add { Events.AddHandler (MinimumSizeChangedEvent, value); } + remove { Events.RemoveHandler (MinimumSizeChangedEvent, value); } + } + + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler TabIndexChanged { + add { base.TabIndexChanged += value; } + remove { base.TabIndexChanged -= value; } + } + + [SettingsBindable (true)] + public override string Text { + get { + return base.Text; + } + + set { + base.Text = value; + ResetSkin(); + } + } + + [SettingsBindable (true)] + public new Point Location { + get { + return base.Location; + } + + set { + base.Location = value; + } + } + + static object FormClosingEvent = new object (); + static object FormClosedEvent = new object (); + static object HelpButtonClickedEvent = new object (); + static object ResizeEndEvent = new object (); + static object ResizeBeginEvent = new object (); + static object RightToLeftLayoutChangedEvent = new object (); + static object ShownEvent = new object (); + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler AutoSizeChanged { + add { base.AutoSizeChanged += value; } + remove { base.AutoSizeChanged -= value; } + } + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler AutoValidateChanged { + add { base.AutoValidateChanged += value; } + remove { base.AutoValidateChanged -= value; } + } + + public event FormClosingEventHandler FormClosing { + add { Events.AddHandler (FormClosingEvent, value); } + remove { Events.RemoveHandler (FormClosingEvent, value); } + } + + public event FormClosedEventHandler FormClosed { + add { Events.AddHandler (FormClosedEvent, value); } + remove { Events.RemoveHandler (FormClosedEvent, value); } + } + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public event CancelEventHandler HelpButtonClicked { + add { Events.AddHandler (HelpButtonClickedEvent, value); } + remove { Events.RemoveHandler (HelpButtonClickedEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler MarginChanged { + add { base.MarginChanged += value; } + remove { base.MarginChanged -= value; } + } + + public event EventHandler RightToLeftLayoutChanged { + add { Events.AddHandler (RightToLeftLayoutChangedEvent, value); } + remove { Events.RemoveHandler (RightToLeftLayoutChangedEvent, value); } + } + + public event EventHandler ResizeBegin { + add { Events.AddHandler (ResizeBeginEvent, value); } + remove { Events.RemoveHandler (ResizeBeginEvent, value); } + } + + public event EventHandler ResizeEnd { + add { Events.AddHandler (ResizeEndEvent, value); } + remove { Events.RemoveHandler (ResizeEndEvent, value); } + } + + public event EventHandler Shown { + add { Events.AddHandler (ShownEvent, value); } + remove { Events.RemoveHandler (ShownEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TabStopChanged { + add { base.TabStopChanged += value; } + remove { base.TabStopChanged -= value; } + } + + protected override void OnBackgroundImageChanged (EventArgs e) + { + base.OnBackgroundImageChanged (e); + } + + protected override void OnBackgroundImageLayoutChanged (EventArgs e) + { + base.OnBackgroundImageLayoutChanged (e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void OnEnabledChanged (EventArgs e) + { + base.OnEnabledChanged (e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void OnEnter (EventArgs e) + { + base.OnEnter (e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnFormClosed (FormClosedEventArgs e) { + Application.RemoveForm (this); + FormClosedEventHandler eh = (FormClosedEventHandler)(Events[FormClosedEvent]); + if (eh != null) + eh (this, e); + + foreach (Form form in disabled_by_showdialog) + { + form.Enabled = true; + } + disabled_by_showdialog.Clear(); + if (modal_dialogs.Contains(this)) + modal_dialogs.Remove(this); + } + + // Consider calling FireClosingEvents instead of calling this directly. + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnFormClosing (FormClosingEventArgs e) + { + FormClosingEventHandler eh = (FormClosingEventHandler)(Events [FormClosingEvent]); + if (eh != null) + eh (this, e); + } + + [MonoTODO ("Will never be called")] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnHelpButtonClicked (CancelEventArgs e) + { + CancelEventHandler eh = (CancelEventHandler)(Events[HelpButtonClickedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnLayout (LayoutEventArgs levent) + { + base.OnLayout (levent); + + if (AutoSize) { + Size new_size = GetPreferredSizeCore (Size.Empty); + if (AutoSizeMode == AutoSizeMode.GrowOnly) { + new_size.Width = Math.Max (new_size.Width, Width); + new_size.Height = Math.Max (new_size.Height, Height); + } + if (new_size == Size) + return; + + SetBoundsInternal (bounds.X, bounds.Y, new_size.Width, new_size.Height, BoundsSpecified.None); + } + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnResizeBegin (EventArgs e) + { + EventHandler eh = (EventHandler) (Events [ResizeBeginEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnResizeEnd (EventArgs e) + { + EventHandler eh = (EventHandler) (Events [ResizeEndEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnRightToLeftLayoutChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events[RightToLeftLayoutChangedEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnShown (EventArgs e) + { + EventHandler eh = (EventHandler) (Events [ShownEvent]); + if (eh != null) + eh (this, e); + } + + #region UIA Framework Events + static object UIAMenuChangedEvent = new object (); + static object UIATopMostChangedEvent = new object (); + static object UIAWindowStateChangedEvent = new object (); + + internal event EventHandler UIAMenuChanged { + add { Events.AddHandler (UIAMenuChangedEvent, value); } + remove { Events.RemoveHandler (UIAMenuChangedEvent, value); } + } + + internal event EventHandler UIATopMostChanged { + add { Events.AddHandler (UIATopMostChangedEvent, value); } + remove { Events.RemoveHandler (UIATopMostChangedEvent, value); } + } + + internal event EventHandler UIAWindowStateChanged { + add { Events.AddHandler (UIAWindowStateChangedEvent, value); } + remove { Events.RemoveHandler (UIAWindowStateChangedEvent, value); } + } + + internal void OnUIAMenuChanged (EventArgs e) + { + EventHandler eh = (EventHandler) Events [UIAMenuChangedEvent]; + if (eh != null) + eh (this, e); + } + + internal void OnUIATopMostChanged () + { + EventHandler eh = (EventHandler) Events [UIATopMostChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + + internal void OnUIAWindowStateChanged () + { + EventHandler eh = (EventHandler) Events [UIAWindowStateChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + #endregion // UIA Framework Events + #endregion // Events + } +} diff --git a/source/ShiftUI/Form/FormClosedEventArgs.cs b/source/ShiftUI/Form/FormClosedEventArgs.cs new file mode 100644 index 0000000..376ab8c --- /dev/null +++ b/source/ShiftUI/Form/FormClosedEventArgs.cs @@ -0,0 +1,49 @@ +// +// FormClosedEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + public class FormClosedEventArgs : EventArgs + { + private CloseReason close_reason; + + #region Public Constructors + public FormClosedEventArgs (CloseReason closeReason) + { + this.close_reason = closeReason; + } + #endregion // Public Constructors + + #region Public Instance Properties + public CloseReason CloseReason { + get { return this.close_reason; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Form/FormClosedEventHandler.cs b/source/ShiftUI/Form/FormClosedEventHandler.cs new file mode 100644 index 0000000..3f8585c --- /dev/null +++ b/source/ShiftUI/Form/FormClosedEventHandler.cs @@ -0,0 +1,32 @@ +// +// FormClosedEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void FormClosedEventHandler (object sender, FormClosedEventArgs e); +} \ No newline at end of file diff --git a/source/ShiftUI/Form/FormClosingEventArgs.cs b/source/ShiftUI/Form/FormClosingEventArgs.cs new file mode 100644 index 0000000..b221ec1 --- /dev/null +++ b/source/ShiftUI/Form/FormClosingEventArgs.cs @@ -0,0 +1,51 @@ +// +// FormClosingEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +using System.ComponentModel; + +namespace ShiftUI +{ + public class FormClosingEventArgs : CancelEventArgs + { + private CloseReason close_reason; + + #region Public Constructors + public FormClosingEventArgs (CloseReason closeReason, bool cancel) : base (cancel) + { + this.close_reason = closeReason; + } + #endregion // Public Constructors + + #region Public Instance Properties + public CloseReason CloseReason { + get { return this.close_reason; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Form/FormClosingEventHandler.cs b/source/ShiftUI/Form/FormClosingEventHandler.cs new file mode 100644 index 0000000..f4fffca --- /dev/null +++ b/source/ShiftUI/Form/FormClosingEventHandler.cs @@ -0,0 +1,32 @@ +// +// FormClosingEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void FormClosingEventHandler (object sender, FormClosingEventArgs e); +} diff --git a/source/ShiftUI/Form/FormCollection.cs b/source/ShiftUI/Form/FormCollection.cs new file mode 100644 index 0000000..a8314a5 --- /dev/null +++ b/source/ShiftUI/Form/FormCollection.cs @@ -0,0 +1,73 @@ +// +// FormCollection.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; +using System.Collections; +using System.Text; + +namespace ShiftUI +{ + public class FormCollection : ReadOnlyCollectionBase + { + public FormCollection () : base () + { + } + + #region Public Properties + public virtual Form this[int index] { + get { + return (Form)base.InnerList[index]; + } + } + + public virtual Form this[string name] { + get { + foreach (Form f in base.InnerList) + if (f.Name == name) + return f; + + return null; + } + } + #endregion + + #region Internal Add/Remove Methods + internal void Add (Form form) + { + if (base.InnerList.Contains (form)) + return; + + base.InnerList.Add (form); + } + + internal void Remove (Form form) + { + base.InnerList.Remove (form); + } + #endregion + } +} diff --git a/source/ShiftUI/Form/FormStartPosition.cs b/source/ShiftUI/Form/FormStartPosition.cs new file mode 100644 index 0000000..9c0cc79 --- /dev/null +++ b/source/ShiftUI/Form/FormStartPosition.cs @@ -0,0 +1,39 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Ravindra (rkumar@novell.com) +// + +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ComVisible (true)] + public enum FormStartPosition + { + Manual = 0, + CenterScreen = 1, + WindowsDefaultLocation = 2, + WindowsDefaultBounds = 3, + CenterParent = 4 + } +} diff --git a/source/ShiftUI/Form/FormWindowManager.cs b/source/ShiftUI/Form/FormWindowManager.cs new file mode 100644 index 0000000..c8222fe --- /dev/null +++ b/source/ShiftUI/Form/FormWindowManager.cs @@ -0,0 +1,87 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Rolf Bjarne Kvinge (RKvinge@novell.com) +// +// + + +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + internal class FormWindowManager : InternalWindowManager + { + private bool pending_activation; + public FormWindowManager (Form form) : base (form) + { + + form.MouseCaptureChanged += new EventHandler (HandleCaptureChanged); + } + + void HandleCaptureChanged (object sender, EventArgs e) + { + if (pending_activation && !form.Capture) { + form.BringToFront (); + pending_activation = false; + } + } + + public override void PointToClient (ref int x, ref int y) + { + XplatUI.ScreenToClient (Form.Parent.Handle, ref x, ref y); + } + + + protected override bool HandleNCLButtonDown (ref Message m) + { + // MS seems to be doing this on mouse up, but we don't get WM_NCLBUTTONUP when anything is captured + // so work around this using MouseCaptureChanged. + pending_activation = true; + + return base.HandleNCLButtonDown (ref m); + } + + protected override void HandleTitleBarDoubleClick (int x, int y) + { + if (IconRectangleContains (x, y)) { + form.Close (); + } else if (form.WindowState == FormWindowState.Maximized) { + form.WindowState = FormWindowState.Normal; + } else { + form.WindowState = FormWindowState.Maximized; + } + base.HandleTitleBarDoubleClick (x, y); + } + + internal override Rectangle MaximizedBounds { + get { + Rectangle result = base.MaximizedBounds; + int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this); + result.Inflate (bw, bw); + return result; + } + } + } +} diff --git a/source/ShiftUI/Form/FormWindowState.cs b/source/ShiftUI/Form/FormWindowState.cs new file mode 100644 index 0000000..40a970f --- /dev/null +++ b/source/ShiftUI/Form/FormWindowState.cs @@ -0,0 +1,38 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Ravindra (rkumar@novell.com) +// + + +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ComVisible (true)] + public enum FormWindowState + { + Normal = 0, + Minimized = 1, + Maximized = 2 + } +} diff --git a/source/ShiftUI/Form/MessageBox.cs b/source/ShiftUI/Form/MessageBox.cs new file mode 100644 index 0000000..aab960a --- /dev/null +++ b/source/ShiftUI/Form/MessageBox.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ShiftUI +{ + public class MessageBox : Form + { + + public static void Show(string message, string title) + { + var m = new MessageBox(title, message); + + m.TopMost = true; + m.ShowDialog(); + } + + public MessageBox(string title, string message) + { + var pnlbottom = new FlowLayoutPanel(); + pnlbottom.Height = 30; + pnlbottom.BackColor = Application.CurrentSkin.MessageBox_BottomPanel; + var pnltop = new Panel(); + pnlbottom.Dock = DockStyle.Bottom; + pnltop.Dock = DockStyle.Fill; + this.Widgets.Add(pnlbottom); + pnlbottom.Show(); + this.Widgets.Add(pnltop); + pnltop.Show(); + var btnok = new Button(); + btnok.Text = "OK"; + btnok.AutoSize = true; + btnok.AutoSizeMode = AutoSizeMode.GrowAndShrink; + pnlbottom.Widgets.Add(btnok); + btnok.Show(); + btnok.Click += (s, a) => + { + this.Close(); + }; + var lblmessage = new Label(); + lblmessage.Padding = new Padding(25); + lblmessage.Text = message; + lblmessage.Dock = DockStyle.Fill; + pnltop.Widgets.Add(lblmessage); + lblmessage.Show(); + //autosize the form + int newheight = 10; + for(int i = 0; i < lblmessage.Text.Length; i++) + { + if ((i % 2) == 0) + newheight += 10; + } + this.MaximumSize = new System.Drawing.Size(500, 200); + this.Height = newheight + pnlbottom.Height; + this.Load += (o, a) => + { + this.Left = (Screen.PrimaryScreen.Bounds.Width - this.Width) / 2; + this.Top = (Screen.PrimaryScreen.Bounds.Height - this.Height) / 2; + + }; + this.Text = title; + } + } +} diff --git a/source/ShiftUI/Internal/ApplicationHandler.cs b/source/ShiftUI/Internal/ApplicationHandler.cs new file mode 100644 index 0000000..df7d3d6 --- /dev/null +++ b/source/ShiftUI/Internal/ApplicationHandler.cs @@ -0,0 +1,78 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Geoff Norton +// +// + +using System; + +namespace ShiftUI.CarbonInternal { + internal class ApplicationHandler : EventHandlerBase, IEventHandler { + internal const uint kEventAppActivated = 1; + internal const uint kEventAppDeactivated = 2; + internal const uint kEventAppQuit = 3; + internal const uint kEventAppLaunchNotification = 4; + internal const uint kEventAppLaunched = 5; + internal const uint kEventAppTerminated = 6; + internal const uint kEventAppFrontSwitched = 7; + internal const uint kEventAppFocusMenuBar = 8; + internal const uint kEventAppFocusNextDocumentWindow = 9; + internal const uint kEventAppFocusNextFloatingWindow = 10; + internal const uint kEventAppFocusToolbar = 11; + internal const uint kEventAppFocusDrawer = 12; + internal const uint kEventAppGetDockTileMenu = 20; + internal const uint kEventAppIsEventInInstantMouser = 104; + internal const uint kEventAppHidden = 107; + internal const uint kEventAppShown = 108; + internal const uint kEventAppSystemUIModeChanged = 109; + internal const uint kEventAppAvailableWindowBoundsChanged = 110; + internal const uint kEventAppActiveWindowChanged = 111; + + internal ApplicationHandler (XplatUICarbon driver) : base (driver) {} + + public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) { + switch (kind) { + case kEventAppActivated: { + foreach (IntPtr utility_window in XplatUICarbon.UtilityWindows) + if (!XplatUICarbon.IsWindowVisible (utility_window)) + XplatUICarbon.ShowWindow (utility_window); + break; + } + case kEventAppDeactivated: { + if (XplatUICarbon.FocusWindow != IntPtr.Zero) { + Driver.SendMessage (XplatUICarbon.FocusWindow, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero); + } + if (XplatUICarbon.Grab.Hwnd != IntPtr.Zero) { + Driver.SendMessage (Hwnd.ObjectFromHandle (XplatUICarbon.Grab.Hwnd).Handle, Msg.WM_LBUTTONDOWN, (IntPtr)MsgButtons.MK_LBUTTON, (IntPtr) (Driver.MousePosition.X << 16 | Driver.MousePosition.Y)); + } + foreach (IntPtr utility_window in XplatUICarbon.UtilityWindows) + if (XplatUICarbon.IsWindowVisible (utility_window)) + XplatUICarbon.HideWindow (utility_window); + break; + } + } + + return true; + } + } +} diff --git a/source/ShiftUI/Internal/ArrangedElementCollection.cs b/source/ShiftUI/Internal/ArrangedElementCollection.cs new file mode 100644 index 0000000..61f5e52 --- /dev/null +++ b/source/ShiftUI/Internal/ArrangedElementCollection.cs @@ -0,0 +1,173 @@ +// +// ArrangedElementCollection.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Collections; +using System; + +namespace ShiftUI.Layout +{ + public class ArrangedElementCollection : IList, ICollection, IEnumerable + { + internal ArrayList list; + + internal ArrangedElementCollection () + { + this.list = new ArrayList (); + } + + #region Public Properties + public virtual int Count { get { return list.Count; } } + public virtual bool IsReadOnly { get { return list.IsReadOnly; } } + #endregion + + #region Public Methods + public void CopyTo (Array array, int index) + { + list.CopyTo (array, index); + } + + public override bool Equals (object obj) + { + if (obj is ArrangedElementCollection && this == obj) + return (true); + else + return (false); + } + + public virtual IEnumerator GetEnumerator () + { + return list.GetEnumerator (); + } + + public override int GetHashCode () + { + return base.GetHashCode (); + } + #endregion + + #region IList Members + int IList.Add (object value) + { + return Add (value); + } + + internal int Add (object value) + { + return list.Add (value); + } + + void IList.Clear () + { + Clear (); + } + + internal void Clear () + { + list.Clear (); + } + + bool IList.Contains (object value) + { + return Contains (value); + } + + internal bool Contains (object value) + { + return list.Contains (value); + } + + int IList.IndexOf (object value) + { + return IndexOf (value); + } + + internal int IndexOf (object value) + { + return list.IndexOf (value); + } + + void IList.Insert (int index, object value) + { + throw new NotSupportedException (); + } + + internal void Insert (int index, object value) + { + list.Insert (index, value); + } + + bool IList.IsFixedSize { + get { return this.IsFixedSize; } + } + + internal bool IsFixedSize { + get { return list.IsFixedSize; } + } + + void IList.Remove (object value) + { + Remove (value); + } + + internal void Remove (object value) + { + list.Remove (value); + } + + void IList.RemoveAt (int index) + { + list.RemoveAt (index); + } + + internal void InternalRemoveAt (int index) + { + list.RemoveAt (index); + } + + object IList.this[int index] { + get { return this[index]; } + set { this[index] = value; } + } + + internal object this[int index] { + get { return list[index]; } + set { list[index] = value; } + } + #endregion + + #region ICollection Members + bool ICollection.IsSynchronized { + get { return list.IsSynchronized; } + } + + object ICollection.SyncRoot { + get { return list.IsSynchronized; } + } + #endregion + } +} diff --git a/source/ShiftUI/Internal/AsyncMethodData.cs b/source/ShiftUI/Internal/AsyncMethodData.cs new file mode 100644 index 0000000..707ce62 --- /dev/null +++ b/source/ShiftUI/Internal/AsyncMethodData.cs @@ -0,0 +1,41 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +using System; +using System.Threading; + + +namespace ShiftUI { + + internal class AsyncMethodData { + public IntPtr Handle; + public Delegate Method; + public object [] Args; + public AsyncMethodResult Result; + public ExecutionContext Context; + public SynchronizationContext SyncContext; + } + +} diff --git a/source/ShiftUI/Internal/AsyncMethodResult.cs b/source/ShiftUI/Internal/AsyncMethodResult.cs new file mode 100644 index 0000000..48c480d --- /dev/null +++ b/source/ShiftUI/Internal/AsyncMethodResult.cs @@ -0,0 +1,108 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +using System; +using System.Threading; + +namespace ShiftUI { + + internal class AsyncMethodResult : IAsyncResult { + + private ManualResetEvent handle; + private object state; + private bool completed; + private object return_value; + private Exception exception; + + public AsyncMethodResult () + { + handle = new ManualResetEvent (false); + } + + public virtual WaitHandle AsyncWaitHandle { + get { + lock (this) { + return handle; + } + } + } + + public object AsyncState { + get { return state; } + set { state = value; } + } + + public bool CompletedSynchronously { + get { return false; } + } + + public bool IsCompleted { + get { + lock (this) { + return completed; + } + } + } + + public object EndInvoke () + { + lock (this) { + if (completed) { + if (exception == null) + return return_value; + else + throw exception; + } + } + handle.WaitOne (); + + if (exception != null) + throw exception; + + return return_value; + } + + public void Complete (object result) + { + lock (this) { + completed = true; + return_value = result; + handle.Set (); + } + } + + public void CompleteWithException (Exception ex) + { + lock (this) { + completed = true; + exception = ex; + handle.Set (); + } + } + } + +} + + diff --git a/source/ShiftUI/Internal/AutoCompleteSource.cs b/source/ShiftUI/Internal/AutoCompleteSource.cs new file mode 100644 index 0000000..ab2fc6a --- /dev/null +++ b/source/ShiftUI/Internal/AutoCompleteSource.cs @@ -0,0 +1,44 @@ +// +// AutoCompleteSource.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum AutoCompleteSource + { + FileSystem = 1, + HistoryList = 2, + RecentlyUsedList = 4, + AllUrl = 6, + AllSystemSources = 7, + FileSystemDirectories = 32, + CustomSource = 64, + None = 128, + ListItems = 256 + } +} diff --git a/source/ShiftUI/Internal/AutoCompleteStringCollection.cs b/source/ShiftUI/Internal/AutoCompleteStringCollection.cs new file mode 100644 index 0000000..2142d47 --- /dev/null +++ b/source/ShiftUI/Internal/AutoCompleteStringCollection.cs @@ -0,0 +1,203 @@ +// +// AutoCompleteStringCollection.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Daniel Nauck +// +// Author: +// Daniel Nauck (dna(at)mono-project(dot)de) + + +using System; +using System.Collections; +using System.ComponentModel; +using System.Reflection; + +namespace ShiftUI +{ + public class AutoCompleteStringCollection : IList, ICollection, IEnumerable + { + private ArrayList list = null; + + public AutoCompleteStringCollection () + { + list = new ArrayList (); + } + + public event CollectionChangeEventHandler CollectionChanged; + + protected void OnCollectionChanged (CollectionChangeEventArgs e) + { + if(CollectionChanged == null) + return; + + CollectionChanged (this, e); + } + + #region IEnumerable Members + + public IEnumerator GetEnumerator () + { + return list.GetEnumerator (); + } + + #endregion + + #region ICollection Members + + void ICollection.CopyTo (Array array, int index) + { + list.CopyTo (array, index); + } + + public void CopyTo (string[] array, int index) + { + list.CopyTo (array, index); + } + + public int Count + { + get { return list.Count; } + } + + public bool IsSynchronized + { + get { return false; } + } + + public object SyncRoot + { + get { return this; } + } + + #endregion + + #region IList Members + + int IList.Add (object value) + { + return Add ((string)value); + } + + public int Add (string value) + { + int index = list.Add (value); + OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, value)); + return index; + } + + public void AddRange (string[] value) + { + if (value == null) + throw new ArgumentNullException ("value", "Argument cannot be null!"); + + list.AddRange (value); + OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null)); + } + + public void Clear () + { + list.Clear (); + OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null)); + } + + bool IList.Contains (object value) + { + return Contains ((string)value); + } + + public bool Contains (string value) + { + return list.Contains (value); + } + + int IList.IndexOf (object value) + { + return IndexOf ((string)value); + } + + public int IndexOf (string value) + { + return list.IndexOf (value); + } + + void IList.Insert (int index, object value) + { + Insert (index, (string)value); + } + + public void Insert (int index, string value) + { + list.Insert (index, value); + OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, value)); + } + + bool IList.IsFixedSize + { + get { return false; } + } + + bool IList.IsReadOnly + { + get { return false; } + } + + public bool IsReadOnly + { + get { return false; } + } + + void IList.Remove (object value) + { + Remove((string)value); + } + + public void Remove (string value) + { + list.Remove (value); + OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, value)); + } + + public void RemoveAt (int index) + { + string value = this[index]; + list.RemoveAt (index); + OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, value)); + } + + object IList.this[int index] + { + get { return this[index]; } + set { this[index] = (string)value; } + } + + public string this[int index] + { + get { return (string)list[index]; } + set { + OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, list[index])); + list[index] = value; + OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, value)); + } + } + #endregion + } +} diff --git a/source/ShiftUI/Internal/BaseCollection.cs b/source/ShiftUI/Internal/BaseCollection.cs new file mode 100644 index 0000000..91b3661 --- /dev/null +++ b/source/ShiftUI/Internal/BaseCollection.cs @@ -0,0 +1,99 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +using System; +using System.Collections; +using System.ComponentModel; + +namespace ShiftUI { + public class BaseCollection : MarshalByRefObject, ICollection, IEnumerable { + internal ArrayList list; + + #region Public Constructors + public BaseCollection () + { + } + #endregion // Public Constructors + + #region Public Instance Properties + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public virtual int Count { + get { + return List.Count; + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public bool IsReadOnly { + get { + return false; + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public bool IsSynchronized { + get { + return false; + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public object SyncRoot { + get { + return this; + } + } + #endregion // Public Instance Properties + + #region Protected Instance Properties + protected virtual ArrayList List { + get { + if (list == null) + list = new ArrayList (); + return list; + } + } + #endregion // Protected Instance Properties + + #region Public Instance Methods + public void CopyTo (Array ar, int index) + { + List.CopyTo (ar, index); + } + + public IEnumerator GetEnumerator () + { + return List.GetEnumerator (); + } + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Internal/Binding.cs b/source/ShiftUI/Internal/Binding.cs new file mode 100644 index 0000000..7b6ccc7 --- /dev/null +++ b/source/ShiftUI/Internal/Binding.cs @@ -0,0 +1,578 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// Jackson Harper jackson@ximian.com +// + + +using System.ComponentModel; +using System; + +namespace ShiftUI { + + [TypeConverter (typeof (ListBindingConverter))] + public class Binding { + + private string property_name; + private object data_source; + private string data_member; + + private bool is_binding; + private bool checked_isnull; + + private BindingMemberInfo binding_member_info; + private IBindableComponent control; + + private BindingManagerBase manager; + private PropertyDescriptor control_property; + private PropertyDescriptor is_null_desc; + + private object data; + private Type data_type; + + private DataSourceUpdateMode datasource_update_mode; + private ControlUpdateMode control_update_mode; + private object datasource_null_value = Convert.DBNull; + private object null_value; + private IFormatProvider format_info; + private string format_string; + private bool formatting_enabled; + #region Public Constructors + public Binding (string propertyName, object dataSource, string dataMember) + : this (propertyName, dataSource, dataMember, false, DataSourceUpdateMode.OnValidation, null, string.Empty, null) + { + } + + public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled) + : this (propertyName, dataSource, dataMember, formattingEnabled, DataSourceUpdateMode.OnValidation, null, string.Empty, null) + { + } + + public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode) + : this (propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, null, string.Empty, null) + { + } + + public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue) + : this (propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, nullValue, string.Empty, null) + { + } + + public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue, string formatString) + : this (propertyName, dataSource, dataMember, formattingEnabled, dataSourceUpdateMode, nullValue, formatString, null) + { + } + + public Binding (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue, string formatString, IFormatProvider formatInfo) + { + property_name = propertyName; + data_source = dataSource; + data_member = dataMember; + binding_member_info = new BindingMemberInfo (dataMember); + datasource_update_mode = dataSourceUpdateMode; + null_value = nullValue; + format_string = formatString; + format_info = formatInfo; + } + #endregion // Public Constructors + + #region Public Instance Properties + [DefaultValue (null)] + public IBindableComponent BindableComponent { + get { + return control; + } + } + + public BindingManagerBase BindingManagerBase { + get { + return manager; + } + } + + public BindingMemberInfo BindingMemberInfo { + get { + return binding_member_info; + } + } + + [DefaultValue (null)] + public Widget Widget { + get { + return control as Widget; + } + } + + [DefaultValue (ControlUpdateMode.OnPropertyChanged)] + public ControlUpdateMode ControlUpdateMode { + get { + return control_update_mode; + } + set { + control_update_mode = value; + } + } + + public object DataSource { + get { + return data_source; + } + } + + [DefaultValue (DataSourceUpdateMode.OnValidation)] + public DataSourceUpdateMode DataSourceUpdateMode { + get { + return datasource_update_mode; + } + set { + datasource_update_mode = value; + } + } + + public object DataSourceNullValue { + get { + return datasource_null_value; + } + set { + datasource_null_value = value; + } + } + + [DefaultValue (false)] + public bool FormattingEnabled { + get { + return formatting_enabled; + } + set { + if (formatting_enabled == value) + return; + + formatting_enabled = value; + PushData (); + } + } + + [DefaultValue (null)] + public IFormatProvider FormatInfo { + get { + return format_info; + } + set { + if (value == format_info) + return; + + format_info = value; + if (formatting_enabled) + PushData (); + } + } + + public string FormatString { + get { + return format_string; + } + set { + if (value == null) + value = String.Empty; + if (value == format_string) + return; + + format_string = value; + if (formatting_enabled) + PushData (); + } + } + + public bool IsBinding { + get { + if (manager == null || manager.IsSuspended) + return false; + + return is_binding; + } + } + + public object NullValue { + get { + return null_value; + } + set { + if (value == null_value) + return; + + null_value = value; + if (formatting_enabled) + PushData (); + } + } + + [DefaultValue ("")] + public string PropertyName { + get { + return property_name; + } + } + #endregion // Public Instance Properties + + public void ReadValue () + { + PushData (true); + } + + public void WriteValue () + { + PullData (true); + } + + #region Protected Instance Methods + protected virtual void OnBindingComplete (BindingCompleteEventArgs e) + { + if (BindingComplete != null) + BindingComplete (this, e); + } + + protected virtual void OnFormat (ConvertEventArgs cevent) + { + if (Format!=null) + Format (this, cevent); + } + + protected virtual void OnParse (ConvertEventArgs cevent) + { + if (Parse!=null) + Parse (this, cevent); + } + #endregion // Protected Instance Methods + + internal string DataMember { + get { return data_member; } + } + + internal void SetWidget (IBindableComponent control) + { + if (control == this.control) + return; + + control_property = TypeDescriptor.GetProperties (control).Find (property_name, true); + + if (control_property == null) + throw new ArgumentException (String.Concat ("Cannot bind to property '", property_name, "' on target control.")); + if (control_property.IsReadOnly) + throw new ArgumentException (String.Concat ("Cannot bind to property '", property_name, "' because it is read only.")); + + data_type = control_property.PropertyType; // Getting the PropertyType is kinda slow and it should never change, so it is cached + + Widget ctrl = control as Widget; + if (ctrl != null) { + ctrl.Validating += new CancelEventHandler (ControlValidatingHandler); + if (!ctrl.IsHandleCreated) + ctrl.HandleCreated += new EventHandler (ControlCreatedHandler); + } + + EventDescriptor prop_changed_event = GetPropertyChangedEvent (control, property_name); + if (prop_changed_event != null) + prop_changed_event.AddEventHandler (control, new EventHandler (ControlPropertyChangedHandler)); + this.control = control; + UpdateIsBinding (); + } + + internal void Check () + { + if (control == null || control.BindingContext == null) + return; + + if (manager == null) { + manager = control.BindingContext [data_source, binding_member_info.BindingPath]; + + if (manager.Position > -1 && binding_member_info.BindingField != String.Empty && + TypeDescriptor.GetProperties (manager.Current).Find (binding_member_info.BindingField, true) == null) + throw new ArgumentException ("Cannot bind to property '" + binding_member_info.BindingField + "' on DataSource.", + "dataMember"); + + manager.AddBinding (this); + manager.PositionChanged += new EventHandler (PositionChangedHandler); + + if (manager is PropertyManager) { // Match .net, which only watchs simple objects + EventDescriptor prop_changed_event = GetPropertyChangedEvent (manager.Current, binding_member_info.BindingField); + if (prop_changed_event != null) + prop_changed_event.AddEventHandler (manager.Current, new EventHandler (SourcePropertyChangedHandler)); + } + } + + if (manager.Position == -1) + return; + + if (!checked_isnull) { + is_null_desc = TypeDescriptor.GetProperties (manager.Current).Find (property_name + "IsNull", false); + checked_isnull = true; + } + + PushData (); + } + + internal bool PullData () + { + return PullData (false); + } + + // Return false ONLY in case of error - and return true even in cases + // where no update was possible + bool PullData (bool force) + { + if (IsBinding == false || manager.Current == null) + return true; + if (!force && datasource_update_mode == DataSourceUpdateMode.Never) + return true; + + data = control_property.GetValue (control); + if (data == null) + data = datasource_null_value; + + try { + SetPropertyValue (data); + } catch (Exception e) { + if (formatting_enabled) { + FireBindingComplete (BindingCompleteContext.DataSourceUpdate, e, e.Message); + return false; + } + throw e; + } + + if (formatting_enabled) + FireBindingComplete (BindingCompleteContext.DataSourceUpdate, null, null); + return true; + } + + internal void PushData () + { + PushData (false); + } + + void PushData (bool force) + { + if (manager == null || manager.IsSuspended || manager.Count == 0 || manager.Position == -1) + return; + if (!force && control_update_mode == ControlUpdateMode.Never) + return; + + if (is_null_desc != null) { + bool is_null = (bool) is_null_desc.GetValue (manager.Current); + if (is_null) { + data = Convert.DBNull; + return; + } + } + + PropertyDescriptor pd = TypeDescriptor.GetProperties (manager.Current).Find (binding_member_info.BindingField, true); + if (pd == null) { + data = manager.Current; + } else { + data = pd.GetValue (manager.Current); + } + + if ((data == null || data == DBNull.Value) && null_value != null) + data = null_value; + + try { + data = FormatData (data); + SetControlValue (data); + } catch (Exception e) { + if (formatting_enabled) { + FireBindingComplete (BindingCompleteContext.ControlUpdate, e, e.Message); + return; + } + throw e; + } + + if (formatting_enabled) + FireBindingComplete (BindingCompleteContext.ControlUpdate, null, null); + } + + internal void UpdateIsBinding () + { + is_binding = false; + if (control == null || (control is Widget && !((Widget)control).IsHandleCreated)) + return; + + is_binding = true; + PushData (); + } + + private void SetControlValue (object data) + { + control_property.SetValue (control, data); + } + + private void SetPropertyValue (object data) + { + PropertyDescriptor pd = TypeDescriptor.GetProperties (manager.Current).Find (binding_member_info.BindingField, true); + if (pd.IsReadOnly) + return; + data = ParseData (data, pd.PropertyType); + pd.SetValue (manager.Current, data); + } + + private void ControlValidatingHandler (object sender, CancelEventArgs e) + { + if (datasource_update_mode != DataSourceUpdateMode.OnValidation) + return; + + bool ok = true; + // If the data doesn't seem to be valid (it can't be converted, + // is the wrong type, etc, we reset to the old data value. + // If Formatting is enabled, no exception is fired, but we get a false value + try { + ok = PullData (); + } catch { + ok = false; + } + + e.Cancel = !ok; + } + + private void ControlCreatedHandler (object o, EventArgs args) + { + UpdateIsBinding (); + } + + private void PositionChangedHandler (object sender, EventArgs e) + { + Check (); + PushData (); + } + + EventDescriptor GetPropertyChangedEvent (object o, string property_name) + { + if (o == null || property_name == null || property_name.Length == 0) + return null; + + string event_name = property_name + "Changed"; + Type event_handler_type = typeof (EventHandler); + + EventDescriptor prop_changed_event = null; + foreach (EventDescriptor event_desc in TypeDescriptor.GetEvents (o)) { + if (event_desc.Name == event_name && event_desc.EventType == event_handler_type) { + prop_changed_event = event_desc; + break; + } + } + + return prop_changed_event; + } + + void SourcePropertyChangedHandler (object o, EventArgs args) + { + PushData (); + } + + void ControlPropertyChangedHandler (object o, EventArgs args) + { + if (datasource_update_mode != DataSourceUpdateMode.OnPropertyChanged) + return; + + PullData (); + } + + private object ParseData (object data, Type data_type) + { + ConvertEventArgs e = new ConvertEventArgs (data, data_type); + + OnParse (e); + if (data_type.IsInstanceOfType (e.Value)) + return e.Value; + if (e.Value == Convert.DBNull) + return e.Value; + if (e.Value == null) { + bool nullable = data_type.IsGenericType && !data_type.ContainsGenericParameters && + data_type.GetGenericTypeDefinition () == typeof (Nullable<>); + return data_type.IsValueType && !nullable ? Convert.DBNull : null; + } + + return ConvertData (e.Value, data_type); + } + + private object FormatData (object data) + { + ConvertEventArgs e = new ConvertEventArgs (data, data_type); + + OnFormat (e); + if (data_type.IsInstanceOfType (e.Value)) + return e.Value; + + if (formatting_enabled) { + if ((e.Value == null || e.Value == Convert.DBNull) && null_value != null) + return null_value; + + if (e.Value is IFormattable && data_type == typeof (string)) { + IFormattable formattable = (IFormattable) e.Value; + return formattable.ToString (format_string, format_info); + } + } + + if (e.Value == null && data_type == typeof (object)) + return Convert.DBNull; + + return ConvertData (data, data_type); + } + + private object ConvertData (object data, Type data_type) + { + if (data == null) + return null; + + TypeConverter converter = TypeDescriptor.GetConverter (data.GetType ()); + if (converter != null && converter.CanConvertTo (data_type)) + return converter.ConvertTo (data, data_type); + + converter = TypeDescriptor.GetConverter (data_type); + if (converter != null && converter.CanConvertFrom (data.GetType())) + return converter.ConvertFrom (data); + + if (data is IConvertible) { + object res = Convert.ChangeType (data, data_type); + if (data_type.IsInstanceOfType (res)) + return res; + } + + return null; + } + void FireBindingComplete (BindingCompleteContext context, Exception exc, string error_message) + { + BindingCompleteEventArgs args = new BindingCompleteEventArgs (this, + exc == null ? BindingCompleteState.Success : BindingCompleteState.Exception, + context); + if (exc != null) { + args.SetException (exc); + args.SetErrorText (error_message); + } + + OnBindingComplete (args); + } + + #region Events + public event ConvertEventHandler Format; + public event ConvertEventHandler Parse; + public event BindingCompleteEventHandler BindingComplete; + #endregion // Events + } +} diff --git a/source/ShiftUI/Internal/BindingCompleteContext.cs b/source/ShiftUI/Internal/BindingCompleteContext.cs new file mode 100644 index 0000000..44d7347 --- /dev/null +++ b/source/ShiftUI/Internal/BindingCompleteContext.cs @@ -0,0 +1,37 @@ +// +// BindingCompleteContext.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum BindingCompleteContext + { + ControlUpdate = 0, + DataSourceUpdate = 1 + } +} diff --git a/source/ShiftUI/Internal/BindingContext.cs b/source/ShiftUI/Internal/BindingContext.cs new file mode 100644 index 0000000..fbf461a --- /dev/null +++ b/source/ShiftUI/Internal/BindingContext.cs @@ -0,0 +1,257 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// Jackson Harper jackson@ximian.com + + +using System.Data; +using System.Collections; +using System.Globalization; +using System.ComponentModel; +using System; + +namespace ShiftUI { + + [DefaultEvent("CollectionChanged")] + public class BindingContext : ICollection, IEnumerable { + + private Hashtable managers; + private EventHandler onCollectionChangedHandler; + + private class HashKey { + public object source; + public string member; + + public HashKey (object source, string member) + { + this.source = source; + this.member = member; + } + + public override int GetHashCode () + { + return source.GetHashCode() ^ member.GetHashCode (); + } + + public override bool Equals (object o) + { + HashKey hk = o as HashKey; + if (hk == null) + return false; + return hk.source == source && hk.member == member; + } + } + + public BindingContext () + { + managers = new Hashtable (); + onCollectionChangedHandler = null; + } + + public bool IsReadOnly { + get { return false; } + } + + public BindingManagerBase this [object dataSource] { + get { return this [dataSource, String.Empty]; } + } + + public BindingManagerBase this [object dataSource, string dataMember] { + get { + if (dataSource == null) + throw new ArgumentNullException ("dataSource"); + if (dataMember == null) + dataMember = String.Empty; + + ICurrencyManagerProvider cm_provider = dataSource as ICurrencyManagerProvider; + if (cm_provider != null) { + if (dataMember.Length == 0) + return cm_provider.CurrencyManager; + + return cm_provider.GetRelatedCurrencyManager (dataMember); + } + + HashKey key = new HashKey (dataSource, dataMember); + BindingManagerBase res = managers [key] as BindingManagerBase; + + if (res != null) + return res; + + res = CreateBindingManager (dataSource, dataMember); + if (res == null) + return null; + managers [key] = res; + return res; + } + } + + private BindingManagerBase CreateBindingManager (object data_source, string data_member) + { + if (data_member == "") { + if (IsListType (data_source.GetType ())) + return new CurrencyManager (data_source); + else + return new PropertyManager (data_source); + } + else { + BindingMemberInfo info = new BindingMemberInfo (data_member); + + BindingManagerBase parent_manager = this[data_source, info.BindingPath]; + + PropertyDescriptor pd = parent_manager == null ? null : parent_manager.GetItemProperties ().Find (info.BindingField, true); + + if (pd == null) + throw new ArgumentException (String.Format ("Cannot create a child list for field {0}.", info.BindingField)); + + if (IsListType (pd.PropertyType)) + return new RelatedCurrencyManager (parent_manager, pd); + else + return new RelatedPropertyManager (parent_manager, info.BindingField); + } + } + + bool IsListType (Type t) + { + return (typeof (IList).IsAssignableFrom (t) + || typeof (IListSource).IsAssignableFrom (t)); + } + + #region Public Instance Methods + public bool Contains(object dataSource) + { + return Contains (dataSource, String.Empty); + } + + public bool Contains (object dataSource, string dataMember) + { + if (dataSource == null) + throw new ArgumentNullException ("dataSource"); + if (dataMember == null) + dataMember = String.Empty; + + HashKey key = new HashKey (dataSource, dataMember); + return managers [key] != null; + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + + protected internal void Add (object dataSource, BindingManagerBase listManager) + { + AddCore (dataSource, listManager); + OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, dataSource)); + } + + protected virtual void AddCore (object dataSource, BindingManagerBase listManager) + { + if (dataSource == null) + throw new ArgumentNullException ("dataSource"); + if (listManager == null) + throw new ArgumentNullException ("listManager"); + + HashKey key = new HashKey (dataSource, String.Empty); + managers [key] = listManager; + } + + protected internal void Clear () + { + ClearCore(); + OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null)); + } + + protected virtual void ClearCore () + { + managers.Clear (); + } + + protected virtual void OnCollectionChanged (CollectionChangeEventArgs ccevent) + { + if (onCollectionChangedHandler != null) { + onCollectionChangedHandler (this, ccevent); + } + } + + protected internal void Remove (object dataSource) + { + if (dataSource == null) + throw new ArgumentNullException ("dataSource"); + + RemoveCore (dataSource); + OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, dataSource)); + } + + protected virtual void RemoveCore (object dataSource) + { + HashKey[] keys = new HashKey [managers.Keys.Count]; + managers.Keys.CopyTo (keys, 0); + + for (int i = 0; i < keys.Length; i ++) { + if (keys[i].source == dataSource) + managers.Remove (keys[i]); + } + } + + [MonoTODO ("Stub, does nothing")] + public static void UpdateBinding (BindingContext newBindingContext, Binding binding) + { + } + + #endregion // Protected Instance Methods + + #region Events + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public event CollectionChangeEventHandler CollectionChanged { + add { throw new NotImplementedException (); } + remove { /* nothing to do here.. */ } + } + #endregion // Events + + #region ICollection Interfaces + void ICollection.CopyTo (Array ar, int index) + { + managers.CopyTo (ar, index); + } + + int ICollection.Count { + get { return managers.Count; } + } + + bool ICollection.IsSynchronized { + get { return false; } + } + + object ICollection.SyncRoot { + get { return null; } + } + + #endregion // ICollection Interfaces + + #region IEnumerable Interfaces + [MonoInternalNote ("our enumerator is slightly different. in MS's implementation the Values are WeakReferences to the managers.")] + IEnumerator IEnumerable.GetEnumerator() { + return managers.GetEnumerator (); + } + #endregion // IEnumerable Interfaces + } +} diff --git a/source/ShiftUI/Internal/BindingManagerBase.cs b/source/ShiftUI/Internal/BindingManagerBase.cs new file mode 100644 index 0000000..c2b0392 --- /dev/null +++ b/source/ShiftUI/Internal/BindingManagerBase.cs @@ -0,0 +1,204 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// Jackson Harper jackson@ximian.com +// + + +// NOT COMPLETE + +using System.ComponentModel; +using System.Collections; +using System; + +namespace ShiftUI +{ + public abstract class BindingManagerBase + { + private BindingsCollection bindings; + internal bool transfering_data; /* true if we're pushing or pulling data */ + + #region Public Constructors + public BindingManagerBase() + { + } + #endregion // Public Constructors + + #region Protected Instance Fields + protected EventHandler onCurrentChangedHandler; + protected EventHandler onPositionChangedHandler; + internal EventHandler onCurrentItemChangedHandler; + #endregion // Protected Instance Fields + + #region Public Instance Properties + public BindingsCollection Bindings { + get { + if (bindings == null) { + bindings = new BindingsCollection (); + } + return bindings; + } + } + + public abstract int Count { + get; + } + + public abstract object Current { + get; + } + + public bool IsBindingSuspended { + get { + return IsSuspended; + } + } + + public abstract int Position { + get; set; + } + #endregion // Public Instance Properties + + #region Public Instance Methods + public abstract void AddNew(); + + public abstract void CancelCurrentEdit(); + + public abstract void EndCurrentEdit(); + + public virtual PropertyDescriptorCollection GetItemProperties() + { + return GetItemPropertiesInternal (); + } + + internal virtual PropertyDescriptorCollection GetItemPropertiesInternal () + { + throw new NotImplementedException (); + } + + public abstract void RemoveAt(int index); + + public abstract void ResumeBinding(); + + public abstract void SuspendBinding(); + #endregion // Public Instance Methods + + internal virtual bool IsSuspended { + get { + return false; + } + } + + #region Protected Instance Methods + [MonoTODO ("Not implemented, will throw NotImplementedException")] + protected internal virtual PropertyDescriptorCollection GetItemProperties (ArrayList dataSources, ArrayList listAccessors) + { + throw new NotImplementedException(); + } + + [MonoTODO ("Not implemented, will throw NotImplementedException")] + protected virtual PropertyDescriptorCollection GetItemProperties (Type listType, int offset, ArrayList dataSources, ArrayList listAccessors) + { + throw new NotImplementedException(); + } + + protected internal abstract string GetListName (ArrayList listAccessors); + + protected internal abstract void OnCurrentChanged (EventArgs e); + + protected void PullData() + { + try { + if (!transfering_data) { + transfering_data = true; + UpdateIsBinding (); + } + foreach (Binding binding in Bindings) { + binding.PullData (); + } + } finally { + transfering_data = false; + } + } + + protected void PushData() + { + try { + if (!transfering_data) { + transfering_data = true; + UpdateIsBinding (); + } + foreach (Binding binding in Bindings) { + binding.PushData (); + } + } finally { + transfering_data = false; + } + } + + + protected void OnBindingComplete (BindingCompleteEventArgs args) + { + if (BindingComplete != null) + BindingComplete (this, args); + } + + protected abstract void OnCurrentItemChanged (EventArgs e); + + protected void OnDataError (Exception e) + { + if (DataError != null) + DataError (this, new BindingManagerDataErrorEventArgs (e)); + } + + protected abstract void UpdateIsBinding(); + #endregion // Protected Instance Methods + + internal void AddBinding (Binding binding) + { + if (Bindings.Contains (binding)) + return; + Bindings.Add (binding); + } + + #region Events + public event EventHandler CurrentChanged { + add { onCurrentChangedHandler += value; } + remove { onCurrentChangedHandler -= value; } + } + + public event EventHandler PositionChanged { + add { onPositionChangedHandler += value; } + remove { onPositionChangedHandler -= value; } + } + + public event EventHandler CurrentItemChanged { + add { onCurrentItemChangedHandler += value; } + remove { onCurrentItemChangedHandler -= value; } + } + + public event BindingCompleteEventHandler BindingComplete; + public event BindingManagerDataErrorEventHandler DataError; + #endregion // Events + } +} diff --git a/source/ShiftUI/Internal/BindingMemberInfo.cs b/source/ShiftUI/Internal/BindingMemberInfo.cs new file mode 100644 index 0000000..3f7ae11 --- /dev/null +++ b/source/ShiftUI/Internal/BindingMemberInfo.cs @@ -0,0 +1,107 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE +using System; + +namespace ShiftUI { + public struct BindingMemberInfo { + private string data_member; + private string data_field; + private string data_path; + + #region Public Constructors + public BindingMemberInfo(string dataMember) { + int i; + + if (dataMember!=null) { + this.data_member=dataMember; + } else { + this.data_member=String.Empty; + } + + // Break out our components + i=data_member.LastIndexOf('.'); + if (i!=-1) { + data_field=data_member.Substring(i+1); + data_path=data_member.Substring(0, i); + } else { + data_field=data_member; + data_path=String.Empty; + } + } + #endregion // Public Constructors + + #region Public Instance Properties + public string BindingField { + get { + return this.data_field; + } + } + + public string BindingMember { + get { + return this.data_member; + } + } + + public string BindingPath { + get { + return this.data_path; + } + } + #endregion // Public Instance Properties + + #region Public Instance Methods + public override bool Equals(object otherObject) { + if (otherObject is BindingMemberInfo) { + return ((this.data_field == ((BindingMemberInfo)otherObject).data_field) && + (this.data_path == ((BindingMemberInfo)otherObject).data_path) && + (this.data_member == ((BindingMemberInfo)otherObject).data_member)); + } else { + return false; + } + } + + public override int GetHashCode() { + return this.data_member.GetHashCode(); + } + #endregion // Public Instance Methods + + #region Public Static Methods + public static bool operator == (BindingMemberInfo a, BindingMemberInfo b) + { + return (a.Equals (b)); + } + + public static bool operator != (BindingMemberInfo a, BindingMemberInfo b) + { + return !(a.Equals (b)); + } + #endregion // Public Static Methods + + } +} diff --git a/source/ShiftUI/Internal/BindingsCollection.cs b/source/ShiftUI/Internal/BindingsCollection.cs new file mode 100644 index 0000000..11f4fe9 --- /dev/null +++ b/source/ShiftUI/Internal/BindingsCollection.cs @@ -0,0 +1,136 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// Jackson Harper jackson@ximian.com +// + + +// COMPLETE + +using System.Collections; +using System.ComponentModel; + +namespace ShiftUI { + [DefaultEvent("CollectionChanged")] + public class BindingsCollection : BaseCollection { + +#region Public Constructors + internal BindingsCollection () + { + } + #endregion // Public Constructors + + #region Public Instance Properties + public override int Count { + get { + return base.Count; + } + } + + public Binding this[int index] { + get { + return (Binding)(base.List[index]); + } + } + #endregion // Public Instance Properties + + #region Protected Instance Properties + protected override ArrayList List { + get { + return base.List; + } + } + #endregion // Protected Instance Properties + + #region Protected Instance Methods + protected internal void Add(Binding binding) { + AddCore(binding); + } + + protected virtual void AddCore (Binding dataBinding) + { + CollectionChangeEventArgs args = new CollectionChangeEventArgs (CollectionChangeAction.Add, dataBinding); + OnCollectionChanging (args); + base.List.Add(dataBinding); + OnCollectionChanged (args); + } + + protected internal void Clear() { + ClearCore(); + } + + protected virtual void ClearCore() + { + CollectionChangeEventArgs args = new CollectionChangeEventArgs(CollectionChangeAction.Refresh, null); + OnCollectionChanging (args); + base.List.Clear(); + OnCollectionChanged (args); + } + + protected virtual void OnCollectionChanged(System.ComponentModel.CollectionChangeEventArgs ccevent) { + if (CollectionChanged!=null) CollectionChanged(this, ccevent); + } + + protected virtual void OnCollectionChanging (CollectionChangeEventArgs e) + { + if (CollectionChanging != null) + CollectionChanging (this, e); + } + + protected internal void Remove(Binding binding) { + RemoveCore(binding); + } + + protected internal void RemoveAt(int index) { + base.List.RemoveAt(index); + OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Remove, base.List)); + } + + protected virtual void RemoveCore(Binding dataBinding) + { + CollectionChangeEventArgs args = new CollectionChangeEventArgs(CollectionChangeAction.Remove, dataBinding); + OnCollectionChanging (args); + base.List.Remove(dataBinding); + OnCollectionChanged (args); + } + + protected internal bool ShouldSerializeMyAll() { + if (this.Count>0) { + return(true); + } else { + return(false); + } + } + #endregion // Public Instance Methods + + internal bool Contains (Binding binding) + { + return List.Contains (binding); + } + + #region Events + public event CollectionChangeEventHandler CollectionChanged; + public event CollectionChangeEventHandler CollectionChanging; + #endregion // Events + } +} diff --git a/source/ShiftUI/Internal/BootMode.cs b/source/ShiftUI/Internal/BootMode.cs new file mode 100644 index 0000000..495d678 --- /dev/null +++ b/source/ShiftUI/Internal/BootMode.cs @@ -0,0 +1,39 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// + +//COMPLETE + + +namespace ShiftUI +{ + + public enum BootMode + { + Normal = 0, + FailSafe = 1, + FailSafeWithNetwork = 2 + } +} + diff --git a/source/ShiftUI/Internal/BoundsSpecified.cs b/source/ShiftUI/Internal/BoundsSpecified.cs new file mode 100644 index 0000000..7acc040 --- /dev/null +++ b/source/ShiftUI/Internal/BoundsSpecified.cs @@ -0,0 +1,43 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + +// COMPLETE +using System; + +namespace ShiftUI +{ + [Flags] + public enum BoundsSpecified + { + None = 0x00000000, + X = 0x00000001, + Y = 0x00000002, + Location = 0x00000003, + Width = 0x00000004, + Height = 0x00000008, + Size = 0x0000000c, + All = 0x0000000f + } +} diff --git a/source/ShiftUI/Internal/ButtonBase.cs b/source/ShiftUI/Internal/ButtonBase.cs new file mode 100644 index 0000000..7f8c894 --- /dev/null +++ b/source/ShiftUI/Internal/ButtonBase.cs @@ -0,0 +1,747 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Drawing.Text; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + //[Designer ("ShiftUI.Design.ButtonBaseDesigner, " + Consts.AssemblySystem_Design, + //"System.ComponentModel.Design.IDesigner")] + public abstract class ButtonBase : Widget + { + #region Local Variables + private FlatStyle flat_style; + private int image_index; + internal Image image; + internal ImageList image_list; + private ContentAlignment image_alignment; + internal ContentAlignment text_alignment; + private bool is_default; + internal bool is_pressed; +// private bool enter_state; + internal StringFormat text_format; + internal bool paint_as_acceptbutton; + + // Properties are 2.0, but variables used in 1.1 for common drawing code + private bool auto_ellipsis; + private FlatButtonAppearance flat_button_appearance; + private string image_key; + private TextImageRelation text_image_relation; + private TextFormatFlags text_format_flags; + private bool use_mnemonic; + private bool use_visual_style_back_color; + #endregion // Local Variables + + #region Public Constructors + protected ButtonBase() : base() + { + flat_style = FlatStyle.Standard; + flat_button_appearance = new FlatButtonAppearance (this); + this.image_key = string.Empty; + this.text_image_relation = TextImageRelation.Overlay; + this.use_mnemonic = true; + use_visual_style_back_color = true; + image_index = -1; + image = null; + image_list = null; + image_alignment = ContentAlignment.MiddleCenter; + ImeMode = ImeMode.Disable; + text_alignment = ContentAlignment.MiddleCenter; + is_default = false; + is_pressed = false; + text_format = new StringFormat(); + text_format.Alignment = StringAlignment.Center; + text_format.LineAlignment = StringAlignment.Center; + text_format.HotkeyPrefix = HotkeyPrefix.Show; + text_format.FormatFlags |= StringFormatFlags.LineLimit; + + text_format_flags = TextFormatFlags.HorizontalCenter; + text_format_flags |= TextFormatFlags.VerticalCenter; + text_format_flags |= TextFormatFlags.TextBoxControl; + + SetStyle (Widgetstyles.ResizeRedraw | + Widgetstyles.Opaque | + Widgetstyles.UserMouse | + Widgetstyles.SupportsTransparentBackColor | + Widgetstyles.CacheText | + Widgetstyles.OptimizedDoubleBuffer, true); + SetStyle (Widgetstyles.StandardClick, false); + } + #endregion // Public Constructors + + #region Public Properties + [Browsable (true)] + [DefaultValue (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + [MWFCategory("Behavior")] + public bool AutoEllipsis { + get { return this.auto_ellipsis; } + set + { + if (this.auto_ellipsis != value) { + this.auto_ellipsis = value; + + if (this.auto_ellipsis) { + text_format_flags |= TextFormatFlags.EndEllipsis; + text_format_flags &= ~TextFormatFlags.WordBreak; + } else { + text_format_flags &= ~TextFormatFlags.EndEllipsis; + text_format_flags |= TextFormatFlags.WordBreak; + } + + if (Parent != null) + Parent.PerformLayout (this, "AutoEllipsis"); + this.Invalidate (); + } + } + } + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)] + [MWFCategory("Layout")] + public override bool AutoSize { + get { return base.AutoSize; } + set { base.AutoSize = value; } + } + + public override Color BackColor { + get { return base.BackColor; } + set { base.BackColor = value; } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + [Browsable (true)] + [MWFCategory("Appearance")] + public FlatButtonAppearance FlatAppearance { + get { return flat_button_appearance; } + } + + [Localizable(true)] + [DefaultValue(FlatStyle.Standard)] + [MWFDescription("Determines look of button"), MWFCategory("Appearance")] + public FlatStyle FlatStyle { + get { return flat_style; } + set { + if (flat_style != value) { + flat_style = value; + + if (Parent != null) + Parent.PerformLayout (this, "FlatStyle"); + Invalidate(); + } + } + } + + [Localizable(true)] + [MWFDescription("Sets image to be displayed on button face"), MWFCategory("Appearance")] + public Image Image { + get { + if (this.image != null) + return this.image; + + if (this.image_index >= 0) + if (this.image_list != null) + return this.image_list.Images[this.image_index]; + + if (!string.IsNullOrEmpty (this.image_key)) + if (this.image_list != null) + return this.image_list.Images[this.image_key]; + return null; + } + set { + if (this.image != value) { + this.image = value; + this.image_index = -1; + this.image_key = string.Empty; + this.image_list = null; + + if (this.AutoSize && this.Parent != null) + this.Parent.PerformLayout (this, "Image"); + + Invalidate (); + } + } + } + + internal bool ShouldSerializeImage () + { + return this.Image != null; + } + + [Localizable(true)] + [DefaultValue(ContentAlignment.MiddleCenter)] + [MWFDescription("Sets the alignment of the image to be displayed on button face"), MWFCategory("Appearance")] + public ContentAlignment ImageAlign { + get { return image_alignment; } + set { + if (image_alignment != value) { + image_alignment = value; + Invalidate (); + } + } + } + + [Localizable(true)] + [DefaultValue(-1)] + //[Editor("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))] + [TypeConverter(typeof(ImageIndexConverter))] + [MWFDescription("Index of image to display, if ImageList is used for button face images"), MWFCategory("Appearance")] + [RefreshProperties (RefreshProperties.Repaint)] + public int ImageIndex { + get { + if (image_list == null) + return -1; + + return image_index; + } + set { + if (this.image_index != value) { + this.image_index = value; + this.image = null; + this.image_key = string.Empty; + Invalidate (); + } + } + } + + [Localizable (true)] + [DefaultValue ("")] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + [RefreshProperties (RefreshProperties.Repaint)] + [TypeConverter (typeof (ImageKeyConverter))] + [MWFCategory("Appearance")] + public string ImageKey { + get { return this.image_key; } + set { + if (this.image_key != value) { + this.image = null; + this.image_index = -1; + this.image_key = value; + this.Invalidate (); + } + } + } + + [DefaultValue(null)] + [MWFDescription("ImageList used for ImageIndex"), MWFCategory("Appearance")] + [RefreshProperties (RefreshProperties.Repaint)] + public ImageList ImageList { + get { return image_list; } + set { + if (image_list != value) { + image_list = value; + + if (value != null && image != null) + image = null; + + Invalidate (); + } + } + } + + [Browsable(false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new ImeMode ImeMode { + get { return base.ImeMode; } + set { base.ImeMode = value; } + } + + [SettingsBindable (true)] + //[Editor ("System.ComponentModel.Design.MultilineStringEditor, " + Consts.AssemblySystem_Design, + //"System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)] + public override string Text { + get { return base.Text; } + set { base.Text = value; } + } + + [Localizable(true)] + [DefaultValue(ContentAlignment.MiddleCenter)] + [MWFDescription("Alignment for button text"), MWFCategory("Appearance")] + public virtual ContentAlignment TextAlign { + get { return text_alignment; } + set { + if (text_alignment != value) { + text_alignment = value; + + text_format_flags &= ~TextFormatFlags.Bottom; + text_format_flags &= ~TextFormatFlags.Top; + text_format_flags &= ~TextFormatFlags.Left; + text_format_flags &= ~TextFormatFlags.Right; + text_format_flags &= ~TextFormatFlags.HorizontalCenter; + text_format_flags &= ~TextFormatFlags.VerticalCenter; + + switch (text_alignment) { + case ContentAlignment.TopLeft: + text_format.Alignment=StringAlignment.Near; + text_format.LineAlignment=StringAlignment.Near; + break; + + case ContentAlignment.TopCenter: + text_format.Alignment=StringAlignment.Center; + text_format.LineAlignment=StringAlignment.Near; + text_format_flags |= TextFormatFlags.HorizontalCenter; + break; + + case ContentAlignment.TopRight: + text_format.Alignment=StringAlignment.Far; + text_format.LineAlignment=StringAlignment.Near; + text_format_flags |= TextFormatFlags.Right; + break; + + case ContentAlignment.MiddleLeft: + text_format.Alignment=StringAlignment.Near; + text_format.LineAlignment=StringAlignment.Center; + text_format_flags |= TextFormatFlags.VerticalCenter; + break; + + case ContentAlignment.MiddleCenter: + text_format.Alignment=StringAlignment.Center; + text_format.LineAlignment=StringAlignment.Center; + text_format_flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter; + break; + + case ContentAlignment.MiddleRight: + text_format.Alignment=StringAlignment.Far; + text_format.LineAlignment=StringAlignment.Center; + text_format_flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.Right; + break; + + case ContentAlignment.BottomLeft: + text_format.Alignment=StringAlignment.Near; + text_format.LineAlignment=StringAlignment.Far; + text_format_flags |= TextFormatFlags.Bottom; + break; + + case ContentAlignment.BottomCenter: + text_format.Alignment=StringAlignment.Center; + text_format.LineAlignment=StringAlignment.Far; + text_format_flags |= TextFormatFlags.HorizontalCenter | TextFormatFlags.Bottom; + break; + + case ContentAlignment.BottomRight: + text_format.Alignment=StringAlignment.Far; + text_format.LineAlignment=StringAlignment.Far; + text_format_flags |= TextFormatFlags.Bottom | TextFormatFlags.Right; + break; + } + + Invalidate(); + } + } + } + + [Localizable (true)] + [DefaultValue (TextImageRelation.Overlay)] + [MWFCategory("Appearance")] + public TextImageRelation TextImageRelation { + get { return this.text_image_relation; } + set { + if (!Enum.IsDefined (typeof (TextImageRelation), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextImageRelation", value)); + + if (this.text_image_relation != value) { + this.text_image_relation = value; + + if (this.AutoSize && this.Parent != null) + this.Parent.PerformLayout (this, "TextImageRelation"); + + this.Invalidate (); + } + } + } + + [DefaultValue (false)] + [MWFCategory("Behavior")] + public bool UseCompatibleTextRendering { + get { return use_compatible_text_rendering; } + set { + if (use_compatible_text_rendering != value) { + use_compatible_text_rendering = value; + if (Parent != null) + Parent.PerformLayout (this, "UseCompatibleTextRendering"); + Invalidate (); + } + } + } + + [DefaultValue (true)] + [MWFCategory("Appearance")] + public bool UseMnemonic { + get { return this.use_mnemonic; } + set { + if (this.use_mnemonic != value) { + this.use_mnemonic = value; + + if (this.use_mnemonic) + text_format_flags &= ~TextFormatFlags.NoPrefix; + else + text_format_flags |= TextFormatFlags.NoPrefix; + + this.Invalidate (); + } + } + } + + [MWFCategory("Appearance")] + public bool UseVisualStyleBackColor { + get { return use_visual_style_back_color; } + set { + if (use_visual_style_back_color != value) { + use_visual_style_back_color = value; + Invalidate (); + } + } + } + #endregion // Public Instance Properties + + #region Protected Properties + protected override CreateParams CreateParams { + get { return base.CreateParams; } + } + + protected override ImeMode DefaultImeMode { + get { return ImeMode.Disable; } + } + + protected override Size DefaultSize { + get { return ThemeEngine.Current.ButtonBaseDefaultSize; } + } + + protected internal bool IsDefault { + get { return is_default; } + set { + if (is_default != value) { + is_default = value; + Invalidate (); + } + } + } + #endregion // Public Instance Properties + + #region Public Methods + // The base calls into GetPreferredSizeCore, which we will override in our subclasses + public override Size GetPreferredSize (Size proposedSize) + { + return base.GetPreferredSize (proposedSize); + } + #endregion + + #region Protected Methods + protected override AccessibleObject CreateAccessibilityInstance () + { + return new ButtonBaseAccessibleObject (this); + } + + protected override void Dispose (bool disposing) + { + base.Dispose (disposing); + } + + protected override void OnEnabledChanged (EventArgs e) + { + base.OnEnabledChanged (e); + } + + protected override void OnGotFocus (EventArgs e) + { + Invalidate (); + base.OnGotFocus (e); + } + + protected override void OnKeyDown (KeyEventArgs kevent) + { + if (kevent.KeyData == Keys.Space) { + is_pressed = true; + Invalidate (); + kevent.Handled = true; + } + + base.OnKeyDown (kevent); + } + + protected override void OnKeyUp (KeyEventArgs kevent) + { + if (kevent.KeyData == Keys.Space) { + is_pressed = false; + Invalidate (); + OnClick (EventArgs.Empty); + kevent.Handled = true; + } + + base.OnKeyUp (kevent); + } + + protected override void OnLostFocus (EventArgs e) + { + Invalidate (); + base.OnLostFocus (e); + } + + protected override void OnMouseDown (MouseEventArgs mevent) + { + if ((mevent.Button & MouseButtons.Left) != 0) { + is_pressed = true; + Invalidate (); + } + + base.OnMouseDown (mevent); + } + + protected override void OnMouseEnter (EventArgs eventargs) + { + is_entered = true; + Invalidate (); + base.OnMouseEnter (eventargs); + } + + protected override void OnMouseLeave (EventArgs eventargs) + { + is_entered = false; + Invalidate (); + base.OnMouseLeave (eventargs); + } + + protected override void OnMouseMove (MouseEventArgs mevent) { + bool inside = false; + bool redraw = false; + + if (ClientRectangle.Contains (mevent.Location)) + inside = true; + + // If the button was pressed and we leave, release the button press and vice versa + if ((mevent.Button & MouseButtons.Left) != 0) { + if (this.Capture && (inside != is_pressed)) { + is_pressed = inside; + redraw = true; + } + } + + if (is_entered != inside) { + is_entered = inside; + redraw = true; + } + + if (redraw) + Invalidate (); + + base.OnMouseMove (mevent); + } + + protected override void OnMouseUp (MouseEventArgs mevent) + { + if (this.Capture && ((mevent.Button & MouseButtons.Left) != 0)) { + this.Capture = false; + + if (is_pressed) { + is_pressed = false; + Invalidate (); + } else if ((this.flat_style == FlatStyle.Flat) || (this.flat_style == FlatStyle.Popup)) { + Invalidate (); + } + + if (ClientRectangle.Contains (mevent.Location)) + if (!ValidationFailed) { + OnClick (EventArgs.Empty); + OnMouseClick (mevent); + } + } + + base.OnMouseUp (mevent); + } + + protected override void OnPaint (PaintEventArgs pevent) + { + Draw (pevent); + base.OnPaint (pevent); + } + + protected override void OnParentChanged (EventArgs e) + { + base.OnParentChanged (e); + } + + protected override void OnTextChanged (EventArgs e) + { + Invalidate (); + base.OnTextChanged (e); + } + + protected override void OnVisibleChanged (EventArgs e) + { + if (!Visible) { + is_pressed = false; + is_entered = false; + } + + base.OnVisibleChanged (e); + } + + protected void ResetFlagsandPaint () + { + // Nothing to do; MS internal + // Should we do Invalidate (); ? + } + + protected override void WndProc (ref Message m) + { + switch ((Msg)m.Msg) { + case Msg.WM_LBUTTONDBLCLK: { + HaveDoubleClick (); + break; + } + + case Msg.WM_MBUTTONDBLCLK: { + HaveDoubleClick (); + break; + } + + case Msg.WM_RBUTTONDBLCLK: { + HaveDoubleClick (); + break; + } + } + + base.WndProc (ref m); + } + #endregion // Public Instance Properties + + #region Public Events + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler AutoSizeChanged { + add { base.AutoSizeChanged += value; } + remove { base.AutoSizeChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler ImeModeChanged { + add { base.ImeModeChanged += value; } + remove { base.ImeModeChanged -= value; } + } + #endregion // Events + + #region Internal Properties + internal ButtonState ButtonState { + get { + ButtonState ret = ButtonState.Normal; + + if (Enabled) { + // Popup style is only followed as long as the mouse isn't "in" the control + if (is_entered) { + if (flat_style == FlatStyle.Flat) { + ret |= ButtonState.Flat; + } + } else { + if (flat_style == FlatStyle.Flat || flat_style == FlatStyle.Popup) { + ret |= ButtonState.Flat; + } + } + + if (is_entered && is_pressed) { + ret |= ButtonState.Pushed; + } + } else { + ret |= ButtonState.Inactive; + if ((flat_style == FlatStyle.Flat) || (flat_style == FlatStyle.Popup)) { + ret |= ButtonState.Flat; + } + } + return ret; + } + } + + internal bool Pressed { + get { return this.is_pressed; } + } + + // The flags to be used for MeasureText and DrawText + internal TextFormatFlags TextFormatFlags { + get { return this.text_format_flags; } + } + #endregion + + #region Internal Methods + // Derived classes should override Draw method and we dont want + // to break the control signature, hence this approach. + internal virtual void Draw (PaintEventArgs pevent) + { + ThemeEngine.Current.DrawButtonBase (pevent.Graphics, pevent.ClipRectangle, this); + } + + internal virtual void HaveDoubleClick () + { + // override me + } + + internal override void OnPaintBackgroundInternal (PaintEventArgs e) + { + base.OnPaintBackground (e); + } + #endregion // Internal Methods + + #region ButtonBaseAccessibleObject sub-class + [ComVisible (true)] + public class ButtonBaseAccessibleObject : WidgetAccessibleObject + { + #region ButtonBaseAccessibleObject Local Variables + private new Widget owner; + #endregion // ButtonBaseAccessibleObject Local Variables + + #region ButtonBaseAccessibleObject Constructors + public ButtonBaseAccessibleObject (Widget owner) : base (owner) + { + if (owner == null) + throw new ArgumentNullException ("owner"); + + this.owner = owner; + default_action = "Press"; + role = AccessibleRole.PushButton; + } + #endregion // ButtonBaseAccessibleObject Constructors + + #region Public Properties + public override AccessibleStates State { + get { return base.State; } + } + #endregion + + #region ButtonBaseAccessibleObject Methods + public override void DoDefaultAction () + { + ((ButtonBase)owner).OnClick (EventArgs.Empty); + } + #endregion // ButtonBaseAccessibleObject Methods + } + #endregion // ButtonBaseAccessibleObject sub-class + } +} diff --git a/source/ShiftUI/Internal/ButtonRenderer.cs b/source/ShiftUI/Internal/ButtonRenderer.cs new file mode 100644 index 0000000..a2e4237 --- /dev/null +++ b/source/ShiftUI/Internal/ButtonRenderer.cs @@ -0,0 +1,153 @@ +// +// ButtonRenderer.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using ShiftUI.VisualStyles; +using System; + +namespace ShiftUI +{ + public sealed class ButtonRenderer + { + private static bool always_use_visual_styles = false; + + #region Private Constructor + private ButtonRenderer () { } + #endregion + + #region Public Static Methods + public static void DrawButton (Graphics g, Rectangle bounds, PushButtonState state) + { + DrawButton (g, bounds, String.Empty, null, TextFormatFlags.Default, null, Rectangle.Empty, false, state); + } + + public static void DrawButton (Graphics g, Rectangle bounds, bool focused, PushButtonState state) + { + DrawButton (g, bounds, String.Empty, null, TextFormatFlags.Default, null, Rectangle.Empty, focused, state); + } + + public static void DrawButton (Graphics g, Rectangle bounds, Image image, Rectangle imageBounds, bool focused, PushButtonState state) + { + DrawButton (g, bounds, String.Empty, null, TextFormatFlags.Default, image, imageBounds, focused, state); + } + + public static void DrawButton (Graphics g, Rectangle bounds, string buttonText, Font font, bool focused, PushButtonState state) + { + DrawButton (g, bounds, buttonText, font, TextFormatFlags.HorizontalCenter, null, Rectangle.Empty, focused, state); + } + + public static void DrawButton (Graphics g, Rectangle bounds, string buttonText, Font font, TextFormatFlags flags, bool focused, PushButtonState state) + { + DrawButton (g, bounds, buttonText, font, flags, null, Rectangle.Empty, focused, state); + } + + public static void DrawButton (Graphics g, Rectangle bounds, string buttonText, Font font, Image image, Rectangle imageBounds, bool focused, PushButtonState state) + { + DrawButton (g, bounds, buttonText, font, TextFormatFlags.HorizontalCenter, image, imageBounds, focused, state); + } + + public static void DrawButton (Graphics g, Rectangle bounds, string buttonText, Font font, TextFormatFlags flags, Image image, Rectangle imageBounds, bool focused, PushButtonState state) + { + if (Application.RenderWithVisualStyles || always_use_visual_styles == true) { + VisualStyleRenderer vsr = GetPushButtonRenderer (state); + + vsr.DrawBackground (g, bounds); + + if (image != null) + vsr.DrawImage (g, imageBounds, image); + } else { + if (state == PushButtonState.Pressed) + WidgetPaint.DrawButton (g, bounds, ButtonState.Pushed); + else + WidgetPaint.DrawButton (g, bounds, ButtonState.Normal); + + if (image != null) + g.DrawImage (image, imageBounds); + } + + Rectangle focus_rect = bounds; + focus_rect.Inflate (-3, -3); + + if (focused) + WidgetPaint.DrawFocusRectangle (g, focus_rect); + + if (buttonText != String.Empty) + if (state == PushButtonState.Disabled) + TextRenderer.DrawText (g, buttonText, font, focus_rect, SystemColors.GrayText, flags); + else + TextRenderer.DrawText (g, buttonText, font, focus_rect, SystemColors.ControlText, flags); + } + + public static bool IsBackgroundPartiallyTransparent (PushButtonState state) + { + if (!VisualStyleRenderer.IsSupported) + return false; + + VisualStyleRenderer vsr = GetPushButtonRenderer (state); + + return vsr.IsBackgroundPartiallyTransparent (); + } + + public static void DrawParentBackground (Graphics g, Rectangle bounds, Widget childControl) + { + if (!VisualStyleRenderer.IsSupported) + return; + + VisualStyleRenderer vsr = new VisualStyleRenderer (VisualStyleElement.Button.PushButton.Default); + + vsr.DrawParentBackground (g, bounds, childControl); + } + #endregion + + #region Private Static Methods + internal static VisualStyleRenderer GetPushButtonRenderer (PushButtonState state) + { + switch (state) { + case PushButtonState.Normal: + return new VisualStyleRenderer (VisualStyleElement.Button.PushButton.Normal); + case PushButtonState.Hot: + return new VisualStyleRenderer (VisualStyleElement.Button.PushButton.Hot); + case PushButtonState.Pressed: + return new VisualStyleRenderer (VisualStyleElement.Button.PushButton.Pressed); + case PushButtonState.Disabled: + return new VisualStyleRenderer (VisualStyleElement.Button.PushButton.Disabled); + case PushButtonState.Default: + default: + return new VisualStyleRenderer (VisualStyleElement.Button.PushButton.Default); + } + } + #endregion + + #region Public Static Properties + public static bool RenderMatchingApplicationState { + get { return !always_use_visual_styles; } + set { always_use_visual_styles = !value; } + } + #endregion + } +} \ No newline at end of file diff --git a/source/ShiftUI/Internal/CheckBoxRenderer.cs b/source/ShiftUI/Internal/CheckBoxRenderer.cs new file mode 100644 index 0000000..8800aa0 --- /dev/null +++ b/source/ShiftUI/Internal/CheckBoxRenderer.cs @@ -0,0 +1,194 @@ +// +// CheckBoxRenderer.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using ShiftUI.VisualStyles; +using System; + +namespace ShiftUI +{ + public sealed class CheckBoxRenderer + { + private static bool always_use_visual_styles = false; + + #region Private Constructor + private CheckBoxRenderer () {} + #endregion + + #region Public Static Methods + public static void DrawCheckBox (Graphics g, Point glyphLocation, CheckBoxState state) + { + DrawCheckBox (g, glyphLocation, Rectangle.Empty, String.Empty, null, TextFormatFlags.HorizontalCenter, null, Rectangle.Empty, false, state); + } + + public static void DrawCheckBox (Graphics g, Point glyphLocation, Rectangle textBounds, string checkBoxText, Font font, bool focused, CheckBoxState state) + { + DrawCheckBox (g, glyphLocation, textBounds, checkBoxText, font, TextFormatFlags.HorizontalCenter, null, Rectangle.Empty, focused, state); + } + + public static void DrawCheckBox (Graphics g, Point glyphLocation, Rectangle textBounds, string checkBoxText, Font font, TextFormatFlags flags, bool focused, CheckBoxState state) + { + DrawCheckBox (g, glyphLocation, textBounds, checkBoxText, font, flags, null, Rectangle.Empty, focused, state); + } + + public static void DrawCheckBox (Graphics g, Point glyphLocation, Rectangle textBounds, string checkBoxText, Font font, Image image, Rectangle imageBounds, bool focused, CheckBoxState state) + { + DrawCheckBox (g, glyphLocation, textBounds, checkBoxText, font, TextFormatFlags.HorizontalCenter, image, imageBounds, focused, state); + } + + public static void DrawCheckBox (Graphics g, Point glyphLocation, Rectangle textBounds, string checkBoxText, Font font, TextFormatFlags flags, Image image, Rectangle imageBounds, bool focused, CheckBoxState state) + { + Rectangle bounds = new Rectangle (glyphLocation, GetGlyphSize (g, state)); + + if (Application.RenderWithVisualStyles || always_use_visual_styles == true) { + VisualStyleRenderer vsr = GetCheckBoxRenderer (state); + + vsr.DrawBackground (g, bounds); + + if (image != null) + vsr.DrawImage (g, imageBounds, image); + + if (focused) + WidgetPaint.DrawFocusRectangle (g, textBounds); + + if (checkBoxText != String.Empty) + if (state == CheckBoxState.CheckedDisabled || state == CheckBoxState.MixedDisabled || state == CheckBoxState.UncheckedDisabled) + TextRenderer.DrawText (g, checkBoxText, font, textBounds, SystemColors.GrayText, flags); + else + TextRenderer.DrawText (g, checkBoxText, font, textBounds, SystemColors.ControlText, flags); + } else { + switch (state) { + case CheckBoxState.CheckedDisabled: + case CheckBoxState.MixedDisabled: + case CheckBoxState.MixedPressed: + WidgetPaint.DrawCheckBox (g, bounds, ButtonState.Inactive | ButtonState.Checked); + break; + case CheckBoxState.CheckedHot: + case CheckBoxState.CheckedNormal: + WidgetPaint.DrawCheckBox (g, bounds, ButtonState.Checked); + break; + case CheckBoxState.CheckedPressed: + WidgetPaint.DrawCheckBox (g, bounds, ButtonState.Pushed | ButtonState.Checked); + break; + case CheckBoxState.MixedHot: + case CheckBoxState.MixedNormal: + WidgetPaint.DrawMixedCheckBox (g, bounds, ButtonState.Checked); + break; + case CheckBoxState.UncheckedDisabled: + case CheckBoxState.UncheckedPressed: + WidgetPaint.DrawCheckBox (g, bounds, ButtonState.Inactive); + break; + case CheckBoxState.UncheckedHot: + case CheckBoxState.UncheckedNormal: + WidgetPaint.DrawCheckBox (g, bounds, ButtonState.Normal); + break; + } + + if (image != null) + g.DrawImage (image, imageBounds); + + if (focused) + WidgetPaint.DrawFocusRectangle (g, textBounds); + + if (checkBoxText != String.Empty) + TextRenderer.DrawText (g, checkBoxText, font, textBounds, SystemColors.ControlText, flags); + } + } + + public static bool IsBackgroundPartiallyTransparent (CheckBoxState state) + { + if (!VisualStyleRenderer.IsSupported) + return false; + + VisualStyleRenderer vsr = GetCheckBoxRenderer (state); + + return vsr.IsBackgroundPartiallyTransparent (); + } + + public static void DrawParentBackground (Graphics g, Rectangle bounds, Widget childControl) + { + if (!VisualStyleRenderer.IsSupported) + return; + + VisualStyleRenderer vsr = new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.UncheckedNormal); + + vsr.DrawParentBackground (g, bounds, childControl); + } + + public static Size GetGlyphSize (Graphics g, CheckBoxState state) + { + if (!VisualStyleRenderer.IsSupported) + return new Size (13, 13); + + VisualStyleRenderer vsr = GetCheckBoxRenderer (state); + + return vsr.GetPartSize (g, ThemeSizeType.Draw); + } + #endregion + + #region Private Static Methods + private static VisualStyleRenderer GetCheckBoxRenderer (CheckBoxState state) + { + switch (state) { + case CheckBoxState.CheckedDisabled: + return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.CheckedDisabled); + case CheckBoxState.CheckedHot: + return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.CheckedHot); + case CheckBoxState.CheckedNormal: + return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.CheckedNormal); + case CheckBoxState.CheckedPressed: + return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.CheckedPressed); + case CheckBoxState.MixedDisabled: + return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.MixedDisabled); + case CheckBoxState.MixedHot: + return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.MixedHot); + case CheckBoxState.MixedNormal: + return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.MixedNormal); + case CheckBoxState.MixedPressed: + return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.MixedPressed); + case CheckBoxState.UncheckedDisabled: + return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.UncheckedDisabled); + case CheckBoxState.UncheckedHot: + return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.UncheckedHot); + case CheckBoxState.UncheckedNormal: + default: + return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.UncheckedNormal); + case CheckBoxState.UncheckedPressed: + return new VisualStyleRenderer (VisualStyleElement.Button.CheckBox.UncheckedPressed); + } + } + #endregion + + #region Public Static Properties + public static bool RenderMatchingApplicationState { + get { return !always_use_visual_styles; } + set { always_use_visual_styles = !value; } + } + #endregion + } +} \ No newline at end of file diff --git a/source/ShiftUI/Internal/Clipboard.cs b/source/ShiftUI/Internal/Clipboard.cs new file mode 100644 index 0000000..9c832a8 --- /dev/null +++ b/source/ShiftUI/Internal/Clipboard.cs @@ -0,0 +1,433 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +using System; +using System.Drawing; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Collections; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Threading; + +namespace ShiftUI { + public sealed class Clipboard { + #region Local Variables + #endregion // Local Variables + + #region Constructors + private Clipboard() { + } + #endregion // Constructors + + #region Private Methods + private static bool ConvertToClipboardData(ref int type, object obj, out byte[] data) { + data = null; + return false; + } + + private static bool ConvertFromClipboardData(int type, IntPtr data, out object obj) { + obj = null; + if (data == IntPtr.Zero) { + return false; + } + return false; + } + #endregion // Private Methods + + #region Public Static Methods + public static void Clear () + { + IntPtr clipboard_handle; + + clipboard_handle = XplatUI.ClipboardOpen (false); + XplatUI.ClipboardStore (clipboard_handle, null, 0, null, false); + } + + public static bool ContainsAudio () + { + return ClipboardContainsFormat (DataFormats.WaveAudio); + } + + public static bool ContainsData (string format) + { + return ClipboardContainsFormat (format); + } + + public static bool ContainsFileDropList () + { + return ClipboardContainsFormat (DataFormats.FileDrop); + } + + public static bool ContainsImage () + { + return ClipboardContainsFormat (DataFormats.Bitmap); + } + + public static bool ContainsText () + { + return ClipboardContainsFormat (DataFormats.Text, DataFormats.UnicodeText); + } + + public static bool ContainsText (TextDataFormat format) + { + switch (format) { + case TextDataFormat.Text: + return ClipboardContainsFormat (DataFormats.Text); + case TextDataFormat.UnicodeText: + return ClipboardContainsFormat (DataFormats.UnicodeText); + case TextDataFormat.Rtf: + return ClipboardContainsFormat (DataFormats.Rtf); + case TextDataFormat.Html: + return ClipboardContainsFormat (DataFormats.Html); + case TextDataFormat.CommaSeparatedValue: + return ClipboardContainsFormat (DataFormats.CommaSeparatedValue); + } + + return false; + } + + public static Stream GetAudioStream () + { + IDataObject data = GetDataObject (); + + if (data == null) + return null; + + return (Stream)data.GetData (DataFormats.WaveAudio, true); + } + + public static Object GetData (string format) + { + IDataObject data = GetDataObject (); + + if (data == null) + return null; + + return data.GetData (format, true); + } + + public static IDataObject GetDataObject () + { + return GetDataObject (false); + } + + public static StringCollection GetFileDropList () + { + IDataObject data = GetDataObject (); + + if (data == null) + return null; + + return (StringCollection)data.GetData (DataFormats.FileDrop, true); + } + + public static Image GetImage () + { + IDataObject data = GetDataObject (); + + if (data == null) + return null; + + return (Image)data.GetData (DataFormats.Bitmap, true); + } + + public static string GetText () + { + return GetText (TextDataFormat.UnicodeText); + } + + public static string GetText (TextDataFormat format) + { + if (!Enum.IsDefined (typeof (TextDataFormat), format)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextDataFormat", format)); + + IDataObject data = GetDataObject (); + + if (data == null) + return string.Empty; + + string retval; + + switch (format) { + case TextDataFormat.Text: + default: + retval = (string)data.GetData (DataFormats.Text, true); + break; + case TextDataFormat.UnicodeText: + retval = (string)data.GetData (DataFormats.UnicodeText, true); + break; + case TextDataFormat.Rtf: + retval = (string)data.GetData (DataFormats.Rtf, true); + break; + case TextDataFormat.Html: + retval = (string)data.GetData (DataFormats.Html, true); + break; + case TextDataFormat.CommaSeparatedValue: + retval = (string)data.GetData (DataFormats.CommaSeparatedValue, true); + break; + } + + return retval == null ? string.Empty : retval; + } + + public static void SetAudio (byte[] audioBytes) + { + if (audioBytes == null) + throw new ArgumentNullException ("audioBytes"); + + MemoryStream ms = new MemoryStream (audioBytes); + + SetAudio (ms); + } + + public static void SetAudio (Stream audioStream) + { + if (audioStream == null) + throw new ArgumentNullException ("audioStream"); + + SetData (DataFormats.WaveAudio, audioStream); + } + + public static void SetData (string format, Object data) + { + if (data == null) + throw new ArgumentNullException ("data"); + + DataObject data_object = new DataObject (format, data); + SetDataObject (data_object); + } + + public static void SetDataObject(object data) { + SetDataObject(data, false); // MSDN says default behavior is to place non-persistent data to clipboard + } + + public static void SetDataObject(object data, bool copy) { + SetDataObject(data, copy, 10, 100); // MSDN says default behavior is to try 10 times with 100 ms delay + } + + internal static void SetDataObjectImpl(object data, bool copy) { + IntPtr clipboard_handle; + XplatUI.ObjectToClipboard converter; + int native_format; + DataFormats.Format item_format; + + converter = new XplatUI.ObjectToClipboard(ConvertToClipboardData); + + clipboard_handle = XplatUI.ClipboardOpen(false); + XplatUI.ClipboardStore(clipboard_handle, null, 0, null, copy); // Empty clipboard + + native_format = -1; + + if (data is IDataObject) { + string[] formats; + + IDataObject data_object = data as IDataObject; + formats = data_object.GetFormats(); + for (int i = 0; i < formats.Length; i++) { + item_format = DataFormats.GetFormat(formats[i]); + if ((item_format != null) && (item_format.Name != DataFormats.StringFormat)) { + native_format = item_format.Id; + } + + object obj = data_object.GetData (formats [i]); + + // this is used only by custom formats + if (IsDataSerializable (obj)) + item_format.is_serializable = true; + + XplatUI.ClipboardStore(clipboard_handle, obj, native_format, converter, copy); + } + } else { + item_format = DataFormats.Format.Find(data.GetType().FullName); + if ((item_format != null) && (item_format.Name != DataFormats.StringFormat)) { + native_format = item_format.Id; + } + + XplatUI.ClipboardStore(clipboard_handle, data, native_format, converter, copy); + } + XplatUI.ClipboardClose(clipboard_handle); + } + + static bool IsDataSerializable (object obj) + { + if (obj is ISerializable) + return true; + + AttributeCollection attrs = TypeDescriptor.GetAttributes (obj); + return attrs [typeof (SerializableAttribute)] != null; + } + + public static void SetDataObject(object data, bool copy, int retryTimes, int retryDelay) + { + if (data == null) + throw new ArgumentNullException("data"); + if (retryTimes < 0) + throw new ArgumentOutOfRangeException("retryTimes"); + if (retryDelay < 0) + throw new ArgumentOutOfRangeException("retryDelay"); + + // MS implementation actually puts data to clipboard even when retryTimes == 0 + bool retry = true; + do + { + retry = false; + --retryTimes; + try + { + SetDataObjectImpl(data, copy); + } catch (ExternalException) { + if (retryTimes <= 0) + throw; + retry = true; + Thread.Sleep(retryDelay); + } + } while (retry && retryTimes > 0); + } + + [MonoInternalNote ("Needs additional checks for valid paths, see MSDN")] + public static void SetFileDropList (StringCollection filePaths) + { + if (filePaths == null) + throw new ArgumentNullException ("filePaths"); + + SetData (DataFormats.FileDrop, filePaths); + } + + public static void SetImage (Image image) + { + if (image == null) + throw new ArgumentNullException ("image"); + + SetData (DataFormats.Bitmap, image); + } + + public static void SetText (string text) + { + if (string.IsNullOrEmpty (text)) + throw new ArgumentNullException ("text"); + + SetData (DataFormats.UnicodeText, text); + } + + public static void SetText (string text, TextDataFormat format) + { + if (string.IsNullOrEmpty (text)) + throw new ArgumentNullException ("text"); + if (!Enum.IsDefined (typeof (TextDataFormat), format)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextDataFormat", format)); + + switch (format) { + case TextDataFormat.Text: + SetData (DataFormats.Text, text); + break; + case TextDataFormat.UnicodeText: + SetData (DataFormats.UnicodeText, text); + break; + case TextDataFormat.Rtf: + SetData (DataFormats.Rtf, text); + break; + case TextDataFormat.Html: + SetData (DataFormats.Html, text); + break; + case TextDataFormat.CommaSeparatedValue: + SetData (DataFormats.CommaSeparatedValue, text); + break; + } + } + #endregion // Public Static Methods + + #region Internal Static Methods + internal static IDataObject GetDataObject (bool primary_selection) + { + DataObject clipboard; + IntPtr clipboard_handle; + int[] native_formats; + DataFormats.Format item_format; + object managed_clipboard_item; + XplatUI.ClipboardToObject converter; + + converter = new XplatUI.ClipboardToObject (ConvertFromClipboardData); + + clipboard_handle = XplatUI.ClipboardOpen (primary_selection); + native_formats = XplatUI.ClipboardAvailableFormats (clipboard_handle); + if (native_formats == null) { + return null; // Clipboard empty + } + + // Build the IDataObject + clipboard = new DataObject (); + for (int i = 0; i < native_formats.Length; i++) { + // We might get a format we don't understand or know + item_format = DataFormats.GetFormat (native_formats[i]); + + if (item_format != null) { + managed_clipboard_item = XplatUI.ClipboardRetrieve (clipboard_handle, native_formats[i], converter); + + if (managed_clipboard_item != null) { + clipboard.SetData (item_format.Name, managed_clipboard_item); + // We don't handle 'bitmap' since it involves handles, so we'll equate it to dib + if (item_format.Name == DataFormats.Dib) { + clipboard.SetData (DataFormats.Bitmap, managed_clipboard_item); + } + } + } + } + + XplatUI.ClipboardClose (clipboard_handle); + + return clipboard; + } + + internal static bool ClipboardContainsFormat (params string[] formats) + { + IntPtr clipboard_handle; + int[] native_formats; + DataFormats.Format item_format; + + clipboard_handle = XplatUI.ClipboardOpen (false); + native_formats = XplatUI.ClipboardAvailableFormats (clipboard_handle); + + if (native_formats == null) + return false; + + foreach (int i in native_formats) { + // We might get a format we don't understand or know + item_format = DataFormats.GetFormat (i); + + if (item_format != null) + if (((IList)formats).Contains (item_format.Name)) + return true; + } + + return false; + } + #endregion + } +} diff --git a/source/ShiftUI/Internal/Consts.cs b/source/ShiftUI/Internal/Consts.cs new file mode 100644 index 0000000..e69de29 diff --git a/source/ShiftUI/Internal/ContextMenuStrip.cs b/source/ShiftUI/Internal/ContextMenuStrip.cs new file mode 100644 index 0000000..052bb04 --- /dev/null +++ b/source/ShiftUI/Internal/ContextMenuStrip.cs @@ -0,0 +1,80 @@ +// +// ContextMenuStrip.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [DefaultEvent ("Opening")] + public class ContextMenuStrip : ToolStripDropDownMenu + { + Widget source_Widget; + internal Widget container; + + #region Public Construtors + public ContextMenuStrip () : base () + { + source_Widget = null; + } + + public ContextMenuStrip (IContainer container) : base () + { + source_Widget = null; + } + #endregion + + #region Public Properties + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public Widget SourceWidget { + get { return this.source_Widget; } + } + #endregion + + #region Protected Methods + protected override void Dispose (bool disposing) + { + base.Dispose (disposing); + } + + protected override void SetVisibleCore (bool visible) + { + base.SetVisibleCore (visible); + if (visible) + XplatUI.SetTopmost (this.Handle, true); + } + #endregion + + internal void SetSourceWidget (Widget source_Widget) + { + container = this.source_Widget = source_Widget; + } + } +} diff --git a/source/ShiftUI/Internal/ControlBindingsCollection.cs b/source/ShiftUI/Internal/ControlBindingsCollection.cs new file mode 100644 index 0000000..345efee --- /dev/null +++ b/source/ShiftUI/Internal/ControlBindingsCollection.cs @@ -0,0 +1,204 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +using System; +using System.Collections; +using System.ComponentModel; +using System.Reflection; + + +namespace ShiftUI { + [DefaultEvent("CollectionChanged")] + public class WidgetBindingsCollection : BindingsCollection { + #region Fields + private Widget control; + private IBindableComponent bindable_component; + private DataSourceUpdateMode default_datasource_update_mode; + #endregion // Fields + + #region Constructors + internal WidgetBindingsCollection (Widget control) { + this.control = control; + bindable_component = this.control as IBindableComponent; + default_datasource_update_mode = DataSourceUpdateMode.OnValidation; + } + + public WidgetBindingsCollection (IBindableComponent control) + { + bindable_component = control; + control = control as Widget; + default_datasource_update_mode = DataSourceUpdateMode.OnValidation; + } + #endregion // Constructors + + #region Public Instance Properties + public Widget Widget { + get { + return control; + } + } + + public Binding this[string propertyName] { + get { + foreach (Binding b in base.List) { + if (b.PropertyName == propertyName) { + return b; + } + } + return null; + } + } + + public IBindableComponent BindableComponent { + get { + return bindable_component; + } + } + + public DataSourceUpdateMode DefaultDataSourceUpdateMode { + get { + return default_datasource_update_mode; + } + set { + default_datasource_update_mode = value; + } + } + #endregion // Public Instance Properties + + #region Public Instance Methods + public new void Add (Binding binding) + { + AddCore (binding); + OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, binding)); + } + + public Binding Add (string propertyName, object dataSource, string dataMember) + { + if (dataSource == null) + throw new ArgumentNullException ("dataSource"); + + Binding res = new Binding (propertyName, dataSource, dataMember); + res.DataSourceUpdateMode = default_datasource_update_mode; + Add (res); + return res; + } + + public Binding Add (string propertyName, object dataSource, string dataMember, bool formattingEnabled) + { + return Add (propertyName, dataSource, dataMember, formattingEnabled, default_datasource_update_mode, null, String.Empty, null); + } + + public Binding Add (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode updateMode) + { + return Add (propertyName, dataSource, dataMember, formattingEnabled, updateMode, null, String.Empty, null); + } + + public Binding Add (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode updateMode, + object nullValue) + { + return Add (propertyName, dataSource, dataMember, formattingEnabled, updateMode, nullValue, String.Empty, null); + } + + public Binding Add (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode updateMode, + object nullValue, string formatString) + { + return Add (propertyName, dataSource, dataMember, formattingEnabled, updateMode, nullValue, formatString, null); + } + + public Binding Add (string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode updateMode, + object nullValue, string formatString, IFormatProvider formatInfo) + { + if (dataSource == null) + throw new ArgumentNullException ("dataSource"); + + Binding res = new Binding (propertyName, dataSource, dataMember); + res.FormattingEnabled = formattingEnabled; + res.DataSourceUpdateMode = updateMode; + res.NullValue = nullValue; + res.FormatString = formatString; + res.FormatInfo = formatInfo; + + Add (res); + return res; + } + + public new void Clear() { + base.Clear(); + } + + public new void Remove (Binding binding) { + if (binding == null) + throw new NullReferenceException("The binding is null"); + + base.Remove(binding); + } + + public new void RemoveAt(int index) { + if (index < 0 || index >= base.List.Count) + throw new ArgumentOutOfRangeException("index"); + + base.RemoveAt(index); + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + protected override void AddCore (Binding dataBinding) + { + if (dataBinding == null) + throw new ArgumentNullException ("dataBinding"); + + if (dataBinding.Widget != null && dataBinding.BindableComponent != bindable_component) + throw new ArgumentException ("dataBinding belongs to another BindingsCollection"); + + for (int i = 0; i < Count; i++) { + Binding bnd = this [i]; + if (bnd == null || bnd.PropertyName.Length == 0 || dataBinding.PropertyName.Length == 0) { + continue; + } + + if (String.Compare (bnd.PropertyName, dataBinding.PropertyName, true) == 0) { + throw new ArgumentException ("The binding is already in the collection"); + } + } + + dataBinding.SetWidget (bindable_component); + dataBinding.Check (); + base.AddCore (dataBinding); + } + + protected override void ClearCore() { + base.ClearCore (); + } + + protected override void RemoveCore (Binding dataBinding) { + if (dataBinding == null) + throw new ArgumentNullException ("dataBinding"); + + base.RemoveCore (dataBinding); + } + #endregion // Protected Instance Methods + } +} + diff --git a/source/ShiftUI/Internal/ControlEventArgs.cs b/source/ShiftUI/Internal/ControlEventArgs.cs new file mode 100644 index 0000000..17eb992 --- /dev/null +++ b/source/ShiftUI/Internal/ControlEventArgs.cs @@ -0,0 +1,49 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE +using System; + +namespace ShiftUI { + public class WidgetEventArgs : EventArgs { + private Widget control; + + #region Public Constructors + public WidgetEventArgs(Widget control) { + this.control=control; + } + #endregion // Public Constructors + + #region Public Instance Properties + public Widget Widget { + get { + return this.control; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Internal/ControlEventHandler.cs b/source/ShiftUI/Internal/ControlEventHandler.cs new file mode 100644 index 0000000..faed044 --- /dev/null +++ b/source/ShiftUI/Internal/ControlEventHandler.cs @@ -0,0 +1,32 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +namespace ShiftUI { + public delegate void WidgetEventHandler (object sender, WidgetEventArgs e); +} diff --git a/source/ShiftUI/Internal/ControlHandler.cs b/source/ShiftUI/Internal/ControlHandler.cs new file mode 100644 index 0000000..08be9bd --- /dev/null +++ b/source/ShiftUI/Internal/ControlHandler.cs @@ -0,0 +1,229 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Geoff Norton +// +// + +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace ShiftUI.CarbonInternal { + internal class WidgetHandler : EventHandlerBase, IEventHandler { + internal const uint kEventWidgetInitialize = 1000; + internal const uint kEventWidgetDispose = 1001; + internal const uint kEventWidgetGetOptimalBounds = 1003; + internal const uint kEventWidgetDefInitialize = kEventWidgetInitialize; + internal const uint kEventWidgetDefDispose = kEventWidgetDispose; + internal const uint kEventWidgetHit = 1; + internal const uint kEventWidgetsimulateHit = 2; + internal const uint kEventWidgetHitTest = 3; + internal const uint kEventWidgetDraw = 4; + internal const uint kEventWidgetApplyBackground = 5; + internal const uint kEventWidgetApplyTextColor = 6; + internal const uint kEventWidgetsetFocusPart = 7; + internal const uint kEventWidgetGetFocusPart = 8; + internal const uint kEventWidgetActivate = 9; + internal const uint kEventWidgetDeactivate = 10; + internal const uint kEventWidgetsetCursor = 11; + internal const uint kEventWidgetContextualMenuClick = 12; + internal const uint kEventWidgetClick = 13; + internal const uint kEventWidgetGetNextFocusCandidate = 14; + internal const uint kEventWidgetGetAutoToggleValue = 15; + internal const uint kEventWidgetInterceptSubviewClick = 16; + internal const uint kEventWidgetGetClickActivation = 17; + internal const uint kEventWidgetDragEnter = 18; + internal const uint kEventWidgetDragWithin = 19; + internal const uint kEventWidgetDragLeave = 20; + internal const uint kEventWidgetDragReceive = 21; + internal const uint kEventWidgetInvalidateForSizeChange = 22; + internal const uint kEventWidgetTrackingAreaEntered = 23; + internal const uint kEventWidgetTrackingAreaExited = 24; + internal const uint kEventWidgetTrack = 51; + internal const uint kEventWidgetGetScrollToHereStartPoint = 52; + internal const uint kEventWidgetGetIndicatorDragConstraint = 53; + internal const uint kEventWidgetIndicatorMoved = 54; + internal const uint kEventWidgetGhostingFinished = 55; + internal const uint kEventWidgetGetActionProcPart = 56; + internal const uint kEventWidgetGetPartRegion = 101; + internal const uint kEventWidgetGetPartBounds = 102; + internal const uint kEventWidgetsetData = 103; + internal const uint kEventWidgetGetData = 104; + internal const uint kEventWidgetGetSizeConstraints= 105; + internal const uint kEventWidgetGetFrameMetrics = 106; + internal const uint kEventWidgetValueFieldChanged = 151; + internal const uint kEventWidgetAddedSubWidget = 152; + internal const uint kEventWidgetRemovingSubWidget = 153; + internal const uint kEventWidgetBoundsChanged = 154; + internal const uint kEventWidgetVisibilityChanged = 157; + internal const uint kEventWidgetTitleChanged = 158; + internal const uint kEventWidgetOwningWindowChanged = 159; + internal const uint kEventWidgetHiliteChanged = 160; + internal const uint kEventWidgetEnabledStateChanged = 161; + internal const uint kEventWidgetLayoutInfoChanged = 162; + internal const uint kEventWidgetArbitraryMessage = 201; + + internal const uint kEventParamCGContextRef = 1668183160; + internal const uint kEventParamDirectObject = 757935405; + internal const uint kEventParamWidgetPart = 1668313716; + internal const uint kEventParamWidgetLikesDrag = 1668047975; + internal const uint kEventParamRgnHandle = 1919381096; + internal const uint typeWidgetRef = 1668575852; + internal const uint typeCGContextRef = 1668183160; + internal const uint typeQDPoint = 1363439732; + internal const uint typeQDRgnHandle = 1919381096; + internal const uint typeWidgetPartCode = 1668313716; + internal const uint typeBoolean = 1651470188; + + internal WidgetHandler (XplatUICarbon driver) : base (driver) {} + + public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) { + Hwnd hwnd; + bool client; + + GetEventParameter (eventref, kEventParamDirectObject, typeWidgetRef, IntPtr.Zero, (uint) Marshal.SizeOf (typeof (IntPtr)), IntPtr.Zero, ref handle); + hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd == null) + return false; + + msg.hwnd = hwnd.Handle; + client = (hwnd.ClientWindow == handle ? true : false); + + switch (kind) { + case kEventWidgetDraw: { + IntPtr rgn = IntPtr.Zero; + HIRect bounds = new HIRect (); + + GetEventParameter (eventref, kEventParamRgnHandle, typeQDRgnHandle, IntPtr.Zero, (uint) Marshal.SizeOf (typeof (IntPtr)), IntPtr.Zero, ref rgn); + + if (rgn != IntPtr.Zero) { + Rect rbounds = new Rect (); + + GetRegionBounds (rgn, ref rbounds); + + bounds.origin.x = rbounds.left; + bounds.origin.y = rbounds.top; + bounds.size.width = rbounds.right - rbounds.left; + bounds.size.height = rbounds.bottom - rbounds.top; + } else { + HIViewGetBounds (handle, ref bounds); + } + + if (!hwnd.visible) { + if (client) { + hwnd.expose_pending = false; + } else { + hwnd.nc_expose_pending = false; + } + return false; + } + + if (!client) { + DrawBorders (hwnd); + } + + Driver.AddExpose (hwnd, client, bounds); + + return true; + } + case kEventWidgetVisibilityChanged: { + if (client) { + msg.message = Msg.WM_SHOWWINDOW; + msg.lParam = (IntPtr) 0; + msg.wParam = (HIViewIsVisible (handle) ? (IntPtr)1 : (IntPtr)0); + return true; + } + return false; + } + case kEventWidgetBoundsChanged: { + HIRect view_frame = new HIRect (); + + HIViewGetFrame (handle, ref view_frame); + if (!client) { + hwnd.X = (int) view_frame.origin.x; + hwnd.Y = (int) view_frame.origin.y; + hwnd.Width = (int) view_frame.size.width; + hwnd.Height = (int) view_frame.size.height; + Driver.PerformNCCalc (hwnd); + } + + msg.message = Msg.WM_WINDOWPOSCHANGED; + msg.hwnd = hwnd.Handle; + + return true; + } + case kEventWidgetGetFocusPart: { + short pcode = 0; + SetEventParameter (eventref, kEventParamWidgetPart, typeWidgetPartCode, (uint)Marshal.SizeOf (typeof (short)), ref pcode); + return false; + } + case kEventWidgetDragEnter: + case kEventWidgetDragWithin: + case kEventWidgetDragLeave: + case kEventWidgetDragReceive: + return Dnd.HandleEvent (callref, eventref, handle, kind, ref msg); + } + return false; + } + + private void DrawBorders (Hwnd hwnd) { + switch (hwnd.border_style) { + case FormBorderStyle.Fixed3D: { + Graphics g; + + g = Graphics.FromHwnd(hwnd.whole_window); + if (hwnd.border_static) + WidgetPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.SunkenOuter); + else + WidgetPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.Sunken); + g.Dispose(); + break; + } + + case FormBorderStyle.FixedSingle: { + Graphics g; + + g = Graphics.FromHwnd(hwnd.whole_window); + WidgetPaint.DrawBorder(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Color.Black, ButtonBorderStyle.Solid); + g.Dispose(); + break; + } + } + } + + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int GetRegionBounds (IntPtr rgnhandle, ref Rect region); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref IntPtr data); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int SetEventParameter (IntPtr eventref, uint name, uint type, uint size, ref short data); + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int HIViewGetBounds (IntPtr handle, ref HIRect rect); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int HIViewGetFrame (IntPtr handle, ref HIRect rect); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static bool HIViewIsVisible (IntPtr vHnd); + } +} diff --git a/source/ShiftUI/Internal/ControlPaint.cs b/source/ShiftUI/Internal/ControlPaint.cs new file mode 100644 index 0000000..d469f51 --- /dev/null +++ b/source/ShiftUI/Internal/ControlPaint.cs @@ -0,0 +1,495 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// NOT COMPLETE + +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System; + +namespace ShiftUI { + public sealed class WidgetPaint { + #region Local Variables + static int RGBMax=255; + static int HLSMax=255; + #endregion // Local Variables + + #region Private Enumerations + + + #region Constructor + // Prevent a public constructor from being created + private WidgetPaint() { + } + #endregion // Constructor + + + #endregion // Private Enumerations + + #region Helpers + internal static void Color2HBS(Color color, out int h, out int l, out int s) { + int r; + int g; + int b; + int cMax; + int cMin; + int rDelta; + int gDelta; + int bDelta; + + r=color.R; + g=color.G; + b=color.B; + + cMax = Math.Max(Math.Max(r, g), b); + cMin = Math.Min(Math.Min(r, g), b); + + l = (((cMax+cMin)*HLSMax)+RGBMax)/(2*RGBMax); + + if (cMax==cMin) { // Achromatic + h=0; // h undefined + s=0; + return; + } + + /* saturation */ + if (l<=(HLSMax/2)) { + s=(((cMax-cMin)*HLSMax)+((cMax+cMin)/2))/(cMax+cMin); + } else { + s=(((cMax-cMin)*HLSMax)+((2*RGBMax-cMax-cMin)/2))/(2*RGBMax-cMax-cMin); + } + + /* hue */ + rDelta=(((cMax-r)*(HLSMax/6))+((cMax-cMin)/2))/(cMax-cMin); + gDelta=(((cMax-g)*(HLSMax/6))+((cMax-cMin)/2))/(cMax-cMin); + bDelta=(((cMax-b)*(HLSMax/6))+((cMax-cMin)/2))/(cMax-cMin); + + if (r == cMax) { + h=bDelta - gDelta; + } else if (g == cMax) { + h=(HLSMax/3) + rDelta - bDelta; + } else { /* B == cMax */ + h=((2*HLSMax)/3) + gDelta - rDelta; + } + + if (h<0) { + h+=HLSMax; + } + + if (h>HLSMax) { + h-=HLSMax; + } + } + + private static int HueToRGB(int n1, int n2, int hue) { + if (hue<0) { + hue+=HLSMax; + } + + if (hue>HLSMax) { + hue -= HLSMax; + } + + /* return r,g, or b value from this tridrant */ + if (hue<(HLSMax/6)) { + return(n1+(((n2-n1)*hue+(HLSMax/12))/(HLSMax/6))); + } + + if (hue<(HLSMax/2)) { + return(n2); + } + + if (hue<((HLSMax*2)/3)) { + return(n1+(((n2-n1)*(((HLSMax*2)/3)-hue)+(HLSMax/12))/(HLSMax/6))); + } else { + return(n1); + } + } + + internal static Color HBS2Color(int hue, int lum, int sat) { + int R; + int G; + int B; + int Magic1; + int Magic2; + + if (sat == 0) { /* Achromatic */ + R=G=B=(lum*RGBMax)/HLSMax; + // FIXME : Should throw exception if hue!=0 + } else { + if (lum<=(HLSMax/2)) { + Magic2=(lum*(HLSMax+sat)+(HLSMax/2))/HLSMax; + } else { + Magic2=sat+lum-((sat*lum)+(HLSMax/2))/HLSMax; + } + Magic1=2*lum-Magic2; + + R = Math.Min(255, (HueToRGB(Magic1,Magic2,hue+(HLSMax/3))*RGBMax+(HLSMax/2))/HLSMax); + G = Math.Min(255, (HueToRGB(Magic1,Magic2,hue)*RGBMax+(HLSMax/2))/HLSMax); + B = Math.Min(255, (HueToRGB(Magic1,Magic2,hue-(HLSMax/3))*RGBMax+(HLSMax/2))/HLSMax); + } + return (Color.FromArgb(R, G, B)); + } + #endregion // Helpers + + #region Public Static Properties + public static Color ContrastControlDark { + get { return(SystemColors.ControlDark); } + } + #endregion // Public Static Properties + + #region Public Static Methods + [MonoTODO ("Not implemented, will throw NotImplementedException")] + public static IntPtr CreateHBitmap16Bit (Bitmap bitmap, Color background) + { + throw new NotImplementedException (); + } + + [MonoTODO ("Not implemented, will throw NotImplementedException")] + public static IntPtr CreateHBitmapColorMask (Bitmap bitmap, IntPtr monochromeMask) + { + throw new NotImplementedException (); + } + + [MonoTODO ("Not implemented, will throw NotImplementedException")] + public static IntPtr CreateHBitmapTransparencyMask (Bitmap bitmap) + { + throw new NotImplementedException (); + } + + public static Color Light(Color baseColor) { + return Light(baseColor, 0.5f); + } + + public static Color Light (Color baseColor, float percOfLightLight) + { + if (baseColor.ToArgb () == ThemeEngine.Current.ColorControl.ToArgb ()) { + int r_sub, g_sub, b_sub; + Color color; + + if (percOfLightLight <= 0f) + return ThemeEngine.Current.ColorControlLight; + + if (percOfLightLight == 1.0f) + return ThemeEngine.Current.ColorControlLightLight; + + r_sub = ThemeEngine.Current.ColorControlLightLight.R - ThemeEngine.Current.ColorControlLight.R; + g_sub = ThemeEngine.Current.ColorControlLightLight.G - ThemeEngine.Current.ColorControlLight.G; + b_sub = ThemeEngine.Current.ColorControlLightLight.B - ThemeEngine.Current.ColorControlLight.B; + + color = Color.FromArgb (ThemeEngine.Current.ColorControlLight.A, + (int) (ThemeEngine.Current.ColorControlLight.R + (r_sub * percOfLightLight)), + (int) (ThemeEngine.Current.ColorControlLight.G + (g_sub * percOfLightLight)), + (int) (ThemeEngine.Current.ColorControlLight.B + (b_sub * percOfLightLight))); + return color; + } + + int H, I, S; + + WidgetPaint.Color2HBS (baseColor, out H, out I, out S); + int NewIntensity = Math.Min (255, I + (int) ((255 - I) * 0.5f * percOfLightLight)); + + return WidgetPaint.HBS2Color (H, NewIntensity, S); + } + + public static Color LightLight (Color baseColor) + { + return Light(baseColor, 1.0f); + } + + public static Color Dark (Color baseColor) + { + return Dark(baseColor, 0.5f); + } + + public static Color Dark (Color baseColor, float percOfDarkDark) + { + if (baseColor.ToArgb () == ThemeEngine.Current.ColorControl.ToArgb ()) { + + int r_sub, g_sub, b_sub; + Color color; + + if (percOfDarkDark <= 0f) + return ThemeEngine.Current.ColorControlDark; + + if (percOfDarkDark == 1.0f) + return ThemeEngine.Current.ColorControlDarkDark; + + r_sub = ThemeEngine.Current.ColorControlDarkDark.R - ThemeEngine.Current.ColorControlDark.R; + g_sub = ThemeEngine.Current.ColorControlDarkDark.G - ThemeEngine.Current.ColorControlDark.G; + b_sub = ThemeEngine.Current.ColorControlDarkDark.B - ThemeEngine.Current.ColorControlDark.B; + + color = Color.FromArgb (ThemeEngine.Current.ColorControlDark.A, + (int) (ThemeEngine.Current.ColorControlDark.R + (r_sub * percOfDarkDark)), + (int) (ThemeEngine.Current.ColorControlDark.G + (g_sub * percOfDarkDark)), + (int) (ThemeEngine.Current.ColorControlDark.B + (b_sub * percOfDarkDark))); + return color; + } + + int H, I, S; + + WidgetPaint.Color2HBS(baseColor, out H, out I, out S); + int PreIntensity = Math.Max (0, I - (int) (I * 0.333f)); + int NewIntensity = Math.Max (0, PreIntensity - (int) (PreIntensity * percOfDarkDark)); + return WidgetPaint.HBS2Color(H, NewIntensity, S); + } + + public static Color DarkDark (Color baseColor) + { + return Dark(baseColor, 1.0f); + } + + public static void DrawBorder (Graphics graphics, Rectangle bounds, Color color, ButtonBorderStyle style) + { + int line_width_top_left = 1; + int line_width_bottom_right = 1; + + if (style == ButtonBorderStyle.Inset) + line_width_top_left = 2; + if (style == ButtonBorderStyle.Outset) { + line_width_bottom_right = 2; + line_width_top_left = 2; + } + + DrawBorder(graphics, bounds, color, line_width_top_left, style, color, line_width_top_left, style, color, line_width_bottom_right, style, color, line_width_bottom_right, style); + } + + internal static void DrawBorder (Graphics graphics, RectangleF bounds, Color color, ButtonBorderStyle style) + { + int line_width_top_left = 1; + int line_width_bottom_right = 1; + + if (style == ButtonBorderStyle.Inset) + line_width_top_left = 2; + if (style == ButtonBorderStyle.Outset) { + line_width_bottom_right = 2; + line_width_top_left = 2; + } + + ThemeEngine.Current.CPDrawBorder (graphics, bounds, color, line_width_top_left, style, color, line_width_top_left, style, color, line_width_bottom_right, style, color, line_width_bottom_right, style); + } + + public static void DrawBorder( Graphics graphics, Rectangle bounds, Color leftColor, int leftWidth, + ButtonBorderStyle leftStyle, Color topColor, int topWidth, ButtonBorderStyle topStyle, + Color rightColor, int rightWidth, ButtonBorderStyle rightStyle, Color bottomColor, int bottomWidth, + ButtonBorderStyle bottomStyle) { + + ThemeEngine.Current.CPDrawBorder (graphics, bounds, leftColor, leftWidth, + leftStyle, topColor, topWidth, topStyle, rightColor, rightWidth, rightStyle, + bottomColor, bottomWidth, bottomStyle); + } + + + public static void DrawBorder3D(Graphics graphics, Rectangle rectangle) { + DrawBorder3D(graphics, rectangle, Border3DStyle.Etched, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom); + } + + public static void DrawBorder3D(Graphics graphics, Rectangle rectangle, Border3DStyle style) { + DrawBorder3D(graphics, rectangle, style, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom); + } + + public static void DrawBorder3D(Graphics graphics, int x, int y, int width, int height) { + DrawBorder3D(graphics, new Rectangle(x, y, width, height), Border3DStyle.Etched, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom); + } + + public static void DrawBorder3D(Graphics graphics, int x, int y, int width, int height, Border3DStyle style) { + DrawBorder3D(graphics, new Rectangle(x, y, width, height), style, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom); + } + + public static void DrawBorder3D( Graphics graphics, int x, int y, int width, int height, Border3DStyle style,Border3DSide sides) { + DrawBorder3D( graphics, new Rectangle(x, y, width, height), style, sides); + } + + public static void DrawBorder3D( Graphics graphics, Rectangle rectangle, Border3DStyle style, Border3DSide sides) { + + ThemeEngine.Current.CPDrawBorder3D (graphics, rectangle, style, sides); + } + + public static void DrawButton( Graphics graphics, int x, int y, int width, int height, ButtonState state) { + DrawButton(graphics, new Rectangle(x, y, width, height), state); + } + + public static void DrawButton( Graphics graphics, Rectangle rectangle, ButtonState state) { + + ThemeEngine.Current.CPDrawButton (graphics, rectangle, state); + } + + + public static void DrawCaptionButton(Graphics graphics, int x, int y, int width, int height, CaptionButton button, ButtonState state) { + DrawCaptionButton(graphics, new Rectangle(x, y, width, height), button, state); + } + + public static void DrawCaptionButton(Graphics graphics, Rectangle rectangle, CaptionButton button, ButtonState state) { + + ThemeEngine.Current.CPDrawCaptionButton (graphics, rectangle, button, state); + } + + public static void DrawCheckBox(Graphics graphics, int x, int y, int width, int height, ButtonState state) { + DrawCheckBox(graphics, new Rectangle(x, y, width, height), state); + } + + public static void DrawCheckBox(Graphics graphics, Rectangle rectangle, ButtonState state) { + + ThemeEngine.Current.CPDrawCheckBox (graphics, rectangle, state); + } + + public static void DrawComboButton(Graphics graphics, Rectangle rectangle, ButtonState state) { + + ThemeEngine.Current.CPDrawComboButton (graphics, rectangle, state); + } + + public static void DrawComboButton(Graphics graphics, int x, int y, int width, int height, ButtonState state) { + DrawComboButton(graphics, new Rectangle(x, y, width, height), state); + } + + public static void DrawContainerGrabHandle(Graphics graphics, Rectangle bounds) { + + ThemeEngine.Current.CPDrawContainerGrabHandle (graphics, bounds); + } + + public static void DrawFocusRectangle( Graphics graphics, Rectangle rectangle) { + DrawFocusRectangle(graphics, rectangle, SystemColors.Control, SystemColors.ControlText); + } + + public static void DrawFocusRectangle( Graphics graphics, Rectangle rectangle, Color foreColor, Color backColor) { + + ThemeEngine.Current.CPDrawFocusRectangle (graphics, rectangle, foreColor, backColor); + } + + public static void DrawGrabHandle(Graphics graphics, Rectangle rectangle, bool primary, bool enabled) { + + ThemeEngine.Current.CPDrawGrabHandle (graphics, rectangle, primary, enabled); + } + + public static void DrawGrid(Graphics graphics, Rectangle area, Size pixelsBetweenDots, Color backColor) { + + ThemeEngine.Current.CPDrawGrid (graphics, area, pixelsBetweenDots, backColor); + } + + public static void DrawImageDisabled(Graphics graphics, Image image, int x, int y, Color background) { + + ThemeEngine.Current.CPDrawImageDisabled (graphics, image, x, y, background); + } + + public static void DrawLockedFrame(Graphics graphics, Rectangle rectangle, bool primary) { + + ThemeEngine.Current.CPDrawLockedFrame (graphics, rectangle, primary); + } + + public static void DrawMenuGlyph(Graphics graphics, Rectangle rectangle, MenuGlyph glyph) { + + ThemeEngine.Current.CPDrawMenuGlyph (graphics, rectangle, glyph, ThemeEngine.Current.ColorMenuText, Color.Empty); + } + + public static void DrawMenuGlyph (Graphics graphics, Rectangle rectangle, MenuGlyph glyph, Color foreColor, Color backColor) + { + ThemeEngine.Current.CPDrawMenuGlyph (graphics, rectangle, glyph, foreColor, backColor); + } + + public static void DrawMenuGlyph(Graphics graphics, int x, int y, int width, int height, MenuGlyph glyph) { + DrawMenuGlyph(graphics, new Rectangle(x, y, width, height), glyph); + } + + public static void DrawMenuGlyph (Graphics graphics, int x, int y, int width, int height, MenuGlyph glyph, Color foreColor, Color backColor) + { + DrawMenuGlyph (graphics, new Rectangle (x, y, width, height), glyph, foreColor, backColor); + } + + public static void DrawMixedCheckBox(Graphics graphics, Rectangle rectangle, ButtonState state) { + ThemeEngine.Current.CPDrawMixedCheckBox (graphics, rectangle, state); + } + + public static void DrawMixedCheckBox(Graphics graphics, int x, int y, int width, int height, ButtonState state) { + DrawMixedCheckBox(graphics, new Rectangle(x, y, width, height), state); + } + + + public static void DrawRadioButton(Graphics graphics, int x, int y, int width, int height, ButtonState state) { + DrawRadioButton(graphics, new Rectangle(x, y, width, height), state); + } + + public static void DrawRadioButton(Graphics graphics, Rectangle rectangle, ButtonState state) { + + ThemeEngine.Current.CPDrawRadioButton (graphics, rectangle, state); + } + + public static void DrawReversibleFrame(Rectangle rectangle, Color backColor, FrameStyle style) { + XplatUI.DrawReversibleFrame (rectangle, backColor, style); + } + + public static void DrawReversibleLine(Point start, Point end, Color backColor) { + XplatUI.DrawReversibleLine (start, end, backColor); + } + + public static void FillReversibleRectangle(Rectangle rectangle, Color backColor) { + XplatUI.FillReversibleRectangle (rectangle, backColor); + } + + public static void DrawScrollButton (Graphics graphics, int x, int y, int width, int height, ScrollButton button, ButtonState state) { + ThemeEngine.Current.CPDrawScrollButton (graphics, new Rectangle(x, y, width, height), button, state); + } + + public static void DrawScrollButton (Graphics graphics, Rectangle rectangle, ScrollButton button, ButtonState state) { + ThemeEngine.Current.CPDrawScrollButton (graphics, rectangle, button, state); + } + + [MonoTODO ("Stub, does nothing")] + private static bool DSFNotImpl = false; + public static void DrawSelectionFrame(Graphics graphics, bool active, Rectangle outsideRect, Rectangle insideRect, Color backColor) { + if (!DSFNotImpl) { + DSFNotImpl = true; + Console.WriteLine("NOT IMPLEMENTED: DrawSelectionFrame(Graphics graphics, bool active, Rectangle outsideRect, Rectangle insideRect, Color backColor)"); + } + //throw new NotImplementedException(); + } + + public static void DrawSizeGrip (Graphics graphics, Color backColor, Rectangle bounds) + { + ThemeEngine.Current.CPDrawSizeGrip (graphics, backColor, bounds); + } + + public static void DrawSizeGrip(Graphics graphics, Color backColor, int x, int y, int width, int height) { + DrawSizeGrip(graphics, backColor, new Rectangle(x, y, width, height)); + } + + public static void DrawStringDisabled(Graphics graphics, string s, Font font, Color color, RectangleF layoutRectangle, StringFormat format) { + + ThemeEngine.Current.CPDrawStringDisabled (graphics, s, font, color, layoutRectangle, format); + } + + public static void DrawStringDisabled (IDeviceContext dc, string s, Font font, Color color, Rectangle layoutRectangle, TextFormatFlags format) + { + ThemeEngine.Current.CPDrawStringDisabled (dc, s, font, color, layoutRectangle, format); + } + + public static void DrawVisualStyleBorder (Graphics graphics, Rectangle bounds) + { + ThemeEngine.Current.CPDrawVisualStyleBorder (graphics, bounds); + } + #endregion // Public Static Methods + } +} diff --git a/source/ShiftUI/Internal/CurrencyManager.cs b/source/ShiftUI/Internal/CurrencyManager.cs new file mode 100644 index 0000000..9f68fd4 --- /dev/null +++ b/source/ShiftUI/Internal/CurrencyManager.cs @@ -0,0 +1,453 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// Ivan N. Zlatev (contact@i-nz.net) +// + +using System; +using System.Data; +using System.Reflection; +using System.Collections; +using System.ComponentModel; + +namespace ShiftUI { + public class CurrencyManager : BindingManagerBase { + + protected int listposition; + protected Type finalType; + + private IList list; + private bool binding_suspended; + + private object data_source; + + bool editing; + + internal CurrencyManager () + { + } + + internal CurrencyManager (object data_source) + { + SetDataSource (data_source); + } + + public IList List { + get { return list; } + } + + public override object Current { + get { + if (listposition == -1 || listposition >= list.Count) { + // Console.WriteLine ("throwing exception from here"); + // Console.WriteLine (Environment.StackTrace); + throw new IndexOutOfRangeException ("list position"); + } + return list [listposition]; + } + } + + public override int Count { + get { return list.Count; } + } + + public override int Position { + get { + return listposition; + } + set { + if (value < 0) + value = 0; + if (value >= list.Count) + value = list.Count - 1; + if (listposition == value) + return; + + if (listposition != -1) + EndCurrentEdit (); + + listposition = value; + OnCurrentChanged (EventArgs.Empty); + OnPositionChanged (EventArgs.Empty); + } + } + + internal void SetDataSource (object data_source) + { + if (this.data_source is IBindingList) + ((IBindingList)this.data_source).ListChanged -= new ListChangedEventHandler (ListChangedHandler); + + if (data_source is IListSource) + data_source = ((IListSource)data_source).GetList(); + + this.data_source = data_source; + if (data_source != null) + this.finalType = data_source.GetType(); + + listposition = -1; + if (this.data_source is IBindingList) + ((IBindingList)this.data_source).ListChanged += new ListChangedEventHandler (ListChangedHandler); + + list = (IList)data_source; + + // XXX this is wrong. MS invokes OnItemChanged directly, which seems to call PushData. + ListChangedHandler (null, new ListChangedEventArgs (ListChangedType.Reset, -1)); + } + + public override PropertyDescriptorCollection GetItemProperties () + { + return ListBindingHelper.GetListItemProperties (list); + } + + public override void RemoveAt (int index) + { + list.RemoveAt (index); + } + + public override void SuspendBinding () + { + binding_suspended = true; + } + + public override void ResumeBinding () + { + binding_suspended = false; + } + + internal override bool IsSuspended { + get { + // Always return true if we don't have items + if (Count == 0) + return true; + + return binding_suspended; + } + } + + internal bool AllowNew { + get { + if (list is IBindingList) + return ((IBindingList)list).AllowNew; + + if (list.IsReadOnly) + return false; + + return false; + } + } + + internal bool AllowRemove { + get { + if (list.IsReadOnly) + return false; + + if (list is IBindingList) + return ((IBindingList)list).AllowRemove; + + return false; + } + } + + internal bool AllowEdit { + get { + if (list is IBindingList) + return ((IBindingList)list).AllowEdit; + + return false; + } + } + + public override void AddNew () + { + IBindingList ibl = list as IBindingList; + + if (ibl == null) + throw new NotSupportedException (); + + ibl.AddNew (); + + bool validate = (Position != (list.Count - 1)); + ChangeRecordState (list.Count - 1, validate, validate, true, true); + } + + + void BeginEdit () + { + IEditableObject editable = Current as IEditableObject; + + if (editable != null) { + try { + editable.BeginEdit (); + editing = true; + } + catch { + /* swallow exceptions in IEditableObject.BeginEdit () */ + } + } + } + + public override void CancelCurrentEdit () + { + if (listposition == -1) + return; + + IEditableObject editable = Current as IEditableObject; + + if (editable != null) { + editing = false; + editable.CancelEdit (); + OnItemChanged (new ItemChangedEventArgs (Position)); + } + if (list is ICancelAddNew) + ((ICancelAddNew)list).CancelNew (listposition); + } + + public override void EndCurrentEdit () + { + if (listposition == -1) + return; + + IEditableObject editable = Current as IEditableObject; + + if (editable != null) { + editing = false; + editable.EndEdit (); + } + + if (list is ICancelAddNew) + ((ICancelAddNew)list).EndNew (listposition); + } + + public void Refresh () + { + ListChangedHandler (null, new ListChangedEventArgs (ListChangedType.Reset, -1)); + } + + protected void CheckEmpty () + { + if (list == null || list.Count < 1) + throw new Exception ("List is empty."); + + } + + protected internal override void OnCurrentChanged (EventArgs e) + { + if (onCurrentChangedHandler != null) { + onCurrentChangedHandler (this, e); + } + + // don't call OnCurrentItemChanged here, as it can be overridden + if (onCurrentItemChangedHandler != null) { + onCurrentItemChangedHandler (this, e); + } + + } + + protected override void OnCurrentItemChanged (EventArgs e) + { + if (onCurrentItemChangedHandler != null) { + onCurrentItemChangedHandler (this, e); + } + } + + protected virtual void OnItemChanged (ItemChangedEventArgs e) + { + if (ItemChanged != null) + ItemChanged (this, e); + + transfering_data = true; + PushData (); + transfering_data = false; + } + + void OnListChanged (ListChangedEventArgs args) + { + if (ListChanged != null) + ListChanged (this, args); + } + + protected virtual void OnPositionChanged (EventArgs e) + { + if (onPositionChangedHandler != null) + onPositionChangedHandler (this, e); + } + + protected internal override string GetListName (ArrayList listAccessors) + { + if (list is ITypedList) { + PropertyDescriptor [] pds = null; + if (listAccessors != null) { + pds = new PropertyDescriptor [listAccessors.Count]; + listAccessors.CopyTo (pds, 0); + } + return ((ITypedList) list).GetListName (pds); + } + else if (finalType != null) { + return finalType.Name; + } + return String.Empty; + } + + protected override void UpdateIsBinding () + { + UpdateItem (); + + foreach (Binding binding in Bindings) + binding.UpdateIsBinding (); + + ChangeRecordState (listposition, false, false, true, false); + + OnItemChanged (new ItemChangedEventArgs (-1)); + } + + private void ChangeRecordState (int newPosition, + bool validating, + bool endCurrentEdit, + bool firePositionChanged, + bool pullData) + { + if (endCurrentEdit) + EndCurrentEdit (); + + int old_index = listposition; + + listposition = newPosition; + + if (listposition >= list.Count) + listposition = list.Count - 1; + + if (old_index != -1 && listposition != -1) + OnCurrentChanged (EventArgs.Empty); + + if (firePositionChanged) + OnPositionChanged (EventArgs.Empty); + } + + private void UpdateItem () + { + // Probably should be validating or something here + if (!transfering_data && listposition == -1 && list.Count > 0) { + listposition = 0; + BeginEdit (); + } + } + + internal object this [int index] { + get { return list [index]; } + } + + private PropertyDescriptorCollection GetBrowsableProperties (Type t) + { + Attribute [] att = new System.Attribute [1]; + att [0] = new BrowsableAttribute (true); + return TypeDescriptor.GetProperties (t, att); + } + + protected void OnMetaDataChanged (EventArgs e) + { + if (MetaDataChanged != null) + MetaDataChanged (this, e); + } + + private void ListChangedHandler (object sender, ListChangedEventArgs e) + { + switch (e.ListChangedType) { + case ListChangedType.PropertyDescriptorAdded: + case ListChangedType.PropertyDescriptorDeleted: + case ListChangedType.PropertyDescriptorChanged: + OnMetaDataChanged (EventArgs.Empty); + OnListChanged (e); + break; + case ListChangedType.ItemDeleted: + if (list.Count == 0) { + /* the last row was deleted */ + listposition = -1; + UpdateIsBinding (); + + OnPositionChanged (EventArgs.Empty); + OnCurrentChanged (EventArgs.Empty); + } + else if (e.NewIndex <= listposition) { + /* the deleted row was either the current one, or one earlier in the list. + Update the index and emit PositionChanged, CurrentChanged, and ItemChanged. */ + // FIXME: this looks wrong, shouldn't it be (listposition - 1) instead of e.NewIndex ? + ChangeRecordState (e.NewIndex, + false, false, e.NewIndex != listposition, false); + } + else { + /* the deleted row was after the current one, so we don't + need to update bound Widgets for Position/Current changed */ + } + + OnItemChanged (new ItemChangedEventArgs (-1)); + OnListChanged (e); + break; + case ListChangedType.ItemAdded: + if (list.Count == 1) { + /* it's the first one we've added */ + ChangeRecordState (e.NewIndex, + false, false, true, false); + + OnItemChanged (new ItemChangedEventArgs (-1)); + OnListChanged (e); + } + else { + if (e.NewIndex <= listposition) { + ChangeRecordState (listposition + 1, + false, false, false, false); + OnItemChanged (new ItemChangedEventArgs (-1)); + OnListChanged (e); + OnPositionChanged (EventArgs.Empty); + } + else { + OnItemChanged (new ItemChangedEventArgs (-1)); + OnListChanged (e); + } + } + + break; + case ListChangedType.ItemChanged: + if (editing) { + if (e.NewIndex == listposition) + OnCurrentItemChanged (EventArgs.Empty); + OnItemChanged (new ItemChangedEventArgs (e.NewIndex)); + } + OnListChanged (e); + break; + case ListChangedType.Reset: + PushData(); + UpdateIsBinding(); + OnListChanged (e); + break; + default: + OnListChanged (e); + break; + } + } + + public event ListChangedEventHandler ListChanged; + public event ItemChangedEventHandler ItemChanged; + public event EventHandler MetaDataChanged; + } +} + diff --git a/source/ShiftUI/Internal/Cursor.cs b/source/ShiftUI/Internal/Cursor.cs new file mode 100644 index 0000000..1b3e0f6 --- /dev/null +++ b/source/ShiftUI/Internal/Cursor.cs @@ -0,0 +1,245 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2008 Novell, Inc. +// +// Authors: +// Geoff Norton (gnorton@novell.com) +// +// + + +using System; +using System.Drawing; +using ShiftUI; +using System.Runtime.InteropServices; + +namespace ShiftUI.CarbonInternal { + internal class Cursor { + internal static CarbonCursor defcur = new CarbonCursor (StdCursor.Default); + + internal static Bitmap DefineStdCursorBitmap (StdCursor id) { + // FIXME + return new Bitmap (16, 16); + } + internal static IntPtr DefineCursor (Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) { + CarbonCursor cc = new CarbonCursor (bitmap, mask, cursor_pixel, mask_pixel, xHotSpot, yHotSpot); + + return (IntPtr) GCHandle.Alloc (cc); + } + internal static IntPtr DefineStdCursor (StdCursor id) { + CarbonCursor cc = new CarbonCursor (id); + + return (IntPtr) GCHandle.Alloc (cc); + } + internal static void SetCursor (IntPtr cursor) { + if (cursor == IntPtr.Zero) { + defcur.SetCursor (); + return; + } + + CarbonCursor cc = (CarbonCursor) ((GCHandle) cursor).Target; + + cc.SetCursor (); + } + } + + internal struct CarbonCursor { + private Bitmap bmp; + private Bitmap mask; + private Color cursor_color; + private Color mask_color; + private int hot_x; + private int hot_y; + private StdCursor id; + private bool standard; + + public CarbonCursor (Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) { + this.id = StdCursor.Default; + this.bmp = bitmap; + this.mask = mask; + this.cursor_color = cursor_pixel; + this.mask_color = mask_pixel; + this.hot_x = xHotSpot; + this.hot_y = yHotSpot; + standard = true; + } + + public CarbonCursor (StdCursor id) { + this.id = id; + this.bmp = null; + this.mask = null; + this.cursor_color = Color.Black; + this.mask_color = Color.Black; + this.hot_x = 0; + this.hot_y = 0; + standard = true; + } + + public StdCursor StdCursor { + get { + return id; + } + } + + public Bitmap Bitmap { + get { + return bmp; + } + } + + public Bitmap Mask { + get { + return mask; + } + } + + public Color CursorColor { + get { + return cursor_color; + } + } + + public Color MaskColor { + get { + return mask_color; + } + } + + public int HotSpotX { + get { + return hot_x; + } + } + + public int HotSpotY { + get { + return hot_y; + } + } + + public void SetCursor () { + if (standard) + SetStandardCursor (); + else + SetCustomCursor (); + } + + public void SetCustomCursor () { + throw new NotImplementedException ("We dont support custom cursors yet"); + } + + public void SetStandardCursor () { + switch (id) { + case StdCursor.AppStarting: + SetThemeCursor (ThemeCursor.kThemeSpinningCursor); + break; + case StdCursor.Arrow: + SetThemeCursor (ThemeCursor.kThemeArrowCursor); + break; + case StdCursor.Cross: + SetThemeCursor (ThemeCursor.kThemeCrossCursor); + break; + case StdCursor.Default: + SetThemeCursor (ThemeCursor.kThemeArrowCursor); + break; + case StdCursor.Hand: + SetThemeCursor (ThemeCursor.kThemeOpenHandCursor); + break; + case StdCursor.Help: + SetThemeCursor (ThemeCursor.kThemeArrowCursor); + break; + case StdCursor.HSplit: + SetThemeCursor (ThemeCursor.kThemeResizeLeftRightCursor); + break; + case StdCursor.IBeam: + SetThemeCursor (ThemeCursor.kThemeIBeamCursor); + break; + case StdCursor.No: + SetThemeCursor (ThemeCursor.kThemeNotAllowedCursor); + break; + case StdCursor.NoMove2D: + SetThemeCursor (ThemeCursor.kThemeNotAllowedCursor); + break; + case StdCursor.NoMoveHoriz: + SetThemeCursor (ThemeCursor.kThemeNotAllowedCursor); + break; + case StdCursor.NoMoveVert: + SetThemeCursor (ThemeCursor.kThemeNotAllowedCursor); + break; + case StdCursor.PanEast: + SetThemeCursor (ThemeCursor.kThemeResizeRightCursor); + break; + case StdCursor.PanNE: + SetThemeCursor (ThemeCursor.kThemeArrowCursor); + break; + case StdCursor.PanNorth: + SetThemeCursor (ThemeCursor.kThemeArrowCursor); + break; + case StdCursor.PanNW: + SetThemeCursor (ThemeCursor.kThemeArrowCursor); + break; + case StdCursor.PanSE: + SetThemeCursor (ThemeCursor.kThemeArrowCursor); + break; + case StdCursor.PanSouth: + SetThemeCursor (ThemeCursor.kThemeArrowCursor); + break; + case StdCursor.PanSW: + SetThemeCursor (ThemeCursor.kThemeArrowCursor); + break; + case StdCursor.PanWest: + SetThemeCursor (ThemeCursor.kThemeResizeLeftCursor); + break; + case StdCursor.SizeAll: + SetThemeCursor (ThemeCursor.kThemeResizeLeftRightCursor); + break; + case StdCursor.SizeNESW: + SetThemeCursor (ThemeCursor.kThemeArrowCursor); + break; + case StdCursor.SizeNS: + SetThemeCursor (ThemeCursor.kThemeArrowCursor); + break; + case StdCursor.SizeNWSE: + SetThemeCursor (ThemeCursor.kThemeArrowCursor); + break; + case StdCursor.SizeWE: + SetThemeCursor (ThemeCursor.kThemeArrowCursor); + break; + case StdCursor.UpArrow: + SetThemeCursor (ThemeCursor.kThemeArrowCursor); + break; + case StdCursor.VSplit: + SetThemeCursor (ThemeCursor.kThemeArrowCursor); + break; + case StdCursor.WaitCursor: + SetThemeCursor (ThemeCursor.kThemeSpinningCursor); + break; + default: + SetThemeCursor (ThemeCursor.kThemeArrowCursor); + break; + } + return; + } + + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int SetThemeCursor (ThemeCursor cursor); + + } +} diff --git a/source/ShiftUI/Internal/CursorConverter.cs b/source/ShiftUI/Internal/CursorConverter.cs new file mode 100644 index 0000000..d84b3d2 --- /dev/null +++ b/source/ShiftUI/Internal/CursorConverter.cs @@ -0,0 +1,126 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +using System; +using System.IO; +using System.Drawing; +using System.Drawing.Imaging; +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design.Serialization; +using System.Globalization; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; + +namespace ShiftUI +{ + public class CursorConverter : TypeConverter + { + public CursorConverter () + { + } + + public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof (byte [])) + return true; + return base.CanConvertFrom (context, sourceType); + } + + public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof (byte []) || destinationType == typeof (InstanceDescriptor)) + return true; + return base.CanConvertTo (context, destinationType); + } + + public override object ConvertFrom (ITypeDescriptorContext context, + CultureInfo culture, object value) + { + byte [] val = value as byte []; + if (val == null) + return base.ConvertFrom (context, culture, value); + + using (MemoryStream s = new MemoryStream (val)) { + return new Cursor (s); + } + } + + public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, + object value, Type destinationType) + { + if (destinationType == null) + throw new ArgumentNullException ("destinationType"); + + if (value == null && destinationType == typeof (string)) + return "(none)"; + + if ( !(value is Cursor)) + throw new ArgumentException("object must be of class Cursor", "value"); + + if (destinationType == typeof (byte [])) { + Cursor c; + SerializationInfo si; + + if (value == null) { + return new byte [0]; + } + + c = (Cursor)value; + + si = new SerializationInfo(typeof(Cursor), new FormatterConverter()); + ((ISerializable)c).GetObjectData(si, new StreamingContext(StreamingContextStates.Remoting)); + + return (byte[])si.GetValue("CursorData", typeof(byte[])); + } else if (destinationType == typeof (InstanceDescriptor)) { + PropertyInfo[] properties = typeof (Cursors).GetProperties (); + foreach (PropertyInfo propInfo in properties) { + if (propInfo.GetValue (null, null) == value) { + return new InstanceDescriptor (propInfo, null); + } + } + } + return base.ConvertTo (context, culture, value, destinationType); + } + + public override StandardValuesCollection GetStandardValues (ITypeDescriptorContext context) + { + PropertyInfo[] props = typeof (Cursors).GetProperties(); + + ArrayList vals = new ArrayList (); + + for (int i = 0; i < props.Length; i++) { + vals.Add (props [i].GetValue (null, null)); + } + return new StandardValuesCollection (vals); + } + + public override bool GetStandardValuesSupported (ITypeDescriptorContext context) + { + return true; + } + } +} diff --git a/source/ShiftUI/Internal/Cursors.cs b/source/ShiftUI/Internal/Cursors.cs new file mode 100644 index 0000000..2d43345 --- /dev/null +++ b/source/ShiftUI/Internal/Cursors.cs @@ -0,0 +1,365 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +// COMPLETE + +using ShiftUI; + +namespace ShiftUI { + public sealed class Cursors { + #region Local Variables + internal static Cursor app_starting; + internal static Cursor arrow; + internal static Cursor cross; + internal static Cursor def; + internal static Cursor hand; + internal static Cursor help; + internal static Cursor hsplit; + internal static Cursor ibeam; + internal static Cursor no; + internal static Cursor no_move_2d; + internal static Cursor no_move_horiz; + internal static Cursor no_move_vert; + internal static Cursor pan_east; + internal static Cursor pan_ne; + internal static Cursor pan_north; + internal static Cursor pan_nw; + internal static Cursor pan_se; + internal static Cursor pan_south; + internal static Cursor pan_sw; + internal static Cursor pan_west; + internal static Cursor size_all; + internal static Cursor size_nesw; + internal static Cursor size_ns; + internal static Cursor size_nwse; + internal static Cursor size_we; + internal static Cursor up_arrow; + internal static Cursor vsplit; + internal static Cursor wait_cursor; + #endregion // Local Variables + + #region Constructors + private Cursors() { + } + #endregion // Constructors + + #region Public Static Properties + public static Cursor AppStarting { + get { + if (app_starting == null) { + app_starting = new Cursor(StdCursor.AppStarting); + app_starting.name = "AppStarting"; + } + return app_starting; + } + } + + public static Cursor Arrow { + get { + if (arrow == null) { + arrow = new Cursor(StdCursor.Arrow); + arrow.name = "Arrow"; + } + return arrow; + } + } + + public static Cursor Cross { + get { + if (cross == null) { + cross = new Cursor(StdCursor.Cross); + cross.name = "Cross"; + } + return cross; + } + } + + public static Cursor Default { + get { + if (def == null) { + def = new Cursor(StdCursor.Default); + def.name = "Default"; + } + return def; + } + } + + public static Cursor Hand { + get { + if (hand == null) { + hand = new Cursor(StdCursor.Hand); + hand.name = "Hand"; + } + return hand; + } + } + + public static Cursor Help { + get { + if (help == null) { + help = new Cursor(StdCursor.Help); + help.name = "Help"; + } + return help; + } + } + + public static Cursor HSplit { + get { + if (hsplit == null) { + hsplit = new Cursor(global::ShiftUI.Properties.Resources.SplitterWE); + hsplit.name = "HSplit"; + } + return hsplit; + } + } + + public static Cursor IBeam { + get { + if (ibeam == null) { + ibeam = new Cursor(StdCursor.IBeam); + ibeam.name = "IBeam"; + } + return ibeam; + } + } + + public static Cursor No { + get { + if (no == null) { + no = new Cursor(StdCursor.No); + no.name = "No"; + } + return no; + } + } + + public static Cursor NoMove2D { + get { + if (no_move_2d == null) { + no_move_2d = new Cursor(StdCursor.NoMove2D); + no_move_2d.name = "NoMove2D"; + } + return no_move_2d; + } + } + + public static Cursor NoMoveHoriz { + get { + if (no_move_horiz == null) { + no_move_horiz = new Cursor(StdCursor.NoMoveHoriz); + no_move_horiz.name = "NoMoveHoriz"; + } + return no_move_horiz; + } + } + + public static Cursor NoMoveVert { + get { + if (no_move_vert == null) { + no_move_vert = new Cursor(StdCursor.NoMoveVert); + no_move_vert.name = "NoMoveVert"; + } + return no_move_vert; + } + } + + public static Cursor PanEast { + get { + if (pan_east == null) { + pan_east = new Cursor(StdCursor.PanEast); + pan_east.name = "PanEast"; + } + return pan_east; + } + } + + + + + public static Cursor PanNE { + get { + if (pan_ne == null) { + pan_ne = new Cursor(StdCursor.PanNE); + pan_ne.name = "PanNE"; + } + return pan_ne; + } + } + + + public static Cursor PanNorth { + get { + if (pan_north == null) { + pan_north = new Cursor(StdCursor.PanNorth); + pan_north.name = "PanNorth"; + } + return pan_north; + } + } + + public static Cursor PanNW { + get { + if (pan_nw == null) { + pan_nw = new Cursor(StdCursor.PanNW); + pan_nw.name = "PanNW"; + } + return pan_nw; + } + } + + public static Cursor PanSE { + get { + if (pan_se == null) { + pan_se = new Cursor(StdCursor.PanSE); + pan_se.name = "PanSE"; + } + return pan_se; + } + } + + public static Cursor PanSouth { + get { + if (pan_south == null) { + pan_south = new Cursor(StdCursor.PanSouth); + pan_south.name = "PanSouth"; + } + return pan_south; + } + } + + public static Cursor PanSW { + get { + if (pan_sw == null) { + pan_sw = new Cursor(StdCursor.PanSW); + pan_sw.name = "PanSW"; + } + return pan_sw; + } + } + + public static Cursor PanWest { + get { + if (pan_west == null) { + pan_west = new Cursor(StdCursor.PanWest); + pan_west.name = "PanWest"; + } + return pan_west; + } + } + + public static Cursor SizeAll { + get { + if (size_all == null) { + size_all = new Cursor(StdCursor.SizeAll); + size_all.name = "SizeAll"; + } + return size_all; + } + } + + public static Cursor SizeNESW { + get { + if (size_nesw == null) { + if (XplatUI.RunningOnUnix) { + size_nesw = new Cursor(Properties.Resources.NESW); + size_nesw.name = "SizeNESW"; + } else { + size_nesw = new Cursor(StdCursor.SizeNESW); + size_nesw.name = "SizeNESW"; + } + } + return size_nesw; + } + } + + public static Cursor SizeNS { + get { + if (size_ns == null) { + size_ns = new Cursor(StdCursor.SizeNS); + size_ns.name = "SizeNS"; + } + return size_ns; + } + } + + public static Cursor SizeNWSE { + get { + if (size_nwse == null) { + if (XplatUI.RunningOnUnix) { + size_nwse = new Cursor(Properties.Resources.NWSE); + size_nwse.name = "SizeNWSE"; + } else { + size_nwse = new Cursor(StdCursor.SizeNWSE); + size_nwse.name = "SizeNWSE"; + } + } + return size_nwse; + } + } + + public static Cursor SizeWE { + get { + if (size_we == null) { + size_we = new Cursor(StdCursor.SizeWE); + size_we.name = "SizeWE"; + } + return size_we; + } + } + + public static Cursor UpArrow { + get { + if (up_arrow == null) { + up_arrow = new Cursor(StdCursor.UpArrow); + up_arrow.name = "UpArrow"; + } + return up_arrow; + } + } + + public static Cursor VSplit { + get { + if (vsplit == null) { + vsplit = new Cursor(Properties.Resources.SplitterWE); + vsplit.name = "VSplit"; + } + return vsplit; + } + } + + public static Cursor WaitCursor { + get { + if (wait_cursor == null) { + wait_cursor = new Cursor(StdCursor.WaitCursor); + wait_cursor.name = "WaitCursor"; + } + return wait_cursor; + } + } + #endregion // Public Static Properties + } +} diff --git a/source/ShiftUI/Internal/DataObject.cs b/source/ShiftUI/Internal/DataObject.cs new file mode 100644 index 0000000..cfe74d5 --- /dev/null +++ b/source/ShiftUI/Internal/DataObject.cs @@ -0,0 +1,485 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +using System; +using System.IO; +using System.Drawing; +using System.Collections; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace ShiftUI { + [ClassInterface(ClassInterfaceType.None)] + public class DataObject : IDataObject, System.Runtime.InteropServices.ComTypes.IDataObject + { + #region DataObject.Entry Class + private class Entry { + #region Local Variables + private string type; + private object data; + private bool autoconvert; + internal Entry next; + #endregion // Local Variables + + #region Constructors + internal Entry(string type, object data, bool autoconvert) { + this.type = type; + this.data = data; + this.autoconvert = autoconvert; + } + #endregion // Constructors + + #region Properties + public object Data { + get { + return data; + } + + set { + data = value; + } + } + public bool AutoConvert { + get { + return autoconvert; + } + set { + autoconvert = value; + } + } + #endregion // Properties + + #region Methods + public static int Count(Entry entries) { + int result; + + result = 0; + + while (entries != null) { + result++; + entries = entries.next; + } + + return result; + } + + public static Entry Find (Entry entries, string type) { + return Find (entries, type, false); + } + + public static Entry Find(Entry entries, string type, bool only_convertible) { + while (entries != null) { + bool available = true; + if (only_convertible && !entries.autoconvert) + available = false; + if (available && String.Compare (entries.type, type, true) == 0) { + return entries; + } + entries = entries.next; + } + + return null; + } + + public static Entry FindConvertible(Entry entries, string type) { + Entry e; + + e = Find(entries, type); + if (e != null) { + return e; + } + + // map to *any* other text format if needed + if (type == DataFormats.StringFormat || type == DataFormats.Text || type == DataFormats.UnicodeText) { + e = entries; + while (e != null) { + if (e.type == DataFormats.StringFormat || e.type == DataFormats.Text || e.type == DataFormats.UnicodeText) + return e; + + e = e.next; + } + } + + return null; + } + + public static string[] Entries(Entry entries, bool convertible) { + Entry e; + ArrayList list; + string[] result; + + // Initially store into something that we can grow easily + list = new ArrayList(Entry.Count(entries)); + e = entries; + + if (convertible) { + // Add the convertibles + Entry text_entry = Entry.Find (entries, DataFormats.Text); + Entry utext_entry = Entry.Find (entries, DataFormats.UnicodeText); + Entry string_entry = Entry.Find (entries, DataFormats.StringFormat); + bool text_convertible = text_entry != null && text_entry.AutoConvert; + bool utext_convertible = utext_entry != null && utext_entry.AutoConvert; + bool string_convertible = string_entry != null && string_entry.AutoConvert; + + if (text_convertible || utext_convertible || string_convertible) { + list.Add (DataFormats.StringFormat); + list.Add (DataFormats.UnicodeText); + list.Add (DataFormats.Text); + } + } + + while (e != null) { + if (!list.Contains (e.type)) + list.Add (e.type); + e = e.next; + } + + // Copy the results into a string array + result = new string[list.Count]; + for (int i = 0; i < list.Count; i++) { + result[i] = (string)list[i]; + } + + return result; + } + #endregion // Methods + } + #endregion // DataObject.Entry class + + #region Local Variables + private Entry entries; + #endregion // Local Variables + + #region Public Constructors + public DataObject() { + entries = null; + } + + public DataObject(object data) { + SetData(data); + } + + public DataObject(string format, object data) { + SetData(format, data); + } + #endregion // Public Constructors + + #region Public Instance Methods + public virtual bool ContainsAudio () + { + return GetDataPresent (DataFormats.WaveAudio, true); + } + + public virtual bool ContainsFileDropList () + { + return GetDataPresent (DataFormats.FileDrop, true); + } + + public virtual bool ContainsImage () + { + return GetDataPresent (DataFormats.Bitmap, true); + } + + public virtual bool ContainsText () + { + return GetDataPresent (DataFormats.UnicodeText, true); + } + + public virtual bool ContainsText (TextDataFormat format) + { + if (!Enum.IsDefined (typeof (TextDataFormat), format)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextDataFormat", format)); + + return GetDataPresent (TextFormatToDataFormat (format), true); + } + + public virtual Stream GetAudioStream () + { + return (Stream)GetData (DataFormats.WaveAudio, true); + } + + public virtual object GetData(string format) { + return GetData(format, true); + } + + public virtual object GetData(string format, bool autoConvert) { + Entry e; + if (autoConvert) { + e = Entry.FindConvertible(entries, format); + } else { + e = Entry.Find(entries, format); + } + if (e == null) + return null; + return e.Data; + } + + public virtual object GetData(Type format) { + return GetData(format.FullName, true); + } + + public virtual bool GetDataPresent(string format) { + return GetDataPresent(format, true); + } + + public virtual bool GetDataPresent(string format, bool autoConvert) { + if (autoConvert) { + return Entry.FindConvertible(entries, format) != null; + } else { + return Entry.Find(entries, format) != null; + } + } + + public virtual bool GetDataPresent(Type format) { + return GetDataPresent(format.FullName, true); + } + + public virtual StringCollection GetFileDropList () + { + return (StringCollection)GetData (DataFormats.FileDrop, true); + } + public virtual string[] GetFormats() { + return GetFormats(true); + } + + public virtual string[] GetFormats(bool autoConvert) { + return Entry.Entries(entries, autoConvert); + } + + public virtual Image GetImage () + { + return (Image)GetData (DataFormats.Bitmap, true); + } + + public virtual string GetText () + { + return (string)GetData (DataFormats.UnicodeText, true); + } + + public virtual string GetText (TextDataFormat format) + { + if (!Enum.IsDefined (typeof (TextDataFormat), format)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextDataFormat", format)); + + return (string)GetData (TextFormatToDataFormat (format), false); + } + + public virtual void SetAudio (byte[] audioBytes) + { + if (audioBytes == null) + throw new ArgumentNullException ("audioBytes"); + + MemoryStream ms = new MemoryStream (audioBytes); + + SetAudio (ms); + } + + public virtual void SetAudio (Stream audioStream) + { + if (audioStream == null) + throw new ArgumentNullException ("audioStream"); + + SetData (DataFormats.WaveAudio, audioStream); + } + + public virtual void SetData(object data) { + SetData(data.GetType(), data); + } + + public virtual void SetData(string format, bool autoConvert, object data) { + Entry entry; + Entry e; + + entry = Entry.Find(entries, format); + + if (entry == null) { + entry = new DataObject.Entry(format, data, autoConvert); + } else { + entry.Data = data; + return; + } + + lock (this) { + if (entries == null) { + entries = entry; + } else { + // Insert into the list of known/defined formats + e = entries; + + while (e.next != null) { + e = e.next; + } + e.next = entry; + } + } + } + + public virtual void SetData(string format, object data) { + SetData(format, true, data); + } + + public virtual void SetData(Type format, object data) { + SetData(EnsureFormat(format), true, data); + } + + [MonoInternalNote ("Needs additional checks for valid paths, see MSDN")] + public virtual void SetFileDropList (StringCollection filePaths) + { + if (filePaths == null) + throw new ArgumentNullException ("filePaths"); + + SetData (DataFormats.FileDrop, filePaths); + } + + public virtual void SetImage (Image image) + { + if (image == null) + throw new ArgumentNullException ("image"); + + SetData (DataFormats.Bitmap, image); + } + + public virtual void SetText (string textData) + { + if (string.IsNullOrEmpty (textData)) + throw new ArgumentNullException ("text"); + + SetData (DataFormats.UnicodeText, textData); + } + + public virtual void SetText (string textData, TextDataFormat format) + { + if (string.IsNullOrEmpty (textData)) + throw new ArgumentNullException ("text"); + if (!Enum.IsDefined (typeof (TextDataFormat), format)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextDataFormat", format)); + + switch (format) { + case TextDataFormat.Text: + SetData (DataFormats.Text, textData); + break; + case TextDataFormat.UnicodeText: + SetData (DataFormats.UnicodeText, textData); + break; + case TextDataFormat.Rtf: + SetData (DataFormats.Rtf, textData); + break; + case TextDataFormat.Html: + SetData (DataFormats.Html, textData); + break; + case TextDataFormat.CommaSeparatedValue: + SetData (DataFormats.CommaSeparatedValue, textData); + break; + } + } + #endregion // Public Instance Methods + + #region Private Methods + internal string EnsureFormat(string name) { + DataFormats.Format f; + + f = DataFormats.Format.Find(name); + if (f == null) { + // Register the format + f = DataFormats.Format.Add(name); + } + + return f.Name; + } + + internal string EnsureFormat(Type type) { + return EnsureFormat(type.FullName); + } + + private string TextFormatToDataFormat (TextDataFormat format) + { + switch (format) { + case TextDataFormat.Text: + default: + return DataFormats.Text; + case TextDataFormat.UnicodeText: + return DataFormats.UnicodeText; + case TextDataFormat.Rtf: + return DataFormats.Rtf; + case TextDataFormat.Html: + return DataFormats.Html; + case TextDataFormat.CommaSeparatedValue: + return DataFormats.CommaSeparatedValue; + } + } + #endregion // Private Methods + + #region IDataObject Members + int System.Runtime.InteropServices.ComTypes.IDataObject.DAdvise (ref System.Runtime.InteropServices.ComTypes.FORMATETC pFormatetc, System.Runtime.InteropServices.ComTypes.ADVF advf, System.Runtime.InteropServices.ComTypes.IAdviseSink adviseSink, out int connection) + { + throw new NotImplementedException (); + } + + void System.Runtime.InteropServices.ComTypes.IDataObject.DUnadvise (int connection) + { + throw new NotImplementedException (); + } + + int System.Runtime.InteropServices.ComTypes.IDataObject.EnumDAdvise (out System.Runtime.InteropServices.ComTypes.IEnumSTATDATA enumAdvise) + { + throw new NotImplementedException (); + } + + System.Runtime.InteropServices.ComTypes.IEnumFORMATETC System.Runtime.InteropServices.ComTypes.IDataObject.EnumFormatEtc (System.Runtime.InteropServices.ComTypes.DATADIR direction) + { + throw new NotImplementedException (); + } + + int System.Runtime.InteropServices.ComTypes.IDataObject.GetCanonicalFormatEtc (ref System.Runtime.InteropServices.ComTypes.FORMATETC formatIn, out System.Runtime.InteropServices.ComTypes.FORMATETC formatOut) + { + throw new NotImplementedException (); + } + + void System.Runtime.InteropServices.ComTypes.IDataObject.GetData (ref System.Runtime.InteropServices.ComTypes.FORMATETC format, out System.Runtime.InteropServices.ComTypes.STGMEDIUM medium) + { + throw new NotImplementedException (); + } + + void System.Runtime.InteropServices.ComTypes.IDataObject.GetDataHere (ref System.Runtime.InteropServices.ComTypes.FORMATETC format, ref System.Runtime.InteropServices.ComTypes.STGMEDIUM medium) + { + throw new NotImplementedException (); + } + + int System.Runtime.InteropServices.ComTypes.IDataObject.QueryGetData (ref System.Runtime.InteropServices.ComTypes.FORMATETC format) + { + throw new NotImplementedException (); + } + + void System.Runtime.InteropServices.ComTypes.IDataObject.SetData (ref System.Runtime.InteropServices.ComTypes.FORMATETC formatIn, ref System.Runtime.InteropServices.ComTypes.STGMEDIUM medium, bool release) + { + throw new NotImplementedException (); + } + #endregion + } +} diff --git a/source/ShiftUI/Internal/Day.cs b/source/ShiftUI/Internal/Day.cs new file mode 100644 index 0000000..0c797a7 --- /dev/null +++ b/source/ShiftUI/Internal/Day.cs @@ -0,0 +1,39 @@ +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// John BouAntoun jba-mono@optusnet.com.au +// + +namespace ShiftUI { + // used mainly by monthcalendar + public enum Day { + Monday, + Tuesday, + Wednesday, + Thursday, + Friday, + Saturday, + Sunday, + Default + } +} diff --git a/source/ShiftUI/Internal/DebugHelper.cs b/source/ShiftUI/Internal/DebugHelper.cs new file mode 100644 index 0000000..3c76307 --- /dev/null +++ b/source/ShiftUI/Internal/DebugHelper.cs @@ -0,0 +1,257 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2008 Novell, Inc. +// +// Authors: +// Andreia Gaita (avidigal@novell.com) +// + +//#define DEBUG +//#define TRACE + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using System.IO; +using System.Diagnostics; + +namespace ShiftUI +{ + internal class DebugHelper + { + static DebugHelper () { + Debug.AutoFlush = true; + } + + struct Data { + public MethodBase method; + public object[] args; + public Data (MethodBase m, object[] a) { + this.method = m; + this.args = a; + } + } + + static Stack methods = new Stack(); + + [Conditional("DEBUG")] + internal static void DumpCallers () { + StackTrace trace = new StackTrace(true); + int count = trace.FrameCount; + Debug.Indent (); + for (int i = 1; i < count; i++) { + StackFrame parentFrame = trace.GetFrame(i); + MethodBase parentMethod = parentFrame.GetMethod(); + string file = parentFrame.GetFileName(); + if (file != null && file.Length > 1) + file = file.Substring (file.LastIndexOf (Path.DirectorySeparatorChar) + 1); + Debug.WriteLine(parentMethod.DeclaringType.Name + "." + parentMethod.Name + + " at " + file + ":" + parentFrame.GetFileLineNumber() + ); + } + + Debug.Unindent (); + } + + [Conditional("DEBUG")] + internal static void DumpCallers (int count) { + StackTrace trace = new StackTrace(true); + int c = (count > trace.FrameCount ? trace.FrameCount : count); + Debug.Indent (); + for (int i = 1; i < c; i++) { + StackFrame parentFrame = trace.GetFrame(i); + MethodBase parentMethod = parentFrame.GetMethod(); + string file = parentFrame.GetFileName(); + if (file != null && file.Length > 1) + file = file.Substring (file.LastIndexOf (Path.DirectorySeparatorChar) + 1); + Debug.WriteLine(parentMethod.DeclaringType.Name + "." + parentMethod.Name + + " at " + file + ":" + parentFrame.GetFileLineNumber() + ); + } + + Debug.Unindent (); + } + + [Conditional("DEBUG")] + internal static void Enter () + { + StackTrace trace = new StackTrace(); + methods.Push (new Data (trace.GetFrame(1).GetMethod(), null)); + Print (); + Debug.Indent (); + } + + [Conditional("DEBUG")] + internal static void Enter (object[] args) + { + StackTrace trace = new StackTrace(); + methods.Push (new Data (trace.GetFrame(1).GetMethod(), args)); + Print (); + Debug.Indent (); + } + + [Conditional("DEBUG")] + internal static void Leave () + { + if (methods.Count > 0) { + methods.Pop (); + Debug.Unindent (); + } + } + + [Conditional("DEBUG")] + internal static void Print () + { + if (methods.Count == 0) + return; + + Data data = methods.Peek (); + Debug.WriteLine (data.method.DeclaringType.Name + "." + data.method.Name); + } + + [Conditional("DEBUG")] + internal static void Print (int index) + { + if (methods.Count == 0 || methods.Count <= index || index < 0) + return; + + Stack temp = new Stack(index-1); + + for (int i = 0; i < index; i++) + temp.Push (methods.Pop ()); + + Data data = methods.Peek (); + for (int i = 0; i < temp.Count; i++) + methods.Push (temp.Pop()); + temp = null; + + Debug.WriteLine (data.method.DeclaringType.Name + "." + data.method.Name); + } + + [Conditional("DEBUG")] + internal static void Print (string methodName, string parameterName) + { + if (methods.Count == 0) + return; + + Stack temp = new Stack(); + + Data data = methods.Peek (); + bool foundit = false; + for (int i = 0; i < methods.Count; i++) + { + data = methods.Peek (); + if (data.method.Name.Equals (methodName)) { + foundit = true; + break; + } + temp.Push (methods.Pop ()); + } + + for (int i = 0; i < temp.Count; i++) + methods.Push (temp.Pop()); + temp = null; + + if (!foundit) + return; + + Debug.WriteLine (data.method.DeclaringType.Name + "." + data.method.Name); + ParameterInfo[] pi = data.method.GetParameters (); + + for (int i = 0; i < pi.Length; i++) { + if (pi[i].Name == parameterName) { + Debug.Indent (); + Debug.Write (parameterName + "="); + if (pi[i].ParameterType == typeof(IntPtr)) + Debug.WriteLine (String.Format ("0x{0:x}", ((IntPtr)data.args[i]).ToInt32())); + else + Debug.WriteLine (data.args[i]); + Debug.Unindent (); + } + } + } + + [Conditional("DEBUG")] + internal static void Print (string parameterName) + { + if (methods.Count == 0) + return; + Data data = methods.Peek (); + + ParameterInfo[] pi = data.method.GetParameters (); + + for (int i = 0; i < pi.Length; i++) { + if (pi[i].Name == parameterName) { + Debug.Indent (); + Debug.Write (parameterName + "="); + if (pi[i].ParameterType == typeof(IntPtr)) + Debug.WriteLine (String.Format ("0x{0:x}", data.args[i])); + else + Debug.WriteLine (data.args[i]); + Debug.Unindent (); + } + } + } + + [Conditional("DEBUG")] + internal static void WriteLine (object arg) + { + Debug.WriteLine (arg); + } + + [Conditional("DEBUG")] + internal static void WriteLine (string format, params object[] arg) + { + Debug.WriteLine (String.Format (format, arg)); + } + + [Conditional("DEBUG")] + internal static void WriteLine (string message) + { + Debug.WriteLine (message); + } + + [Conditional("DEBUG")] + internal static void Indent () + { + Debug.Indent (); + } + + [Conditional("DEBUG")] + internal static void Unindent () + { + Debug.Unindent (); + } + + [Conditional("TRACE")] + internal static void TraceWriteLine (string format, params object[] arg) + { + Debug.WriteLine (String.Format (format, arg)); + } + + [Conditional("TRACE")] + internal static void TraceWriteLine (string message) + { + Debug.WriteLine (message); + } + + } +} diff --git a/source/ShiftUI/Internal/DefaultLayout.cs b/source/ShiftUI/Internal/DefaultLayout.cs new file mode 100644 index 0000000..4fbf647 --- /dev/null +++ b/source/ShiftUI/Internal/DefaultLayout.cs @@ -0,0 +1,290 @@ +// +// DefaultLayout.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// Stefan Noack (noackstefan@googlemail.com) +// + +using System; +using System.Drawing; + +namespace ShiftUI.Layout +{ + class DefaultLayout : LayoutEngine + { + void LayoutDockedChildren (Widget parent, Widget[] Widgets) + { + Rectangle space = parent.DisplayRectangle; + MdiClient mdi = null; + + // Deal with docking; go through in reverse, MS docs say that lowest Z-order is closest to edge + for (int i = Widgets.Length - 1; i >= 0; i--) { + Widget child = Widgets[i]; + Size child_size = child.Size; + + if (child.AutoSize) + child_size = GetPreferredWidgetSize (child); + + if (!child.VisibleInternal + || child.WidgetLayoutType == Widget.LayoutType.Anchor) + continue; + + // MdiClient never fills the whole area like other Widgets, have to do it later + if (child is MdiClient) { + mdi = (MdiClient)child; + continue; + } + + switch (child.Dock) { + case DockStyle.None: + // Do nothing + break; + + case DockStyle.Left: + child.SetBoundsInternal (space.Left, space.Y, child_size.Width, space.Height, BoundsSpecified.None); + space.X += child.Width; + space.Width -= child.Width; + break; + + case DockStyle.Top: + child.SetBoundsInternal (space.Left, space.Y, space.Width, child_size.Height, BoundsSpecified.None); + space.Y += child.Height; + space.Height -= child.Height; + break; + + case DockStyle.Right: + child.SetBoundsInternal (space.Right - child_size.Width, space.Y, child_size.Width, space.Height, BoundsSpecified.None); + space.Width -= child.Width; + break; + + case DockStyle.Bottom: + child.SetBoundsInternal (space.Left, space.Bottom - child_size.Height, space.Width, child_size.Height, BoundsSpecified.None); + space.Height -= child.Height; + break; + + case DockStyle.Fill: + child.SetBoundsInternal (space.Left, space.Top, space.Width, space.Height, BoundsSpecified.None); + break; + } + } + + // MdiClient gets whatever space is left + if (mdi != null) + mdi.SetBoundsInternal (space.Left, space.Top, space.Width, space.Height, BoundsSpecified.None); + } + + void LayoutAnchoredChildren (Widget parent, Widget[] Widgets) + { + Rectangle space = parent.ClientRectangle; + + for (int i = 0; i < Widgets.Length; i++) { + int left; + int top; + int width; + int height; + + Widget child = Widgets[i]; + + if (!child.VisibleInternal + || child.WidgetLayoutType == Widget.LayoutType.Dock) + continue; + + AnchorStyles anchor = child.Anchor; + + left = child.Left; + top = child.Top; + + width = child.Width; + height = child.Height; + + if ((anchor & AnchorStyles.Right) != 0) { + if ((anchor & AnchorStyles.Left) != 0) + width = space.Width - child.dist_right - left; + else + left = space.Width - child.dist_right - width; + } + else if ((anchor & AnchorStyles.Left) == 0) { + // left+=diff_width/2 will introduce rounding errors (diff_width removed from svn after r51780) + // This calculates from scratch every time: + left = left + (space.Width - (left + width + child.dist_right)) / 2; + child.dist_right = space.Width - (left + width); + } + + if ((anchor & AnchorStyles.Bottom) != 0) { + if ((anchor & AnchorStyles.Top) != 0) + height = space.Height - child.dist_bottom - top; + else + top = space.Height - child.dist_bottom - height; + } + else if ((anchor & AnchorStyles.Top) == 0) { + // top += diff_height/2 will introduce rounding errors (diff_height removed from after r51780) + // This calculates from scratch every time: + top = top + (space.Height - (top + height + child.dist_bottom)) / 2; + child.dist_bottom = space.Height - (top + height); + } + + // Sanity + if (width < 0) + width = 0; + + if (height < 0) + height = 0; + + child.SetBoundsInternal (left, top, width, height, BoundsSpecified.None); + } + } + + void LayoutAutoSizedChildren (Widget parent, Widget[] Widgets) + { + for (int i = 0; i < Widgets.Length; i++) { + int left; + int top; + + Widget child = Widgets[i]; + if (!child.VisibleInternal + || child.WidgetLayoutType == Widget.LayoutType.Dock + || !child.AutoSize) + continue; + + AnchorStyles anchor = child.Anchor; + left = child.Left; + top = child.Top; + + Size preferredsize = GetPreferredWidgetSize (child); + + if (((anchor & AnchorStyles.Left) != 0) || ((anchor & AnchorStyles.Right) == 0)) + child.dist_right += child.Width - preferredsize.Width; + if (((anchor & AnchorStyles.Top) != 0) || ((anchor & AnchorStyles.Bottom) == 0)) + child.dist_bottom += child.Height - preferredsize.Height; + + child.SetBoundsInternal (left, top, preferredsize.Width, preferredsize.Height, BoundsSpecified.None); + } + } + + void LayoutAutoSizeContainer (Widget container) + { + int left; + int top; + int width; + int height; + + if (!container.VisibleInternal || container.WidgetLayoutType == Widget.LayoutType.Dock || !container.AutoSize) + return; + + left = container.Left; + top = container.Top; + + Size preferredsize = container.PreferredSize; + + if (container.GetAutoSizeMode () == AutoSizeMode.GrowAndShrink) { + width = preferredsize.Width; + height = preferredsize.Height; + } else { + width = container.ExplicitBounds.Width; + height = container.ExplicitBounds.Height; + if (preferredsize.Width > width) + width = preferredsize.Width; + if (preferredsize.Height > height) + height = preferredsize.Height; + } + + // Sanity + if (width < container.MinimumSize.Width) + width = container.MinimumSize.Width; + + if (height < container.MinimumSize.Height) + height = container.MinimumSize.Height; + + if (container.MaximumSize.Width != 0 && width > container.MaximumSize.Width) + width = container.MaximumSize.Width; + + if (container.MaximumSize.Height != 0 && height > container.MaximumSize.Height) + height = container.MaximumSize.Height; + + container.SetBoundsInternal (left, top, width, height, BoundsSpecified.None); + } + + public override bool Layout (object container, LayoutEventArgs args) + { + Widget parent = container as Widget; + + Widget[] Widgets = parent.Widgets.GetAllWidgets (); + + LayoutDockedChildren (parent, Widgets); + LayoutAnchoredChildren (parent, Widgets); + LayoutAutoSizedChildren (parent, Widgets); + if (parent is Form) LayoutAutoSizeContainer (parent); + + return false; + } + + private Size GetPreferredWidgetSize (Widget child) + { + int width; + int height; + Size preferredsize = child.PreferredSize; + + if (child.GetAutoSizeMode () == AutoSizeMode.GrowAndShrink || (child.Dock != DockStyle.None && !(child is Button) && !(child is FlowLayoutPanel))) { + width = preferredsize.Width; + height = preferredsize.Height; + } else { + width = child.ExplicitBounds.Width; + height = child.ExplicitBounds.Height; + if (preferredsize.Width > width) + width = preferredsize.Width; + if (preferredsize.Height > height) + height = preferredsize.Height; + } + if (child.AutoSize && child is FlowLayoutPanel && child.Dock != DockStyle.None) { + switch (child.Dock) { + case DockStyle.Left: + case DockStyle.Right: + if (preferredsize.Width < child.ExplicitBounds.Width && preferredsize.Height < child.Parent.PaddingClientRectangle.Height) + width = preferredsize.Width; + break; + case DockStyle.Top: + case DockStyle.Bottom: + if (preferredsize.Height < child.ExplicitBounds.Height && preferredsize.Width < child.Parent.PaddingClientRectangle.Width) + height = preferredsize.Height; + break; + } + } + // Sanity + if (width < child.MinimumSize.Width) + width = child.MinimumSize.Width; + + if (height < child.MinimumSize.Height) + height = child.MinimumSize.Height; + + if (child.MaximumSize.Width != 0 && width > child.MaximumSize.Width) + width = child.MaximumSize.Width; + + if (child.MaximumSize.Height != 0 && height > child.MaximumSize.Height) + height = child.MaximumSize.Height; + + return new Size (width, height); + } + } +} diff --git a/source/ShiftUI/Internal/Dnd.cs b/source/ShiftUI/Internal/Dnd.cs new file mode 100644 index 0000000..b08b528 --- /dev/null +++ b/source/ShiftUI/Internal/Dnd.cs @@ -0,0 +1,371 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Geoff Norton (gnorton@novell.com) +// +// + + +using System; +using System.IO; +using System.Text; +using System.Drawing; +using System.Threading; +using System.Collections; +using ShiftUI; +using System.Runtime.Serialization; +using System.Runtime.InteropServices; +using System.Runtime.Serialization.Formatters.Binary; + +namespace ShiftUI.CarbonInternal { + internal delegate void DragTrackingDelegate (short message, IntPtr window, IntPtr data, IntPtr dragref); + + internal class Dnd { + internal const uint kEventParamDragRef = 1685217639; + internal const uint typeDragRef = 1685217639; + + internal const uint typeMono = 1836019311; + internal const uint typeMonoSerializedObject = 1836279154; + + private static DragDropEffects effects = DragDropEffects.None; + private static DragTrackingDelegate DragTrackingHandler = new DragTrackingDelegate (TrackingCallback); + + static Dnd () { + try { + InstallTrackingHandler (DragTrackingHandler, IntPtr.Zero, IntPtr.Zero); + } catch (EntryPointNotFoundException) { + // it is deprecated in 10.6 and does not exist anymore. + } + } + + internal Dnd () { + } + + internal static void TrackingCallback (short message, IntPtr window, IntPtr data, IntPtr dragref) { + XplatUICarbon.GetInstance ().FlushQueue (); + } + + internal static DragDropEffects DragActionsToEffects (UInt32 actions) { + DragDropEffects effects = DragDropEffects.None; + if ((actions & 1) != 0) + effects |= DragDropEffects.Copy; + if ((actions & (1 << 4)) != 0) + effects |= DragDropEffects.Move; + if ((actions & 0xFFFFFFFF) != 0) + effects |= DragDropEffects.All; + + return effects; + } + + internal static DataObject DragToDataObject (IntPtr dragref) { + UInt32 items = 0; + ArrayList flavorlist = new ArrayList (); + + CountDragItems (dragref, ref items); + + for (uint item_counter = 1; item_counter <= items; item_counter++) { + IntPtr itemref = IntPtr.Zero; + UInt32 flavors = 0; + + GetDragItemReferenceNumber (dragref, item_counter, ref itemref); + CountDragItemFlavors (dragref, itemref, ref flavors); + for (uint flavor_counter = 1; flavor_counter <= flavors; flavor_counter++) { + FlavorHandler flavor = new FlavorHandler (dragref, itemref, flavor_counter); + if (flavor.Supported) + flavorlist.Add (flavor); + } + } + + if (flavorlist.Count > 0) { + return ((FlavorHandler) flavorlist [0]).Convert (flavorlist); + } + + return new DataObject (); + } + + internal static bool HandleEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) { + Widget Widget; + DataObject data; + DragEventArgs drag_event; + DragDropEffects allowed; + QDPoint point = new QDPoint (); + UInt32 actions = 0; + IntPtr dragref = IntPtr.Zero; + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd == null || hwnd.Handle != handle) + return false; + + GetEventParameter (eventref, kEventParamDragRef, typeDragRef, IntPtr.Zero, (uint) Marshal.SizeOf (typeof (IntPtr)), IntPtr.Zero, ref dragref); + XplatUICarbon.GetGlobalMouse (ref point); + GetDragAllowableActions (dragref, ref actions); + Widget = Widget.FromHandle (hwnd.Handle); + allowed = DragActionsToEffects (actions); + data = DragToDataObject (dragref); + drag_event = new DragEventArgs (data, 0, point.x, point.y, allowed, DragDropEffects.None); + + switch (kind) { + case WidgetHandler.kEventWidgetDragEnter: { + bool accept = Widget.AllowDrop; + SetEventParameter (eventref, WidgetHandler.kEventParamWidgetLikesDrag, WidgetHandler.typeBoolean, (uint)Marshal.SizeOf (typeof (bool)), ref accept); + + Widget.DndEnter (drag_event); + effects = drag_event.Effect; + return false; + } + case WidgetHandler.kEventWidgetDragWithin: + Widget.DndOver (drag_event); + effects = drag_event.Effect; + break; + case WidgetHandler.kEventWidgetDragLeave: + Widget.DndLeave (drag_event); + break; + case WidgetHandler.kEventWidgetDragReceive: + Widget.DndDrop (drag_event); + break; + } + return true; + } + + public void SetAllowDrop (Hwnd hwnd, bool allow) { + if (hwnd.allow_drop == allow) + return; + + hwnd.allow_drop = allow; + SetWidgetDragTrackingEnabled (hwnd.whole_window, true); + SetWidgetDragTrackingEnabled (hwnd.client_window, true); + } + + public void SendDrop (IntPtr handle, IntPtr from, IntPtr time) { + } + + public DragDropEffects StartDrag (IntPtr handle, object data, DragDropEffects allowed_effects) { + IntPtr dragref = IntPtr.Zero; + EventRecord eventrecord = new EventRecord (); + + effects = DragDropEffects.None; + + NewDrag (ref dragref); + XplatUICarbon.GetGlobalMouse (ref eventrecord.mouse); + StoreObjectInDrag (handle, dragref, data); + + TrackDrag (dragref, ref eventrecord, IntPtr.Zero); + + DisposeDrag (dragref); + + return effects; + } + + public void StoreObjectInDrag (IntPtr handle, IntPtr dragref, object data) { + IntPtr type = IntPtr.Zero; + IntPtr dataptr = IntPtr.Zero; + Int32 size = 0; + + if (data is string) { + // implement me + throw new NotSupportedException ("Implement me."); + } else if (data is ISerializable) { + MemoryStream stream = new MemoryStream (); + BinaryFormatter bf = new BinaryFormatter (); + + bf.Serialize (stream, data); + + dataptr = Marshal.AllocHGlobal ((int) stream.Length); + stream.Seek (0, 0); + + for (int i = 0; i < stream.Length; i++) { + Marshal.WriteByte (dataptr, i, (byte) stream.ReadByte ()); + } + + type = (IntPtr) typeMonoSerializedObject; + size = (int) stream.Length; + } else { + dataptr = (IntPtr) GCHandle.Alloc (data); + + type = (IntPtr) typeMono; + size = Marshal.SizeOf (typeof (IntPtr)); + } + + AddDragItemFlavor (dragref, handle, type, ref dataptr, size, 1 << 0); + } + + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int InstallTrackingHandler (DragTrackingDelegate callback, IntPtr window, IntPtr data); + + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref IntPtr data); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int SetEventParameter (IntPtr eventref, uint name, uint type, uint size, ref bool data); + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int SetWidgetDragTrackingEnabled (IntPtr view, bool enabled); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int AddDragItemFlavor (IntPtr dragref, IntPtr itemref, IntPtr flavortype, ref IntPtr data, Int32 size, UInt32 flags); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int CountDragItems (IntPtr dragref, ref UInt32 count); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int CountDragItemFlavors (IntPtr dragref, IntPtr itemref, ref UInt32 count); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int GetDragItemReferenceNumber (IntPtr dragref, UInt32 index, ref IntPtr itemref); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int NewDrag (ref IntPtr dragref); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int TrackDrag (IntPtr dragref, ref EventRecord eventrecord, IntPtr region); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int DisposeDrag (IntPtr dragref); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int GetDragAllowableActions (IntPtr dragref, ref UInt32 actions); + } + + internal struct EventRecord { + internal UInt16 what; + internal UInt32 message; + internal UInt32 when; + internal QDPoint mouse; + internal UInt16 modifiers; + } + + internal class FlavorHandler { + internal IntPtr flavorref; + internal IntPtr dragref; + internal IntPtr itemref; + internal Int32 size; + internal UInt32 flags; + internal byte [] data; + internal string fourcc; + + internal FlavorHandler (IntPtr dragref, IntPtr itemref, uint counter) { + GetFlavorType (dragref, itemref, counter, ref flavorref); + GetFlavorFlags (dragref, itemref, flavorref, ref flags); + byte [] fourcc_b = BitConverter.GetBytes ((Int32)flavorref); + this.fourcc = String.Format ("{0}{1}{2}{3}", (char)fourcc_b [3], (char)fourcc_b [2], (char)fourcc_b [1], (char)fourcc_b [0]); + this.dragref = dragref; + this.itemref = itemref; + + this.GetData (); + } + + internal void GetData () { + GetFlavorDataSize (dragref, itemref, flavorref, ref size); + data = new byte [size]; + GetFlavorData (dragref, itemref, flavorref, data, ref size, 0); + } + + internal string DataString { + get { return Encoding.Default.GetString (this.data); } + } + + internal byte[] DataArray { + get { return this.data; } + } + + internal IntPtr DataPtr { + get { return (IntPtr) BitConverter.ToInt32 (this.data, 0); } + } + + internal bool Supported { + get { + switch (fourcc) { + case "furl": + return true; + case "mono": + return true; + case "mser": + return true; + } + return false; + } + } + + internal DataObject Convert (ArrayList flavorlist) { + switch (fourcc) { + case "furl": + return ConvertToFileDrop (flavorlist); + case "mono": + return ConvertToObject (flavorlist); + case "mser": + return DeserializeObject (flavorlist); + } + + return new DataObject (); + } + + internal DataObject DeserializeObject (ArrayList flavorlist) { + DataObject data = new DataObject (); + MemoryStream stream = new MemoryStream (this.DataArray); + BinaryFormatter bf = new BinaryFormatter (); + + if (stream.Length == 0) + return data; + + stream.Seek (0, 0); + data.SetData (bf.Deserialize (stream)); + + return data; + } + + internal DataObject ConvertToObject (ArrayList flavorlist) { + DataObject data = new DataObject (); + + foreach (FlavorHandler flavor in flavorlist) { + GCHandle handle = (GCHandle) flavor.DataPtr; + + data.SetData (handle.Target); + } + + return data; + } + + internal DataObject ConvertToFileDrop (ArrayList flavorlist) { + DataObject data = new DataObject (); + ArrayList uri_list = new ArrayList (); + + foreach (FlavorHandler flavor in flavorlist) { + try { + uri_list.Add (new Uri (flavor.DataString).LocalPath); + } catch { } + } + + string [] l = (string []) uri_list.ToArray (typeof (string)); + if (l.Length < 1) + return data; + data.SetData (DataFormats.FileDrop, l); + data.SetData ("FileName", l [0]); + data.SetData ("FileNameW", l [0]); + + return data; + } + + public override string ToString () { + return fourcc; + } + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int GetFlavorDataSize (IntPtr dragref, IntPtr itemref, IntPtr flavorref, ref Int32 size); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int GetFlavorData (IntPtr dragref, IntPtr itemref, IntPtr flavorref, [In, Out] byte[] data, ref Int32 size, UInt32 offset); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int GetFlavorFlags (IntPtr dragref, IntPtr itemref, IntPtr flavorref, ref UInt32 flags); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int GetFlavorType (IntPtr dragref, IntPtr itemref, UInt32 index, ref IntPtr flavor); + } +} diff --git a/source/ShiftUI/Internal/DockingAttribute.cs b/source/ShiftUI/Internal/DockingAttribute.cs new file mode 100644 index 0000000..3aba6bf --- /dev/null +++ b/source/ShiftUI/Internal/DockingAttribute.cs @@ -0,0 +1,74 @@ +// +// DockingAttribute.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Daniel Nauck +// +// Author: +// Daniel Nauck (dna(at)mono-project(dot)de) + + +using System; +using ShiftUI; + +namespace ShiftUI +{ + [AttributeUsageAttribute(AttributeTargets.Class)] + public sealed class DockingAttribute : Attribute + { + private DockingBehavior dockingBehavior; + + public DockingAttribute() + { + dockingBehavior = DockingBehavior.Never; + } + + public DockingAttribute(DockingBehavior dockingBehavior) + { + this.dockingBehavior = dockingBehavior; + } + + public static readonly DockingAttribute Default = new DockingAttribute(); + + public DockingBehavior DockingBehavior + { + get { return dockingBehavior; } + } + + public override bool Equals(object obj) + { + if (obj is DockingAttribute) + return (dockingBehavior == ((DockingAttribute)obj).DockingBehavior); + else + return false; + } + + public override int GetHashCode() + { + return dockingBehavior.GetHashCode(); + } + + public override bool IsDefaultAttribute() + { + return Default.Equals(this); + } + } +} diff --git a/source/ShiftUI/Internal/DockingBehavior.cs b/source/ShiftUI/Internal/DockingBehavior.cs new file mode 100644 index 0000000..b5dcdc0 --- /dev/null +++ b/source/ShiftUI/Internal/DockingBehavior.cs @@ -0,0 +1,38 @@ +// +// DockingBehavior.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum DockingBehavior + { + Never = 0, + Ask = 1, + AutoDock = 2 + } +} diff --git a/source/ShiftUI/Internal/DrawToolTipEventArgs.cs b/source/ShiftUI/Internal/DrawToolTipEventArgs.cs new file mode 100644 index 0000000..8d66f5f --- /dev/null +++ b/source/ShiftUI/Internal/DrawToolTipEventArgs.cs @@ -0,0 +1,113 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Rolf Bjarne Kvinge +// +// +// COMPLETE + + +using System.Drawing; +using System; + +namespace ShiftUI +{ + public class DrawToolTipEventArgs : EventArgs + { + private Widget associated_control; + private IWin32Window associated_window; + private Color back_color; + private Font font; + private Rectangle bounds; + private Color fore_color; + private Graphics graphics; + private string tooltip_text; + + public DrawToolTipEventArgs (Graphics graphics, IWin32Window associatedWindow, Widget associatedControl, Rectangle bounds, string toolTipText, Color backColor, Color foreColor, Font font) + { + this.graphics = graphics; + this.associated_window = associatedWindow; + this.associated_control = associatedControl; + this.bounds = bounds; + this.tooltip_text = toolTipText; + this.back_color = backColor; + this.fore_color = foreColor; + this.font = font; + } + + public void DrawBackground () + { + graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (back_color), bounds); + } + + public void DrawBorder () + { + WidgetPaint.DrawBorder (graphics, bounds, SystemColors.WindowFrame, ButtonBorderStyle.Solid); + } + + public void DrawText () + { + DrawText (TextFormatFlags.HidePrefix | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter); + } + + public void DrawText (TextFormatFlags flags) + { + TextRenderer.DrawTextInternal (graphics, tooltip_text, font, bounds, fore_color, flags, false); + } + + public Widget AssociatedWidget { + get { + return associated_control; + } + } + + public IWin32Window AssociatedWindow { + get { + return associated_window; + } + } + + public Rectangle Bounds { + get { + return bounds; + } + } + + public Font Font { + get { + return font; + } + } + + public Graphics Graphics { + get { + return graphics; + } + } + + public string ToolTipText { + get { + return tooltip_text; + } + } + } +} \ No newline at end of file diff --git a/source/ShiftUI/Internal/DrawToolTipEventHandler.cs b/source/ShiftUI/Internal/DrawToolTipEventHandler.cs new file mode 100644 index 0000000..e647ae8 --- /dev/null +++ b/source/ShiftUI/Internal/DrawToolTipEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Rolf Bjarne Kvinge +// +// +// COMPLETE + +namespace ShiftUI +{ + public delegate void DrawToolTipEventHandler (object sender, DrawToolTipEventArgs e); +} diff --git a/source/ShiftUI/Internal/Enums.cs b/source/ShiftUI/Internal/Enums.cs new file mode 100644 index 0000000..50d705e --- /dev/null +++ b/source/ShiftUI/Internal/Enums.cs @@ -0,0 +1,108 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software",, to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Geoff Norton +// + +using System; + +namespace ShiftUI.CarbonInternal { + internal enum WindowClass : uint { + kAlertWindowClass = 1, + kMovableAlertWindowClass = 2, + kModalWindowClass = 3, + kMovableModalWindowClass = 4, + kFloatingWindowClass = 5, + kDocumentWindowClass = 6, + kUtilityWindowClass = 8, + kHelpWindowClass = 10, + kSheetWindowClass = 11, + kToolbarWindowClass = 12, + kPlainWindowClass = 13, + kOverlayWindowClass = 14, + kSheetAlertWindowClass = 15, + kAltPlainWindowClass = 16, + kDrawerWindowClass = 20, + kAllWindowClasses = 0xFFFFFFFF + } + + internal enum WindowAttributes : uint { + kWindowNoAttributes = 0, + kWindowCloseBoxAttribute = (1u << 0), + kWindowHorizontalZoomAttribute = (1u << 1), + kWindowVerticalZoomAttribute = (1u << 2), + kWindowFullZoomAttribute = (kWindowVerticalZoomAttribute | kWindowHorizontalZoomAttribute), + kWindowCollapseBoxAttribute = (1u << 3), + kWindowResizableAttribute = (1u << 4), + kWindowSideTitlebarAttribute = (1u << 5), + kWindowToolbarButtonAttribute = (1u << 6), + kWindowMetalAttribute = (1u << 8), + kWindowNoUpdatesAttribute = (1u << 16), + kWindowNoActivatesAttribute = (1u << 17), + kWindowOpaqueForEventsAttribute = (1u << 18), + kWindowCompositingAttribute = (1u << 19), + kWindowNoShadowAttribute = (1u << 21), + kWindowHideOnSuspendAttribute = (1u << 24), + kWindowStandardHandlerAttribute = (1u << 25), + kWindowHideOnFullScreenAttribute = (1u << 26), + kWindowInWindowMenuAttribute = (1u << 27), + kWindowLiveResizeAttribute = (1u << 28), + kWindowIgnoreClicksAttribute = (1u << 29), + kWindowNoConstrainAttribute = (1u << 31), + kWindowStandardDocumentAttributes = (kWindowCloseBoxAttribute | kWindowFullZoomAttribute | kWindowCollapseBoxAttribute | kWindowResizableAttribute), + kWindowStandardFloatingAttributes = (kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute) + } + + internal enum ThemeCursor : uint { + kThemeArrowCursor = 0, + kThemeCopyArrowCursor = 1, + kThemeAliasArrowCursor = 2, + kThemeContextualMenuArrowCursor = 3, + kThemeIBeamCursor = 4, + kThemeCrossCursor = 5, + kThemePlusCursor = 6, + kThemeWatchCursor = 7, + kThemeClosedHandCursor = 8, + kThemeOpenHandCursor = 9, + kThemePointingHandCursor = 10, + kThemeCountingUpHandCursor = 11, + kThemeCountingDownHandCursor = 12, + kThemeCountingUpAndDownHandCursor = 13, + kThemeSpinningCursor = 14, + kThemeResizeLeftCursor = 15, + kThemeResizeRightCursor = 16, + kThemeResizeLeftRightCursor = 17, + kThemeNotAllowedCursor = 18 + } + + internal enum MouseTrackingResult : ushort { + kMouseTrackingMouseDown = 1, + kMouseTrackingMouseUp = 2, + kMouseTrackingMouseExited = 3, + kMouseTrackingMouseEntered = 4, + kMouseTrackingMouseDragged = 5, + kMouseTrackingKeyModifiersChanged = 6, + kMouseTrackingUserCancelled = 7, + kMouseTrackingTimedOut = 8, + kMouseTrackingMouseMoved = 9 + } +} diff --git a/source/ShiftUI/Internal/EventHandler.cs b/source/ShiftUI/Internal/EventHandler.cs new file mode 100644 index 0000000..673e3d0 --- /dev/null +++ b/source/ShiftUI/Internal/EventHandler.cs @@ -0,0 +1,184 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Geoff Norton +// +// + +using System; +using System.Runtime.InteropServices; + +namespace ShiftUI.CarbonInternal { + internal delegate int EventDelegate (IntPtr callref, IntPtr eventref, IntPtr user_data); + + internal class EventHandler { + internal static EventDelegate EventHandlerDelegate = new EventDelegate (EventCallback); + internal static XplatUICarbon Driver; + + internal const int EVENT_NOT_HANDLED = 0; + internal const int EVENT_HANDLED = -9874; + + internal const uint kEventClassMouse = 1836021107; + internal const uint kEventClassKeyboard = 1801812322; + internal const uint kEventClassTextInput = 1952807028; + internal const uint kEventClassApplication = 1634758764; + internal const uint kEventClassAppleEvent = 1701867619; + internal const uint kEventClassMenu = 1835363957; + internal const uint kEventClassWindow = 2003398244; + internal const uint kEventClassWidget = 1668183148; + internal const uint kEventClassCommand = 1668113523; + internal const uint kEventClassTablet = 1952607348; + internal const uint kEventClassVolume = 1987013664; + internal const uint kEventClassAppearance = 1634758765; + internal const uint kEventClassService = 1936028278; + internal const uint kEventClassToolbar = 1952604530; + internal const uint kEventClassToolbarItem = 1952606580; + internal const uint kEventClassAccessibility = 1633903461; + internal const uint kEventClassHIObject = 1751740258; + + internal static EventTypeSpec [] HIObjectEvents = new EventTypeSpec [] { + new EventTypeSpec (kEventClassHIObject, HIObjectHandler.kEventHIObjectConstruct), + new EventTypeSpec (kEventClassHIObject, HIObjectHandler.kEventHIObjectInitialize), + new EventTypeSpec (kEventClassHIObject, HIObjectHandler.kEventHIObjectDestruct) + }; + internal static EventTypeSpec [] WidgetEvents = new EventTypeSpec [] { + new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetBoundsChanged), + new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetDraw), + new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetDragEnter), + new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetDragWithin), + new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetDragLeave), + new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetDragReceive), + new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetGetFocusPart), + new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetInitialize), + new EventTypeSpec (kEventClassWidget, WidgetHandler.kEventWidgetVisibilityChanged) + }; + + internal static EventTypeSpec [] ApplicationEvents = new EventTypeSpec[] { + new EventTypeSpec (kEventClassApplication, ApplicationHandler.kEventAppActivated), + new EventTypeSpec (kEventClassApplication, ApplicationHandler.kEventAppDeactivated) + }; + + private static EventTypeSpec [] WindowEvents = new EventTypeSpec[] { + new EventTypeSpec (kEventClassMouse, MouseHandler.kEventMouseMoved), + new EventTypeSpec (kEventClassMouse, MouseHandler.kEventMouseDragged), + new EventTypeSpec (kEventClassMouse, MouseHandler.kEventMouseDown), + new EventTypeSpec (kEventClassMouse, MouseHandler.kEventMouseUp), + new EventTypeSpec (kEventClassMouse, MouseHandler.kEventMouseWheelMoved), + new EventTypeSpec (kEventClassMouse, MouseHandler.kEventMouseScroll), + + new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowDeactivated), + new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowActivated), + new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowDeactivated), + new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowCollapsed), + new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowCollapsing), + new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowExpanded), + new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowExpanding), + new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowBoundsChanged), + new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowResizeStarted), + new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowResizeCompleted), + new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowClose), + new EventTypeSpec (kEventClassWindow, WindowHandler.kEventWindowShown), + + new EventTypeSpec (kEventClassKeyboard, KeyboardHandler.kEventRawKeyModifiersChanged), + new EventTypeSpec (kEventClassKeyboard, KeyboardHandler.kEventRawKeyDown), + new EventTypeSpec (kEventClassKeyboard, KeyboardHandler.kEventRawKeyRepeat), + new EventTypeSpec (kEventClassKeyboard, KeyboardHandler.kEventRawKeyUp), + new EventTypeSpec (kEventClassTextInput, KeyboardHandler.kEventTextInputUnicodeForKeyEvent) + }; + + internal static int EventCallback (IntPtr callref, IntPtr eventref, IntPtr handle) { + uint klass = GetEventClass (eventref); + uint kind = GetEventKind (eventref); + MSG msg = new MSG (); + IEventHandler handler = null; + + switch (klass) { + case kEventClassHIObject: { + handler = (IEventHandler) Driver.HIObjectHandler; + break; + } + case kEventClassKeyboard: + case kEventClassTextInput: + handler = (IEventHandler) Driver.KeyboardHandler; + break; + case kEventClassWindow: + handler = (IEventHandler) Driver.WindowHandler; + break; + case kEventClassMouse: + handler = (IEventHandler) Driver.MouseHandler; + break; + case kEventClassWidget: + handler = (IEventHandler) Driver.WidgetHandler; + break; + case kEventClassApplication: + handler = (IEventHandler) Driver.ApplicationHandler; + break; + default: + return EVENT_NOT_HANDLED; + } + + if (handler.ProcessEvent (callref, eventref, handle, kind, ref msg)) { + Driver.EnqueueMessage (msg); + return EVENT_HANDLED; + } + + return EVENT_NOT_HANDLED; + } + + internal static bool TranslateMessage (ref MSG msg) { + bool result = false; + + if (!result) + result = Driver.KeyboardHandler.TranslateMessage (ref msg); + if (!result) + result = Driver.MouseHandler.TranslateMessage (ref msg); + + return result; + } + + internal static void InstallApplicationHandler () { + InstallEventHandler (GetApplicationEventTarget (), EventHandlerDelegate, (uint)ApplicationEvents.Length, ApplicationEvents, IntPtr.Zero, IntPtr.Zero); + } + + internal static void InstallWidgetHandler (IntPtr Widget) { + InstallEventHandler (GetWidgetEventTarget (Widget), EventHandlerDelegate, (uint)WidgetEvents.Length, WidgetEvents, Widget, IntPtr.Zero); + } + + internal static void InstallWindowHandler (IntPtr window) { + InstallEventHandler (GetWindowEventTarget (window), EventHandlerDelegate, (uint)WindowEvents.Length, WindowEvents, window, IntPtr.Zero); + } + + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern IntPtr GetApplicationEventTarget (); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal static extern IntPtr GetWidgetEventTarget (IntPtr Widget); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal static extern IntPtr GetWindowEventTarget (IntPtr window); + + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal static extern uint GetEventClass (IntPtr eventref); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern uint GetEventKind (IntPtr eventref); + + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int InstallEventHandler (IntPtr window, EventDelegate event_handler, uint count, EventTypeSpec [] types, IntPtr user_data, IntPtr handlerref); + } +} diff --git a/source/ShiftUI/Internal/EventHandlerBase.cs b/source/ShiftUI/Internal/EventHandlerBase.cs new file mode 100644 index 0000000..39bada4 --- /dev/null +++ b/source/ShiftUI/Internal/EventHandlerBase.cs @@ -0,0 +1,40 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Geoff Norton +// +// + +using System; + +namespace ShiftUI.CarbonInternal { + internal abstract class EventHandlerBase { + internal XplatUICarbon Driver; + + public EventHandlerBase () { + } + + public EventHandlerBase (XplatUICarbon driver) { + Driver = driver; + } + } +} diff --git a/source/ShiftUI/Internal/FixedSizeTextBox.cs b/source/ShiftUI/Internal/FixedSizeTextBox.cs new file mode 100644 index 0000000..33b5dff --- /dev/null +++ b/source/ShiftUI/Internal/FixedSizeTextBox.cs @@ -0,0 +1,47 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// +// + +// This is an internal class that allows us to use a textbox as a child control +// for things such as UpDown Widgets, and the ComboBox that will not have their +// size altered by scaling + +namespace ShiftUI { + + internal class FixedSizeTextBox : TextBox { + + public FixedSizeTextBox () + { + SetStyle (Widgetstyles.FixedWidth, true); + SetStyle (Widgetstyles.FixedHeight, true); + } + + public FixedSizeTextBox (bool fixed_horz, bool fixed_vert) { + SetStyle (Widgetstyles.FixedWidth, fixed_horz); + SetStyle (Widgetstyles.FixedHeight, fixed_vert); + } + } +} + diff --git a/source/ShiftUI/Internal/FlowLayout.cs b/source/ShiftUI/Internal/FlowLayout.cs new file mode 100644 index 0000000..5eb55a5 --- /dev/null +++ b/source/ShiftUI/Internal/FlowLayout.cs @@ -0,0 +1,589 @@ +// +// FlowLayout.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Collections.Generic; +using System.Drawing; + +namespace ShiftUI.Layout +{ + class FlowLayout : LayoutEngine + { + private static FlowLayoutSettings default_settings = new FlowLayoutSettings (); + + public FlowLayout () + { + } + + public override void InitLayout (object child, BoundsSpecified specified) + { + base.InitLayout (child, specified); + } + + public override bool Layout (object container, LayoutEventArgs args) + { + if (container is ToolStripPanel) + return false; + + if (container is ToolStrip) + return LayoutToolStrip ((ToolStrip)container); + + Widget parent = container as Widget; + + FlowLayoutSettings settings; + if (parent is FlowLayoutPanel) + settings = (parent as FlowLayoutPanel).LayoutSettings; + else + settings = default_settings; + + // Nothing to layout, exit method + if (parent.Widgets.Count == 0) return false; + + // Use DisplayRectangle so that parent.Padding is honored. + Rectangle parentDisplayRectangle = parent.DisplayRectangle; + Point currentLocation; + + // Set our starting point based on flow direction + switch (settings.FlowDirection) { + case FlowDirection.BottomUp: + currentLocation = new Point (parentDisplayRectangle.Left, parentDisplayRectangle.Bottom); + break; + case FlowDirection.LeftToRight: + case FlowDirection.TopDown: + default: + currentLocation = parentDisplayRectangle.Location; + break; + case FlowDirection.RightToLeft: + currentLocation = new Point (parentDisplayRectangle.Right, parentDisplayRectangle.Top); + break; + } + + bool forceFlowBreak = false; + + List rowWidgets = new List (); + + foreach (Widget c in parent.Widgets) { + // Only apply layout to visible Widgets. + if (!c.Visible) { continue; } + + // Resize any AutoSize Widgets to their preferred size + if (c.AutoSize == true) { + Size new_size = c.GetPreferredSize (c.Size); + c.SetBoundsInternal (c.Left, c.Top, new_size.Width, new_size.Height, BoundsSpecified.None); + } + + switch (settings.FlowDirection) { + case FlowDirection.BottomUp: + // Decide if it's time to start a new column + // - Our settings must be WrapContents, and we ran out of room or the previous Widget's FlowBreak == true + if (settings.WrapContents) + if ((currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) { + + currentLocation.X = FinishColumn (rowWidgets); + currentLocation.Y = parentDisplayRectangle.Bottom; + + forceFlowBreak = false; + rowWidgets.Clear (); + } + + // Offset the right margin and set the Widget to our point + currentLocation.Offset (0, c.Margin.Bottom * -1); + c.SetBoundsInternal (currentLocation.X + c.Margin.Left, currentLocation.Y - c.Height, c.Width, c.Height, BoundsSpecified.None); + + // Update our location pointer + currentLocation.Y -= (c.Height + c.Margin.Top); + break; + case FlowDirection.LeftToRight: + default: + // Decide if it's time to start a new row + // - Our settings must be WrapContents, and we ran out of room or the previous Widget's FlowBreak == true + if (settings.WrapContents && !(parent is ToolStripPanel)) + if ((parentDisplayRectangle.Width + parentDisplayRectangle.Left - currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) { + + currentLocation.Y = FinishRow (rowWidgets); + currentLocation.X = parentDisplayRectangle.Left; + + forceFlowBreak = false; + rowWidgets.Clear (); + } + + // Offset the left margin and set the Widget to our point + currentLocation.Offset (c.Margin.Left, 0); + c.SetBoundsInternal (currentLocation.X, currentLocation.Y + c.Margin.Top, c.Width, c.Height, BoundsSpecified.None); + + // Update our location pointer + currentLocation.X += c.Width + c.Margin.Right; + break; + case FlowDirection.RightToLeft: + // Decide if it's time to start a new row + // - Our settings must be WrapContents, and we ran out of room or the previous Widget's FlowBreak == true + if (settings.WrapContents) + if ((currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) { + + currentLocation.Y = FinishRow (rowWidgets); + currentLocation.X = parentDisplayRectangle.Right; + + forceFlowBreak = false; + rowWidgets.Clear (); + } + + // Offset the right margin and set the Widget to our point + currentLocation.Offset (c.Margin.Right * -1, 0); + c.SetBoundsInternal (currentLocation.X - c.Width, currentLocation.Y + c.Margin.Top, c.Width, c.Height, BoundsSpecified.None); + + // Update our location pointer + currentLocation.X -= (c.Width + c.Margin.Left); + break; + case FlowDirection.TopDown: + // Decide if it's time to start a new column + // - Our settings must be WrapContents, and we ran out of room or the previous Widget's FlowBreak == true + if (settings.WrapContents) + if ((parentDisplayRectangle.Height + parentDisplayRectangle.Top - currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) { + + currentLocation.X = FinishColumn (rowWidgets); + currentLocation.Y = parentDisplayRectangle.Top; + + forceFlowBreak = false; + rowWidgets.Clear (); + } + + // Offset the top margin and set the Widget to our point + currentLocation.Offset (0, c.Margin.Top); + c.SetBoundsInternal (currentLocation.X + c.Margin.Left, currentLocation.Y, c.Width, c.Height, BoundsSpecified.None); + + // Update our location pointer + currentLocation.Y += c.Height + c.Margin.Bottom; + break; + } + // Add it to our list of things to adjust the second dimension of + rowWidgets.Add (c); + + // If user set a flowbreak on this Widget, it will be the last one in this row/column + if (settings.GetFlowBreak (c)) + forceFlowBreak = true; + } + + // Set the Widget heights/widths for the last row/column + if (settings.FlowDirection == FlowDirection.LeftToRight || settings.FlowDirection == FlowDirection.RightToLeft) + FinishRow (rowWidgets); + else + FinishColumn (rowWidgets); + + return false; + } + + // Calculate the heights of the Widgets, returns the y coordinate of the greatest height it uses + private int FinishRow (List row) + { + // Nothing to do + if (row.Count == 0) return 0; + + int rowTop = int.MaxValue; + int rowBottom = 0; + bool allDockFill = true; + bool noAuto = true; + + // Special semantics if all Widgets are Dock.Fill/Anchor:Top,Bottom or AutoSize = true + foreach (Widget c in row) { + if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top && (c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) + allDockFill = false; + if (c.AutoSize == true) + noAuto = false; + } + + // Find the tallest Widget with a concrete height + foreach (Widget c in row) { + if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill) && ((c.Anchor & AnchorStyles.Top) != AnchorStyles.Top || (c.Anchor & AnchorStyles.Bottom) != AnchorStyles.Bottom || c.AutoSize == true)) + rowBottom = c.Bottom + c.Margin.Bottom; + if (c.Top - c.Margin.Top < rowTop) + rowTop = c.Top - c.Margin.Top; + } + + // Find the tallest Widget that is AutoSize = true + if (rowBottom == 0) + foreach (Widget c in row) + if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill && c.AutoSize == true)) + rowBottom = c.Bottom + c.Margin.Bottom; + + // Find the tallest Widget that is Dock = Fill + if (rowBottom == 0) + foreach (Widget c in row) + if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock == DockStyle.Fill)) + rowBottom = c.Bottom + c.Margin.Bottom; + + // Set the new heights for each Widget + foreach (Widget c in row) + if (allDockFill && noAuto) + c.SetBoundsInternal (c.Left, c.Top, c.Width, 0, BoundsSpecified.None); + else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top) && ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) + c.SetBoundsInternal (c.Left, c.Top, c.Width, rowBottom - c.Top - c.Margin.Bottom, BoundsSpecified.None); + else if (c.Dock == DockStyle.Bottom || ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) + c.SetBoundsInternal (c.Left, rowBottom - c.Margin.Bottom - c.Height, c.Width, c.Height, BoundsSpecified.None); + else if (c.Dock == DockStyle.Top || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top)) + continue; + else + c.SetBoundsInternal (c.Left, ((rowBottom - rowTop) / 2) - (c.Height / 2) + (int)Math.Floor (((c.Margin.Top - c.Margin.Bottom) / 2.0)) + rowTop, c.Width, c.Height, BoundsSpecified.None); + + // Return bottom y of this row used + if (rowBottom == 0) + return rowTop; + + return rowBottom; + } + + // Calculate the widths of the Widgets, returns the x coordinate of the greatest width it uses + private int FinishColumn (List col) + { + // Nothing to do + if (col.Count == 0) return 0; + + int rowLeft = int.MaxValue; + int rowRight = 0; + bool allDockFill = true; + bool noAuto = true; + + // Special semantics if all Widgets are Dock.Fill/Anchor:Left,Right or AutoSize = true + foreach (Widget c in col) { + if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left && (c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) + allDockFill = false; + if (c.AutoSize == true) + noAuto = false; + } + + // Find the widest Widget with a concrete width + foreach (Widget c in col) { + if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill) && ((c.Anchor & AnchorStyles.Left) != AnchorStyles.Left || (c.Anchor & AnchorStyles.Right) != AnchorStyles.Right || c.AutoSize == true)) + rowRight = c.Right + c.Margin.Right; + if (c.Left - c.Margin.Left < rowLeft) + rowLeft = c.Left - c.Margin.Left; + } + + // Find the widest Widget that is AutoSize = true + if (rowRight == 0) + foreach (Widget c in col) + if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill && c.AutoSize == true)) + rowRight = c.Right + c.Margin.Right; + + // Find the widest Widget that is Dock = Fill + if (rowRight == 0) + foreach (Widget c in col) + if (c.Right + c.Margin.Right > rowRight && (c.Dock == DockStyle.Fill)) + rowRight = c.Right + c.Margin.Right; + + // Set the new widths for each Widget + foreach (Widget c in col) + if (allDockFill && noAuto) + c.SetBoundsInternal (c.Left, c.Top, 0, c.Height, BoundsSpecified.None); + else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left) && ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) + c.SetBoundsInternal (c.Left, c.Top, rowRight - c.Left - c.Margin.Right, c.Height, BoundsSpecified.None); + else if (c.Dock == DockStyle.Right || ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) + c.SetBoundsInternal (rowRight - c.Margin.Right - c.Width, c.Top, c.Width, c.Height, BoundsSpecified.None); + else if (c.Dock == DockStyle.Left || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left)) + continue; + else + c.SetBoundsInternal (((rowRight - rowLeft) / 2) - (c.Width / 2) + (int)Math.Floor (((c.Margin.Left - c.Margin.Right) / 2.0)) + rowLeft, c.Top, c.Width, c.Height, BoundsSpecified.None); + + // Return rightmost x of this row used + if (rowRight == 0) + return rowLeft; + + return rowRight; + } + + #region Layout for ToolStrip + // ToolStrips use the same FlowLayout, but is made up of ToolStripItems which + // are Components instead of Widgets, so we have to duplicate this login for + // ToolStripItems. + private bool LayoutToolStrip (ToolStrip parent) + { + FlowLayoutSettings settings; + settings = (FlowLayoutSettings)parent.LayoutSettings; + + // Nothing to layout, exit method + if (parent.Items.Count == 0) return false; + + foreach (ToolStripItem tsi in parent.Items) + tsi.SetPlacement (ToolStripItemPlacement.Main); + + // Use DisplayRectangle so that parent.Padding is honored. + Rectangle parentDisplayRectangle = parent.DisplayRectangle; + Point currentLocation; + + // Set our starting point based on flow direction + switch (settings.FlowDirection) { + case FlowDirection.BottomUp: + currentLocation = new Point (parentDisplayRectangle.Left, parentDisplayRectangle.Bottom); + break; + case FlowDirection.LeftToRight: + case FlowDirection.TopDown: + default: + currentLocation = parentDisplayRectangle.Location; + break; + case FlowDirection.RightToLeft: + currentLocation = new Point (parentDisplayRectangle.Right, parentDisplayRectangle.Top); + break; + } + + bool forceFlowBreak = false; + + List rowWidgets = new List (); + + foreach (ToolStripItem c in parent.Items) { + // Only apply layout to visible Widgets. + if (!c.Available) { continue; } + + // Resize any AutoSize Widgets to their preferred size + if (c.AutoSize == true) + c.SetBounds (new Rectangle (c.Location, c.GetPreferredSize (c.Size))); + + switch (settings.FlowDirection) { + case FlowDirection.BottomUp: + // Decide if it's time to start a new column + // - Our settings must be WrapContents, and we ran out of room or the previous Widget's FlowBreak == true + if (settings.WrapContents) + if ((currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) { + + currentLocation.X = FinishColumn (rowWidgets); + currentLocation.Y = parentDisplayRectangle.Bottom; + + forceFlowBreak = false; + rowWidgets.Clear (); + } + + // Offset the right margin and set the Widget to our point + currentLocation.Offset (0, c.Margin.Bottom * -1); + c.Location = new Point (currentLocation.X + c.Margin.Left, currentLocation.Y - c.Height); + + // Update our location pointer + currentLocation.Y -= (c.Height + c.Margin.Top); + break; + case FlowDirection.LeftToRight: + default: + // Decide if it's time to start a new row + // - Our settings must be WrapContents, and we ran out of room or the previous Widget's FlowBreak == true + if (settings.WrapContents) + if ((parentDisplayRectangle.Width - currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) { + + currentLocation.Y = FinishRow (rowWidgets); + currentLocation.X = parentDisplayRectangle.Left; + + forceFlowBreak = false; + rowWidgets.Clear (); + } + + // Offset the left margin and set the Widget to our point + currentLocation.Offset (c.Margin.Left, 0); + c.Location = new Point (currentLocation.X, currentLocation.Y + c.Margin.Top); + + // Update our location pointer + currentLocation.X += c.Width + c.Margin.Right; + break; + case FlowDirection.RightToLeft: + // Decide if it's time to start a new row + // - Our settings must be WrapContents, and we ran out of room or the previous Widget's FlowBreak == true + if (settings.WrapContents) + if ((currentLocation.X) < (c.Width + c.Margin.Left + c.Margin.Right) || forceFlowBreak) { + + currentLocation.Y = FinishRow (rowWidgets); + currentLocation.X = parentDisplayRectangle.Right; + + forceFlowBreak = false; + rowWidgets.Clear (); + } + + // Offset the right margin and set the Widget to our point + currentLocation.Offset (c.Margin.Right * -1, 0); + c.Location = new Point (currentLocation.X - c.Width, currentLocation.Y + c.Margin.Top); + + // Update our location pointer + currentLocation.X -= (c.Width + c.Margin.Left); + break; + case FlowDirection.TopDown: + // Decide if it's time to start a new column + // - Our settings must be WrapContents, and we ran out of room or the previous Widget's FlowBreak == true + if (settings.WrapContents) + if ((parentDisplayRectangle.Height - currentLocation.Y) < (c.Height + c.Margin.Top + c.Margin.Bottom) || forceFlowBreak) { + + currentLocation.X = FinishColumn (rowWidgets); + currentLocation.Y = parentDisplayRectangle.Top; + + forceFlowBreak = false; + rowWidgets.Clear (); + } + + // Offset the top margin and set the Widget to our point + currentLocation.Offset (0, c.Margin.Top); + c.Location = new Point (currentLocation.X + c.Margin.Left, currentLocation.Y); + + // Update our location pointer + currentLocation.Y += c.Height + c.Margin.Bottom; + break; + } + // Add it to our list of things to adjust the second dimension of + rowWidgets.Add (c); + + // If user set a flowbreak on this Widget, it will be the last one in this row/column + if (settings.GetFlowBreak (c)) + forceFlowBreak = true; + } + + int final_height = 0; + + // Set the Widget heights/widths for the last row/column + if (settings.FlowDirection == FlowDirection.LeftToRight || settings.FlowDirection == FlowDirection.RightToLeft) + final_height = FinishRow (rowWidgets); + else + FinishColumn (rowWidgets); + + if (final_height > 0) + parent.SetBoundsInternal (parent.Left, parent.Top, parent.Width, final_height + parent.Padding.Bottom, BoundsSpecified.None); + + return false; + + } + + // Calculate the heights of the Widgets, returns the y coordinate of the greatest height it uses + private int FinishRow (List row) + { + // Nothing to do + if (row.Count == 0) return 0; + + int rowTop = int.MaxValue; + int rowBottom = 0; + bool allDockFill = true; + bool noAuto = true; + + // Special semantics if all Widgets are Dock.Fill/Anchor:Top,Bottom or AutoSize = true + foreach (ToolStripItem c in row) { + if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top && (c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) + allDockFill = false; + if (c.AutoSize == true) + noAuto = false; + } + + // Find the tallest Widget with a concrete height + foreach (ToolStripItem c in row) { + if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill) && ((c.Anchor & AnchorStyles.Top) != AnchorStyles.Top || (c.Anchor & AnchorStyles.Bottom) != AnchorStyles.Bottom || c.AutoSize == true)) + rowBottom = c.Bottom + c.Margin.Bottom; + if (c.Top - c.Margin.Top < rowTop) + rowTop = c.Top - c.Margin.Top; + } + + // Find the tallest Widget that is AutoSize = true + if (rowBottom == 0) + foreach (ToolStripItem c in row) + if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock != DockStyle.Fill && c.AutoSize == true)) + rowBottom = c.Bottom + c.Margin.Bottom; + + // Find the tallest Widget that is Dock = Fill + if (rowBottom == 0) + foreach (ToolStripItem c in row) + if (c.Bottom + c.Margin.Bottom > rowBottom && (c.Dock == DockStyle.Fill)) + rowBottom = c.Bottom + c.Margin.Bottom; + + // Set the new heights for each Widget + foreach (ToolStripItem c in row) + if (allDockFill && noAuto) + c.Height = 0; + else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top) && ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) + c.Height = rowBottom - c.Top - c.Margin.Bottom; + else if (c.Dock == DockStyle.Bottom || ((c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) + c.Top = rowBottom - c.Margin.Bottom - c.Height; + else if (c.Dock == DockStyle.Top || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top)) + continue; + else + c.Top = ((rowBottom - rowTop) / 2) - (c.Height / 2) + (int)Math.Floor (((c.Margin.Top - c.Margin.Bottom) / 2.0)) + rowTop; + + // Return bottom y of this row used + if (rowBottom == 0) + return rowTop; + + return rowBottom; + } + + // Calculate the widths of the Widgets, returns the x coordinate of the greatest width it uses + private int FinishColumn (List col) + { + // Nothing to do + if (col.Count == 0) return 0; + + int rowLeft = int.MaxValue; + int rowRight = 0; + bool allDockFill = true; + bool noAuto = true; + + // Special semantics if all Widgets are Dock.Fill/Anchor:Left,Right or AutoSize = true + foreach (ToolStripItem c in col) { + if (c.Dock != DockStyle.Fill && !((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left && (c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) + allDockFill = false; + if (c.AutoSize == true) + noAuto = false; + } + + // Find the widest Widget with a concrete width + foreach (ToolStripItem c in col) { + if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill) && ((c.Anchor & AnchorStyles.Left) != AnchorStyles.Left || (c.Anchor & AnchorStyles.Right) != AnchorStyles.Right || c.AutoSize == true)) + rowRight = c.Right + c.Margin.Right; + if (c.Left - c.Margin.Left < rowLeft) + rowLeft = c.Left - c.Margin.Left; + } + + // Find the widest Widget that is AutoSize = true + if (rowRight == 0) + foreach (ToolStripItem c in col) + if (c.Right + c.Margin.Right > rowRight && (c.Dock != DockStyle.Fill && c.AutoSize == true)) + rowRight = c.Right + c.Margin.Right; + + // Find the widest Widget that is Dock = Fill + if (rowRight == 0) + foreach (ToolStripItem c in col) + if (c.Right + c.Margin.Right > rowRight && (c.Dock == DockStyle.Fill)) + rowRight = c.Right + c.Margin.Right; + + // Set the new widths for each Widget + foreach (ToolStripItem c in col) + if (allDockFill && noAuto) + c.Width = 0; + else if (c.Dock == DockStyle.Fill || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left) && ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) + c.Width = rowRight - c.Left - c.Margin.Right; + else if (c.Dock == DockStyle.Right || ((c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) + c.Left = rowRight - c.Margin.Right - c.Width; + else if (c.Dock == DockStyle.Left || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left)) + continue; + else + c.Left = ((rowRight - rowLeft) / 2) - (c.Width / 2) + (int)Math.Floor (((c.Margin.Left - c.Margin.Right) / 2.0)) + rowLeft; + + // Return rightmost x of this row used + if (rowRight == 0) + return rowLeft; + + return rowRight; + } + #endregion + } +} diff --git a/source/ShiftUI/Internal/FlowLayoutSettings.cs b/source/ShiftUI/Internal/FlowLayoutSettings.cs new file mode 100644 index 0000000..3480165 --- /dev/null +++ b/source/ShiftUI/Internal/FlowLayoutSettings.cs @@ -0,0 +1,111 @@ +// +// FlowLayoutSettings.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using ShiftUI.Layout; +using System.ComponentModel; +using System.Collections.Generic; +using System; + +namespace ShiftUI +{ + [DefaultProperty ("FlowDirection")] + public class FlowLayoutSettings : LayoutSettings + { + private FlowDirection flow_direction; + private bool wrap_contents; + private LayoutEngine layout_engine; + private Dictionary flow_breaks; + private Widget owner; + + internal FlowLayoutSettings () : this (null) + { + } + + internal FlowLayoutSettings (Widget owner) + { + flow_breaks = new Dictionary (); + wrap_contents = true; + flow_direction = FlowDirection.LeftToRight; + this.owner = owner; + } + + #region Public Properties + [DefaultValue (FlowDirection.LeftToRight)] + public FlowDirection FlowDirection { + get { return this.flow_direction; } + set { + if (this.flow_direction != value) { + this.flow_direction = value; + if (owner != null) + owner.PerformLayout (owner, "FlowDirection"); + } + } + } + + public override LayoutEngine LayoutEngine { + get { + if (this.layout_engine == null) + this.layout_engine = new FlowLayout (); + + return this.layout_engine; + } + } + + [DefaultValue (true)] + public bool WrapContents { + get { return this.wrap_contents; } + set { + if (this.wrap_contents != value) { + this.wrap_contents = value; + if (owner != null) + owner.PerformLayout (owner, "WrapContents"); + } + } + } + #endregion + + #region Public Methods + public bool GetFlowBreak (Object child) + { + bool retval; + + if (flow_breaks.TryGetValue (child, out retval)) + return retval; + + return false; + } + + public void SetFlowBreak (Object child, bool value) + { + flow_breaks[child] = value; + if (owner != null) + owner.PerformLayout ((Widget)child, "FlowBreak"); + } + #endregion + } +} diff --git a/source/ShiftUI/Internal/GetChildAtPointSkip.cs b/source/ShiftUI/Internal/GetChildAtPointSkip.cs new file mode 100644 index 0000000..963406c --- /dev/null +++ b/source/ShiftUI/Internal/GetChildAtPointSkip.cs @@ -0,0 +1,41 @@ +// +// GetChildAtPointSkip.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + + +namespace ShiftUI +{ + [Flags] + public enum GetChildAtPointSkip + { + None = 0, + Invisible = 1, + Disabled = 2, + Transparent = 4 + } +} \ No newline at end of file diff --git a/source/ShiftUI/Internal/GridItem.cs b/source/ShiftUI/Internal/GridItem.cs new file mode 100644 index 0000000..3efac21 --- /dev/null +++ b/source/ShiftUI/Internal/GridItem.cs @@ -0,0 +1,114 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jonathan Chambers (jonathan.chambers@ansys.com) +// + +// NOT COMPLETE + +using System; +using System.Drawing; +using System.ComponentModel; + +namespace ShiftUI +{ + public abstract class GridItem + { + #region Fields + private bool expanded; + private object tag; + #endregion Fields + + #region Constructors + protected GridItem() + { + expanded = false; + } + #endregion // Constructors + + #region Public Instance Properties + public virtual bool Expandable + { + get { + return GridItems.Count > 1; + } + } + + public virtual bool Expanded + { + get { + return expanded; + } + + set { + expanded = value; + } + } + + public abstract GridItemCollection GridItems + { + get; + } + + public abstract GridItemType GridItemType + { + get; + } + + public abstract string Label + { + get; + } + + + public abstract GridItem Parent + { + get; + } + + + public abstract PropertyDescriptor PropertyDescriptor + { + get; + } + + [Localizable (false)] + [Bindable (true)] + [DefaultValue (null)] + [TypeConverter (typeof (StringConverter))] + public Object Tag { + get { return this.tag; } + set { this.tag = value; } + } + + public abstract object Value + { + get; + set; + } + #endregion + + #region Public Instance Methods + public abstract bool Select (); + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Internal/GridItemType.cs b/source/ShiftUI/Internal/GridItemType.cs new file mode 100644 index 0000000..821626a --- /dev/null +++ b/source/ShiftUI/Internal/GridItemType.cs @@ -0,0 +1,38 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jonathan Chambers (jonathan.chambers@ansys.com) +// + +// COMPLETE + +namespace ShiftUI +{ + public enum GridItemType + { + Property = 0, + Category = 1, + ArrayValue = 2, + Root = 3 + } +} + diff --git a/source/ShiftUI/Internal/GroupBoxRenderer.cs b/source/ShiftUI/Internal/GroupBoxRenderer.cs new file mode 100644 index 0000000..c0c9699 --- /dev/null +++ b/source/ShiftUI/Internal/GroupBoxRenderer.cs @@ -0,0 +1,157 @@ +// +// GroupBoxRenderer.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using ShiftUI.VisualStyles; +using System; + +namespace ShiftUI +{ + public sealed class GroupBoxRenderer + { + private static bool always_use_visual_styles = false; + + #region Private Constructor + private GroupBoxRenderer () { } + #endregion + + #region Public Static Methods + public static void DrawGroupBox (Graphics g, Rectangle bounds, GroupBoxState state) + { + DrawGroupBox (g, bounds, String.Empty, null, Color.Empty, TextFormatFlags.Default, state); + } + + public static void DrawGroupBox (Graphics g, Rectangle bounds, string groupBoxText, Font font, GroupBoxState state) + { + DrawGroupBox (g, bounds, groupBoxText, font, Color.Empty, TextFormatFlags.Default, state); + } + + public static void DrawGroupBox (Graphics g, Rectangle bounds, string groupBoxText, Font font, Color textColor, GroupBoxState state) + { + DrawGroupBox (g, bounds, groupBoxText, font, textColor, TextFormatFlags.Default, state); + } + + public static void DrawGroupBox (Graphics g, Rectangle bounds, string groupBoxText, Font font, TextFormatFlags flags, GroupBoxState state) + { + DrawGroupBox (g, bounds, groupBoxText, font, Color.Empty, flags, state); + } + + public static void DrawGroupBox (Graphics g, Rectangle bounds, string groupBoxText, Font font, Color textColor, TextFormatFlags flags, GroupBoxState state) + { + Size font_size = TextRenderer.MeasureText (groupBoxText, font); + + if (Application.RenderWithVisualStyles || always_use_visual_styles == true) { + VisualStyleRenderer vsr; + Rectangle new_bounds; + + switch (state) { + case GroupBoxState.Normal: + default: + vsr = new VisualStyleRenderer (VisualStyleElement.Button.GroupBox.Normal); + new_bounds = new Rectangle (bounds.Left, bounds.Top + (int)(font_size.Height / 2) - 1, bounds.Width, bounds.Height - (int)(font_size.Height / 2) + 1); + break; + case GroupBoxState.Disabled: + vsr = new VisualStyleRenderer (VisualStyleElement.Button.GroupBox.Disabled); + new_bounds = new Rectangle (bounds.Left, bounds.Top + (int)(font_size.Height / 2) - 2, bounds.Width, bounds.Height - (int)(font_size.Height / 2) + 2); + break; + } + + if (groupBoxText == String.Empty) + vsr.DrawBackground (g, bounds); + else + vsr.DrawBackgroundExcludingArea (g, new_bounds, new Rectangle (bounds.Left + 9, bounds.Top, font_size.Width - 3, font_size.Height)); + + if (textColor == Color.Empty) + textColor = vsr.GetColor (ColorProperty.TextColor); + + if (groupBoxText != String.Empty) + TextRenderer.DrawText (g, groupBoxText, font, new Point (bounds.Left + 8, bounds.Top), textColor, flags); + } + else { + // MS has a pretty big bug when rendering the non-visual styles group box. Instead of using the height + // part of the bounds as height, they use it as the bottom, so the boxes are drawn in completely different + // places. Rather than emulate this bug, we do it correctly. After googling for a while, I don't think + // anyone has ever actually used this class for anything, so it should be fine. :) + Rectangle new_bounds = new Rectangle (bounds.Left, bounds.Top + (int)(font_size.Height / 2), bounds.Width, bounds.Height - (int)(font_size.Height / 2)); + + // Don't paint over the background where we are going to put the text + Region old_clip = g.Clip; + g.SetClip (new Rectangle (bounds.Left + 9, bounds.Top, font_size.Width - 3, font_size.Height), System.Drawing.Drawing2D.CombineMode.Exclude); + + WidgetPaint.DrawBorder3D (g, new_bounds, Border3DStyle.Etched); + + g.Clip = old_clip; + + if (groupBoxText != String.Empty) { + if (textColor == Color.Empty) + textColor = state == GroupBoxState.Normal ? SystemColors.ControlText : + SystemColors.GrayText; + TextRenderer.DrawText (g, groupBoxText, font, new Point (bounds.Left + 8, bounds.Top), textColor, flags); + } + } + } + + public static bool IsBackgroundPartiallyTransparent (GroupBoxState state) + { + if (!VisualStyleRenderer.IsSupported) + return false; + + VisualStyleRenderer vsr; + + switch (state) { + case GroupBoxState.Normal: + default: + vsr = new VisualStyleRenderer (VisualStyleElement.Button.GroupBox.Normal); + break; + case GroupBoxState.Disabled: + vsr = new VisualStyleRenderer (VisualStyleElement.Button.GroupBox.Disabled); + break; + } + + return vsr.IsBackgroundPartiallyTransparent (); + } + + public static void DrawParentBackground (Graphics g, Rectangle bounds, Widget childControl) + { + if (!VisualStyleRenderer.IsSupported) + return; + + VisualStyleRenderer vsr = new VisualStyleRenderer (VisualStyleElement.Button.GroupBox.Normal); + + vsr.DrawParentBackground (g, bounds, childControl); + } + #endregion + + #region Public Static Properties + public static bool RenderMatchingApplicationState { + get { return !always_use_visual_styles; } + set { always_use_visual_styles = !value; } + } + #endregion + } +} diff --git a/source/ShiftUI/Internal/HIObjectHandler.cs b/source/ShiftUI/Internal/HIObjectHandler.cs new file mode 100644 index 0000000..ca7adc0 --- /dev/null +++ b/source/ShiftUI/Internal/HIObjectHandler.cs @@ -0,0 +1,57 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Geoff Norton +// +// + +using System; +using System.Runtime.InteropServices; + +namespace ShiftUI.CarbonInternal { + internal class HIObjectHandler : EventHandlerBase, IEventHandler { + internal const uint kEventHIObjectConstruct = 1; + internal const uint kEventHIObjectInitialize = 2; + internal const uint kEventHIObjectDestruct = 3; + + internal HIObjectHandler (XplatUICarbon driver) : base (driver) {} + + public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) { + switch (kind) { + case kEventHIObjectConstruct: + IntPtr v = IntPtr.Zero; + GetEventParameter (eventref, (uint)1751740265, (uint)1751740258, IntPtr.Zero, 4, IntPtr.Zero, ref v); + return false; + case kEventHIObjectInitialize: + CallNextEventHandler (callref, eventref); + return false; + case kEventHIObjectDestruct: + return false; + } + return false; + } + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int CallNextEventHandler (IntPtr callref, IntPtr eventref); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref IntPtr data); + } +} diff --git a/source/ShiftUI/Internal/HScrollProperties.cs b/source/ShiftUI/Internal/HScrollProperties.cs new file mode 100644 index 0000000..4eed2da --- /dev/null +++ b/source/ShiftUI/Internal/HScrollProperties.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Authors: +// Olivier Dufour olivier.duff@free.fr +// + +namespace ShiftUI +{ + public class HScrollProperties : ScrollProperties + { + public HScrollProperties (ScrollableWidget container) : base (container) + { + scroll_bar = container.hscrollbar; + } + } +} diff --git a/source/ShiftUI/Internal/Hwnd.cs b/source/ShiftUI/Internal/Hwnd.cs new file mode 100644 index 0000000..fcdc17d --- /dev/null +++ b/source/ShiftUI/Internal/Hwnd.cs @@ -0,0 +1,910 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005-2006 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// NOT COMPLETE + +using System; +using System.Collections; +using System.Drawing; +using System.Runtime.InteropServices; + +// NOTE: Possible optimization: +// Several properties calculate dimensions on the fly; instead; they can +// be stored in a field and only be recalculated when a style is changed (DefaultClientRect, for example) + +namespace ShiftUI { + internal class Hwnd : IDisposable { + #region Local Variables + private static Hashtable windows = new Hashtable(100, 0.5f); + //private const int menu_height = 14; // FIXME - Read this value from somewhere + + private IntPtr handle; + internal IntPtr client_window; + internal IntPtr whole_window; + internal IntPtr cursor; + internal Menu menu; + internal TitleStyle title_style; + internal FormBorderStyle border_style; + internal bool border_static; + internal int x; + internal int y; + internal int width; + internal int height; + internal bool allow_drop; + internal Hwnd parent; + internal bool visible; + internal bool mapped; + internal uint opacity; + internal bool enabled; + internal bool zero_sized; + internal ArrayList invalid_list; + internal Rectangle nc_invalid; + internal bool expose_pending; + internal bool nc_expose_pending; + internal bool configure_pending; + internal bool resizing_or_moving; // Used by the X11 backend to track form resize/move + internal bool reparented; + internal Stack drawing_stack; + internal object user_data; + internal Rectangle client_rectangle; + internal ArrayList marshal_free_list; + internal int caption_height; + internal int tool_caption_height; + internal bool whacky_wm; + internal bool fixed_size; + internal bool zombie; /* X11 only flag. true if the X windows have been destroyed but we haven't been Disposed */ + internal bool topmost; /* X11 only. */ + internal Region user_clip; + internal XEventQueue queue; + internal WindowExStyles initial_ex_style; + internal WindowStyles initial_style; + internal FormWindowState cached_window_state = (FormWindowState)(-1); /* X11 only field */ + internal Point previous_child_startup_location = new Point (int.MinValue, int.MinValue); + static internal Point previous_main_startup_location = new Point (int.MinValue, int.MinValue); + internal ArrayList children; + + [ThreadStatic] + private static Bitmap bmp; + [ThreadStatic] + private static Graphics bmp_g; + #endregion // Local Variables + + // locks for some operations (used in XplatUIX11.cs) + internal object configure_lock = new object (); + internal object expose_lock = new object (); + + #region Constructors and destructors + public Hwnd() { + x = 0; + y = 0; + width = 0; + height = 0; + visible = false; + menu = null; + border_style = FormBorderStyle.None; + client_window = IntPtr.Zero; + whole_window = IntPtr.Zero; + cursor = IntPtr.Zero; + handle = IntPtr.Zero; + parent = null; + invalid_list = new ArrayList(); + expose_pending = false; + nc_expose_pending = false; + enabled = true; + reparented = false; + client_rectangle = Rectangle.Empty; + marshal_free_list = new ArrayList(2); + opacity = 0xffffffff; + fixed_size = false; + drawing_stack = new Stack (); + children = new ArrayList (); + resizing_or_moving = false; + whacky_wm = false; + topmost = false; + } + + public void Dispose() { + expose_pending = false; + nc_expose_pending = false; + Parent = null; + lock (windows) { + windows.Remove(client_window); + windows.Remove(whole_window); + } + client_window = IntPtr.Zero; + whole_window = IntPtr.Zero; + zombie = false; + for (int i = 0; i < marshal_free_list.Count; i++) { + Marshal.FreeHGlobal((IntPtr)marshal_free_list[i]); + } + marshal_free_list.Clear(); + } + #endregion + + #region Static Methods + public static Hwnd ObjectFromWindow(IntPtr window) { + Hwnd rv; + lock (windows) { + rv = (Hwnd)windows[window]; + } + return rv; + } + + public static Hwnd ObjectFromHandle(IntPtr handle) { + //return (Hwnd)(((GCHandle)handle).Target); + Hwnd rv; + lock (windows) { + rv = (Hwnd)windows[handle]; + } + return rv; + } + + public static IntPtr HandleFromObject(Hwnd obj) { + return obj.handle; + } + + public static Hwnd GetObjectFromWindow(IntPtr window) { + Hwnd rv; + lock (windows) { + rv = (Hwnd)windows[window]; + } + return rv; + } + + public static IntPtr GetHandleFromWindow(IntPtr window) { + Hwnd hwnd; + + lock (windows) { + hwnd = (Hwnd)windows[window]; + } + if (hwnd != null) { + return hwnd.handle; + } else { + return IntPtr.Zero; + } + } + + public static Borders GetBorderWidth (CreateParams cp) + { + Borders border_size = new Borders (); + + Size windowborder = ThemeEngine.Current.BorderSize; /*new Size (1, 1);*/ // This is the only one that can be changed from the display properties in windows. + Size border = ThemeEngine.Current.BorderStaticSize; /*new Size (1, 1);*/ + Size clientedge = ThemeEngine.Current.Border3DSize; /*new Size (2, 2);*/ + Size thickframe = new Size (2 + windowborder.Width, 2 + windowborder.Height); + Size dialogframe = ThemeEngine.Current.BorderSizableSize; /* new Size (3, 3);*/ + + if (cp.IsSet (WindowStyles.WS_CAPTION)) { + border_size.Inflate (dialogframe); + } else if (cp.IsSet (WindowStyles.WS_BORDER)) { + if (cp.IsSet (WindowExStyles.WS_EX_DLGMODALFRAME)) { + if (cp.IsSet (WindowStyles.WS_THICKFRAME) && (cp.IsSet (WindowExStyles.WS_EX_STATICEDGE) || cp.IsSet (WindowExStyles.WS_EX_CLIENTEDGE))) { + border_size.Inflate (border); + } + } else { + border_size.Inflate (border); + } + } else if (cp.IsSet (WindowStyles.WS_DLGFRAME)) { + border_size.Inflate (dialogframe); + } + + if (cp.IsSet (WindowStyles.WS_THICKFRAME)) { + if (cp.IsSet (WindowStyles.WS_DLGFRAME)) { + border_size.Inflate (border); + } else { + border_size.Inflate (thickframe); + } + } + + bool only_small_border; + Size small_border = Size.Empty; + + only_small_border = cp.IsSet (WindowStyles.WS_THICKFRAME) || cp.IsSet (WindowStyles.WS_DLGFRAME); + if (only_small_border && cp.IsSet (WindowStyles.WS_THICKFRAME) && !cp.IsSet (WindowStyles.WS_BORDER) && !cp.IsSet (WindowStyles.WS_DLGFRAME)) { + small_border = border; + } + + if (cp.IsSet (WindowExStyles.WS_EX_CLIENTEDGE | WindowExStyles.WS_EX_DLGMODALFRAME)) { + border_size.Inflate (clientedge + (only_small_border ? small_border : dialogframe)); + } else if (cp.IsSet (WindowExStyles.WS_EX_STATICEDGE | WindowExStyles.WS_EX_DLGMODALFRAME)) { + border_size.Inflate (only_small_border ? small_border : dialogframe); + } else if (cp.IsSet (WindowExStyles.WS_EX_STATICEDGE | WindowExStyles.WS_EX_CLIENTEDGE)) { + border_size.Inflate (border + (only_small_border ? Size.Empty : clientedge)); + } else { + if (cp.IsSet (WindowExStyles.WS_EX_CLIENTEDGE)) { + border_size.Inflate (clientedge); + } + if (cp.IsSet (WindowExStyles.WS_EX_DLGMODALFRAME) && !cp.IsSet (WindowStyles.WS_DLGFRAME)) { + border_size.Inflate (cp.IsSet (WindowStyles.WS_THICKFRAME) ? border : dialogframe); + } + if (cp.IsSet (WindowExStyles.WS_EX_STATICEDGE)) { + if (cp.IsSet (WindowStyles.WS_THICKFRAME) || cp.IsSet (WindowStyles.WS_DLGFRAME)) { + border_size.Inflate (new Size (-border.Width, -border.Height)); + } else { + border_size.Inflate (border); + } + } + } + + return border_size; + } + + public static Rectangle GetWindowRectangle (CreateParams cp, Menu menu) + { + return GetWindowRectangle (cp, menu, Rectangle.Empty); + } + + public static Rectangle GetWindowRectangle (CreateParams cp, Menu menu, Rectangle client_rect) + { + Rectangle rect; + Borders borders; + + borders = GetBorders (cp, menu); + + rect = new Rectangle (Point.Empty, client_rect.Size); + rect.Y -= borders.top; + rect.Height += borders.top + borders.bottom; + rect.X -= borders.left; + rect.Width += borders.left + borders.right; + + #if debug + Console.WriteLine ("GetWindowRectangle ({0}, {1}, {2}): {3}", cp, menu != null, client_rect, rect); + #endif + return rect; + } + + public Rectangle GetClientRectangle (int width, int height) + { + CreateParams cp = new CreateParams (); + cp.WindowStyle = initial_style; + cp.WindowExStyle = initial_ex_style; + return GetClientRectangle (cp, menu, width, height); + } + + // This could be greatly optimized by caching the outputs and only updating when something is moved + // in the parent planar space. To do that we need to track z-order in the parent space as well + public ArrayList GetClippingRectangles () + { + ArrayList masks = new ArrayList (); + + if (x < 0) { + masks.Add (new Rectangle (0, 0, x*-1, Height)); + if (y < 0) { + masks.Add (new Rectangle (x*-1, 0, Width, y*-1)); + } + } else if (y < 0) { + masks.Add (new Rectangle (0, 0, Width, y*-1)); + } + + foreach (Hwnd child in children) { + if (child.visible) + masks.Add (new Rectangle (child.X, child.Y, child.Width, child.Height)); + } + + if (parent == null) { + return masks; + } + + ArrayList siblings = parent.children; + + foreach (Hwnd sibling in siblings) { + IntPtr sibling_handle = whole_window; + + if (sibling == this) + continue; + + // This entire method should be cached to find all higher views at the time of query + do { + sibling_handle = XplatUI.GetPreviousWindow (sibling_handle); + + if (sibling_handle == sibling.WholeWindow && sibling.visible) { + + Rectangle intersect = Rectangle.Intersect (new Rectangle (X, Y, Width, Height), new Rectangle (sibling.X, sibling.Y, sibling.Width, sibling.Height)); + + if (intersect == Rectangle.Empty) + continue; + + intersect.X -= X; + intersect.Y -= Y; + + masks.Add (intersect); + } + } while (sibling_handle != IntPtr.Zero); + } + + return masks; + } + + public static Borders GetBorders (CreateParams cp, Menu menu) + { + + Borders borders = new Borders (); + + if (menu != null) { + int menu_height = menu.Rect.Height; + if (menu_height == 0) + menu_height = ThemeEngine.Current.CalcMenuBarSize (GraphicsContext, menu, cp.Width); + borders.top += menu_height; + } + + if (cp.IsSet (WindowStyles.WS_CAPTION)) { + int caption_height; + if (cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) { + caption_height = ThemeEngine.Current.ToolWindowCaptionHeight; + } else { + caption_height = ThemeEngine.Current.CaptionHeight; + } + borders.top += caption_height; + } + + Borders border_width = GetBorderWidth (cp); + + borders.left += border_width.left; + borders.right += border_width.right; + borders.top += border_width.top; + borders.bottom += border_width.bottom; + + return borders; + } + + public static Rectangle GetClientRectangle(CreateParams cp, Menu menu, int width, int height) { + Rectangle rect; + Borders borders; + + borders = GetBorders (cp, menu); + + rect = new Rectangle(0, 0, width, height); + rect.Y += borders.top; + rect.Height -= borders.top + borders.bottom; + rect.X += borders.left; + rect.Width -= borders.left + borders.right; + + #if debug + Console.WriteLine ("GetClientRectangle ({0}, {1}, {2}, {3}): {4}", cp, menu != null, width, height, rect); + #endif + + return rect; + } + + public static Graphics GraphicsContext { + get { + if (bmp_g == null) { + bmp = new Bitmap (1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + bmp_g = Graphics.FromImage (bmp); + } + + return bmp_g; + } + } + #endregion // Static Methods + + #region Instance Properties + public FormBorderStyle BorderStyle { + get { + return border_style; + } + + set { + border_style = value; + } + } + + public Rectangle ClientRect { + get { + if (client_rectangle == Rectangle.Empty) { + return DefaultClientRect; + } + return client_rectangle; + } + + set { + client_rectangle = value; + } + } + + public IntPtr Cursor { + get { + return cursor; + } + + set { + cursor = value; + } + } + + public IntPtr ClientWindow { + get { + return client_window; + } + + set { + client_window = value; + handle = value; + + zombie = false; + + if (client_window != IntPtr.Zero) { + lock (windows) { + if (windows[client_window] == null) { + windows[client_window] = this; + } + } + } + } + } + + public Region UserClip { + get { + return user_clip; + } + + set { + user_clip = value; + } + } + + public Rectangle DefaultClientRect { + get { + // We pass a Zero for the menu handle so the menu size is + // not computed this is done via an WM_NCCALC + CreateParams cp = new CreateParams (); + Rectangle rect; + + cp.WindowStyle = initial_style; + cp.WindowExStyle = initial_ex_style; + + rect = GetClientRectangle (cp, null, width, height); + + return rect; + } + } + + public bool ExposePending { + get { + return expose_pending; + } + } + + public IntPtr Handle { + get { + if (handle == IntPtr.Zero) { + throw new ArgumentNullException("Handle", "Handle is not yet assigned, need a ClientWindow"); + } + return handle; + } + } + + public int Height { + get { + return height; + } + + set { + height = value; + } + } + + public Menu Menu { + get { + return menu; + } + + set { + menu = value; + } + } + + public bool Reparented { + get { + return reparented; + } + + set { + reparented = value; + } + } + + public uint Opacity { + get { + return opacity; + } + + set { + opacity = value; + } + } + + public XEventQueue Queue { + get { + return queue; + } + + set { + queue = value; + } + } + + public bool Enabled { + get { + if (!enabled) { + return false; + } + + if (parent != null) { + return parent.Enabled; + } + + return true; + } + + set { + enabled = value; + } + } + + public IntPtr EnabledHwnd { + get { + if (Enabled || parent == null) { + return Handle; + } + + return parent.EnabledHwnd; + } + } + + public Point MenuOrigin { + get { + Form frm = Widget.FromHandle (handle) as Form; + if (frm != null && frm.window_manager != null) + return frm.window_manager.GetMenuOrigin (); + + Point pt; + Size border_3D_size = ThemeEngine.Current.Border3DSize; + + pt = new Point(0, 0); + + if (border_style == FormBorderStyle.Fixed3D) { + pt.X += border_3D_size.Width; + pt.Y += border_3D_size.Height; + } else if (border_style == FormBorderStyle.FixedSingle) { + pt.X += 1; + pt.Y += 1; + } + + if (this.title_style == TitleStyle.Normal) { + pt.Y += caption_height; + } else if (this.title_style == TitleStyle.Normal) { + pt.Y += tool_caption_height; + } + + return pt; + } + } + + public Rectangle Invalid { + get { + if (invalid_list.Count == 0) + return Rectangle.Empty; + + Rectangle result = (Rectangle)invalid_list[0]; + for (int i = 1; i < invalid_list.Count; i ++) { + result = Rectangle.Union (result, (Rectangle)invalid_list[i]); + } + return result; + } + } + + public Rectangle[] ClipRectangles { + get { + return (Rectangle[]) invalid_list.ToArray (typeof (Rectangle)); + } + } + + public Rectangle NCInvalid { + get { return nc_invalid; } + set { nc_invalid = value; } + + } + + public bool NCExposePending { + get { + return nc_expose_pending; + } + } + + public Hwnd Parent { + get { + return parent; + } + + set { + if (parent != null) + parent.children.Remove (this); + parent = value; + if (parent != null) + parent.children.Add (this); + } + } + + public bool Mapped { + get { + if (!mapped) { + return false; + } + + if (parent != null) { + return parent.Mapped; + } + + return true; + } + + set { + mapped = value; + } + } + + public int CaptionHeight { + get { return caption_height; } + set { caption_height = value; } + } + + public int ToolCaptionHeight { + get { return tool_caption_height; } + set { tool_caption_height = value; } + } + + public TitleStyle TitleStyle { + get { + return title_style; + } + + set { + title_style = value; + } + } + + public object UserData { + get { + return user_data; + } + + set { + user_data = value; + } + } + + public IntPtr WholeWindow { + get { + return whole_window; + } + + set { + whole_window = value; + + zombie = false; + + if (whole_window != IntPtr.Zero) { + lock (windows) { + if (windows[whole_window] == null) { + windows[whole_window] = this; + } + } + } + } + } + + public int Width { + get { + return width; + } + + set { + width = value; + } + } + + public bool Visible { + get { + return visible; + } + + set { + visible = value; + } + } + + public int X { + get { + return x; + } + + set { + x = value; + } + } + + public int Y { + get { + return y; + } + + set { + y = value; + } + } + + #endregion // Instance properties + + #region Methods + public void AddInvalidArea(int x, int y, int width, int height) { + AddInvalidArea(new Rectangle(x, y, width, height)); + } + + public void AddInvalidArea(Rectangle rect) { + ArrayList tmp = new ArrayList (); + foreach (Rectangle r in invalid_list) { + if (!rect.Contains (r)) { + tmp.Add (r); + } + } + tmp.Add (rect); + invalid_list = tmp; + } + + public void ClearInvalidArea() { + invalid_list.Clear(); + expose_pending = false; + } + + public void AddNcInvalidArea(int x, int y, int width, int height) { + if (nc_invalid == Rectangle.Empty) { + nc_invalid = new Rectangle (x, y, width, height); + return; + } + + int right, bottom; + right = Math.Max (nc_invalid.Right, x + width); + bottom = Math.Max (nc_invalid.Bottom, y + height); + nc_invalid.X = Math.Min (nc_invalid.X, x); + nc_invalid.Y = Math.Min (nc_invalid.Y, y); + + nc_invalid.Width = right - nc_invalid.X; + nc_invalid.Height = bottom - nc_invalid.Y; + } + + public void AddNcInvalidArea(Rectangle rect) { + if (nc_invalid == Rectangle.Empty) { + nc_invalid = rect; + return; + } + nc_invalid = Rectangle.Union (nc_invalid, rect); + } + + public void ClearNcInvalidArea() { + nc_invalid = Rectangle.Empty; + nc_expose_pending = false; + } + + public override string ToString() { + return String.Format("Hwnd, Mapped:{3} ClientWindow:0x{0:X}, WholeWindow:0x{1:X}, Zombie={4}, Parent:[{2:X}]", client_window.ToInt32(), whole_window.ToInt32(), parent != null ? parent.ToString() : "", Mapped, zombie); + } + + public static Point GetNextStackedFormLocation (CreateParams cp, Hwnd parent_hwnd) + { + if (cp.control == null) + return Point.Empty; + + int X = cp.X; + int Y = cp.Y; + Point previous, next; + Rectangle within; + + if (parent_hwnd != null) { + Widget parent = cp.control.Parent; + previous = parent_hwnd.previous_child_startup_location; + if (parent_hwnd.client_rectangle == Rectangle.Empty && parent != null) { + within = parent.ClientRectangle; + } else { + within = parent_hwnd.client_rectangle; + } + } else { + previous = Hwnd.previous_main_startup_location; + within = ShiftUI.Screen.PrimaryScreen.WorkingArea; + } + + if (previous.X == int.MinValue || previous.Y == int.MinValue) { + next = Point.Empty; + } else { + next = new Point (previous.X + 22, previous.Y + 22); + } + + if (!within.Contains (next.X * 3, next.Y * 3)) { + next = Point.Empty; + } + + if (next == Point.Empty && cp.Parent == IntPtr.Zero) { + next = new Point (22, 22); + } + + if (parent_hwnd != null) { + parent_hwnd.previous_child_startup_location = next; + } else { + Hwnd.previous_main_startup_location = next; + } + + if (X == int.MinValue && Y == int.MinValue) { + X = next.X; + Y = next.Y; + } + + return new Point (X, Y); + } + + #endregion // Methods + + internal struct Borders + { + public int top; + public int bottom; + public int left; + public int right; + + public void Inflate (Size size) + { + left += size.Width; + right += size.Width; + top += size.Height; + bottom += size.Height; + } + + public override string ToString () + { + return string.Format("{{top={0}, bottom={1}, left={2}, right={3}}}", top, bottom, left, right); + } + + public static bool operator == (Borders a, Borders b) + { + return (a.left == b.left && a.right == b.right && a.top == b.top && a.bottom == b.bottom); + } + + public static bool operator != (Borders a, Borders b) + { + return !(a == b); + } + + public override bool Equals (object obj) + { + return base.Equals (obj); + } + + public override int GetHashCode () + { + return base.GetHashCode (); + } + } + } +} diff --git a/source/ShiftUI/Internal/IBindableComponent.cs b/source/ShiftUI/Internal/IBindableComponent.cs new file mode 100644 index 0000000..8c7edaa --- /dev/null +++ b/source/ShiftUI/Internal/IBindableComponent.cs @@ -0,0 +1,34 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. (http://www.novell.com) +// + + +using System; +using System.ComponentModel; + +namespace ShiftUI { + + public interface IBindableComponent : IComponent, IDisposable + { + BindingContext BindingContext { get; set; } + WidgetBindingsCollection DataBindings { get; } + } +} diff --git a/source/ShiftUI/Internal/IBounds.cs b/source/ShiftUI/Internal/IBounds.cs new file mode 100644 index 0000000..923a029 --- /dev/null +++ b/source/ShiftUI/Internal/IBounds.cs @@ -0,0 +1,40 @@ +// +// IBounds.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2008 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace ShiftUI +{ + interface IBounds + { + Rectangle Bounds { get; } + } +} diff --git a/source/ShiftUI/Internal/IButtonControl.cs b/source/ShiftUI/Internal/IButtonControl.cs new file mode 100644 index 0000000..33d9fc8 --- /dev/null +++ b/source/ShiftUI/Internal/IButtonControl.cs @@ -0,0 +1,40 @@ +// +// ShiftUI.IButtonWidget.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// +// + + +// COMPLETE + +namespace ShiftUI +{ + + public interface IButtonWidget + { + DialogResult DialogResult {get; set;} + void NotifyDefault (bool value); + void PerformClick (); + } +} diff --git a/source/ShiftUI/Internal/ICommandExecutor.cs b/source/ShiftUI/Internal/ICommandExecutor.cs new file mode 100644 index 0000000..dfe1573 --- /dev/null +++ b/source/ShiftUI/Internal/ICommandExecutor.cs @@ -0,0 +1,34 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// + +// COMPLETE + +namespace ShiftUI { + public interface ICommandExecutor { + #region Public Instance Methods + void Execute(); + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Internal/IComponentEditorPageSite.cs b/source/ShiftUI/Internal/IComponentEditorPageSite.cs new file mode 100644 index 0000000..fd9eaa9 --- /dev/null +++ b/source/ShiftUI/Internal/IComponentEditorPageSite.cs @@ -0,0 +1,34 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok (pbartok@novell.com); +// + +// COMPLETE + +namespace ShiftUI { + + public interface IComponentEditorPageSite { + Widget GetWidget(); + void SetDirty(); + } +} diff --git a/source/ShiftUI/Internal/IContainerControl.cs b/source/ShiftUI/Internal/IContainerControl.cs new file mode 100644 index 0000000..da5cc19 --- /dev/null +++ b/source/ShiftUI/Internal/IContainerControl.cs @@ -0,0 +1,39 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +namespace ShiftUI { + public interface IContainerWidget { + #region Public Instance Properties + Widget ActiveWidget {get; set;} + #endregion // Public Instance Properties + + #region Public Instance Methods + bool ActivateWidget(Widget active); + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Internal/ICurrencyManagerProvider.cs b/source/ShiftUI/Internal/ICurrencyManagerProvider.cs new file mode 100644 index 0000000..a3993cc --- /dev/null +++ b/source/ShiftUI/Internal/ICurrencyManagerProvider.cs @@ -0,0 +1,32 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. (http://www.novell.com) +// + + +namespace ShiftUI { + + public interface ICurrencyManagerProvider { + CurrencyManager CurrencyManager { get; } + + CurrencyManager GetRelatedCurrencyManager (string dataMember); + } + +} diff --git a/source/ShiftUI/Internal/IDataGridColumnStyleEditingNotificationService.cs b/source/ShiftUI/Internal/IDataGridColumnStyleEditingNotificationService.cs new file mode 100644 index 0000000..f55a6c6 --- /dev/null +++ b/source/ShiftUI/Internal/IDataGridColumnStyleEditingNotificationService.cs @@ -0,0 +1,35 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +namespace ShiftUI { + public interface IDataGridColumnStyleEditingNotificationService { + #region Public Instance Methods + void ColumnStartedEditing(Widget editingWidget); + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Internal/IDataGridEditingService.cs b/source/ShiftUI/Internal/IDataGridEditingService.cs new file mode 100644 index 0000000..41f9c9a --- /dev/null +++ b/source/ShiftUI/Internal/IDataGridEditingService.cs @@ -0,0 +1,36 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// +// Peter Bartok pbartok@novell.com +// + +// COMPLETE + +namespace ShiftUI { + public interface IDataGridEditingService { + #region Public Instance Methods + bool BeginEdit(DataGridColumnStyle gridColumn, int rowNumber); + bool EndEdit(DataGridColumnStyle gridColumn, int rowNumber, bool shouldAbort); + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Internal/IDataGridViewEditingCell.cs b/source/ShiftUI/Internal/IDataGridViewEditingCell.cs new file mode 100644 index 0000000..30fc6e4 --- /dev/null +++ b/source/ShiftUI/Internal/IDataGridViewEditingCell.cs @@ -0,0 +1,41 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Author: +// Pedro Martínez Juliá +// + + +namespace ShiftUI { + + public interface IDataGridViewEditingCell { + + object EditingCellFormattedValue { get; set; } + + bool EditingCellValueChanged { get; set; } + + object GetEditingCellFormattedValue (DataGridViewDataErrorContexts context); + + void PrepareEditingCellForEdit (bool selectAll); + + } + +} diff --git a/source/ShiftUI/Internal/IDataGridViewEditingControl.cs b/source/ShiftUI/Internal/IDataGridViewEditingControl.cs new file mode 100644 index 0000000..8b102d0 --- /dev/null +++ b/source/ShiftUI/Internal/IDataGridViewEditingControl.cs @@ -0,0 +1,53 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Author: +// Pedro Martínez Juliá +// + + +namespace ShiftUI { + + public interface IDataGridViewEditingWidget { + + DataGridView EditingWidgetDataGridView {get; set;} + + object EditingWidgetFormattedValue {get; set;} + + int EditingWidgetRowIndex {get; set;} + + bool EditingWidgetValueChanged {get; set;} + + Cursor EditingPanelCursor {get;} + + bool RepositionEditingWidgetOnValueChange {get;} + + void ApplyCellStyleToEditingWidget (DataGridViewCellStyle dataGridViewCellStyle); + + bool EditingWidgetWantsInputKey (Keys keyData, bool dataGridViewWantsInputKey); + + object GetEditingWidgetFormattedValue (DataGridViewDataErrorContexts context); + + void PrepareEditingWidgetForEdit (bool selectAll); + + } + +} diff --git a/source/ShiftUI/Internal/IDataObject.cs b/source/ShiftUI/Internal/IDataObject.cs new file mode 100644 index 0000000..7ce0d80 --- /dev/null +++ b/source/ShiftUI/Internal/IDataObject.cs @@ -0,0 +1,54 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + [ComVisible(true)] + public interface IDataObject { + #region Public Instance Methods + object GetData(string format); + object GetData(string format, bool autoConvert); + object GetData(Type format); + + bool GetDataPresent(string format); + bool GetDataPresent(string format, bool autoConvert); + bool GetDataPresent(Type format); + + string[] GetFormats(); + string[] GetFormats(bool autoConvert); + + void SetData(object data); + void SetData(string format, bool autoConvert, object data); + void SetData(string format, object data); + void SetData(Type format, object data); + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Internal/IDropTarget.cs b/source/ShiftUI/Internal/IDropTarget.cs new file mode 100644 index 0000000..2589634 --- /dev/null +++ b/source/ShiftUI/Internal/IDropTarget.cs @@ -0,0 +1,36 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// + +using System; +using System.Drawing; +using System.ComponentModel; + +namespace ShiftUI { + + public interface IDropTarget { + void OnDragDrop (DragEventArgs e); + void OnDragEnter (DragEventArgs e); + void OnDragLeave (EventArgs e); + void OnDragOver (DragEventArgs e); + } + +} diff --git a/source/ShiftUI/Internal/IEventHandler.cs b/source/ShiftUI/Internal/IEventHandler.cs new file mode 100644 index 0000000..e46175e --- /dev/null +++ b/source/ShiftUI/Internal/IEventHandler.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Geoff Norton +// +// + +using System; + +namespace ShiftUI.CarbonInternal { + internal interface IEventHandler { + bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg); + } +} diff --git a/source/ShiftUI/Internal/IFeatureSupport.cs b/source/ShiftUI/Internal/IFeatureSupport.cs new file mode 100644 index 0000000..748b510 --- /dev/null +++ b/source/ShiftUI/Internal/IFeatureSupport.cs @@ -0,0 +1,38 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE +using System; + +namespace ShiftUI { + public interface IFeatureSupport { + #region Public Instance Methods + Version GetVersionPresent(object feature); + bool IsPresent(object feature); + bool IsPresent(object feature, Version minimumVersion); + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Internal/IFileReaderService.cs b/source/ShiftUI/Internal/IFileReaderService.cs new file mode 100644 index 0000000..abee90e --- /dev/null +++ b/source/ShiftUI/Internal/IFileReaderService.cs @@ -0,0 +1,37 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +using System.IO; + +namespace ShiftUI { + public interface IFileReaderService { + #region Public Instance Methods + Stream OpenFileFromSource(string relativePath); + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Internal/IKeyFilter.cs b/source/ShiftUI/Internal/IKeyFilter.cs new file mode 100644 index 0000000..ecc2396 --- /dev/null +++ b/source/ShiftUI/Internal/IKeyFilter.cs @@ -0,0 +1,32 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2008 Novell, Inc. +// +// Authors: +// Mike Gorse mgorse@novell.com +// +// + + +namespace ShiftUI { + internal interface IKeyFilter { + bool PreFilterKey(KeyFilterData data); + } +} diff --git a/source/ShiftUI/Internal/IMessageFilter.cs b/source/ShiftUI/Internal/IMessageFilter.cs new file mode 100644 index 0000000..d55394f --- /dev/null +++ b/source/ShiftUI/Internal/IMessageFilter.cs @@ -0,0 +1,34 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +namespace ShiftUI { + public interface IMessageFilter { + bool PreFilterMessage(ref Message m); + } +} diff --git a/source/ShiftUI/Internal/IToolStripData.cs b/source/ShiftUI/Internal/IToolStripData.cs new file mode 100644 index 0000000..c01afd3 --- /dev/null +++ b/source/ShiftUI/Internal/IToolStripData.cs @@ -0,0 +1,41 @@ +// +// IToolStripData.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2008 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace ShiftUI +{ + interface IToolStripData + { + bool IsCurrentlyDragging { get; } + bool Stretch { get; set; } + } +} diff --git a/source/ShiftUI/Internal/IWin32Window.cs b/source/ShiftUI/Internal/IWin32Window.cs new file mode 100644 index 0000000..73bfc31 --- /dev/null +++ b/source/ShiftUI/Internal/IWin32Window.cs @@ -0,0 +1,44 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + [ComVisible(true)] + [Guid("458AB8A2-A1EA-4d7b-8EBE-DEE5D3D9442C")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IWin32Window { + #region Public Instance Properties + IntPtr Handle { + get; + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Internal/IWindowTarget.cs b/source/ShiftUI/Internal/IWindowTarget.cs new file mode 100644 index 0000000..0157773 --- /dev/null +++ b/source/ShiftUI/Internal/IWindowTarget.cs @@ -0,0 +1,34 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +using System; + +namespace ShiftUI { + public interface IWindowTarget { + #region Public Instance Methods + void OnHandleChange(IntPtr newHandle); + void OnMessage(ref Message m); + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Internal/ImageIndexConverter.cs b/source/ShiftUI/Internal/ImageIndexConverter.cs new file mode 100644 index 0000000..b2783e9 --- /dev/null +++ b/source/ShiftUI/Internal/ImageIndexConverter.cs @@ -0,0 +1,102 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Ravindra rkumar@novell.com +// + + +// COMPLETE + +using System; +using System.Drawing; +using System.ComponentModel; +using System.Collections; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + public class ImageIndexConverter : Int32Converter + { + #region Constructors + + public ImageIndexConverter () { } + + #endregion Constructors + + #region Protected Properties + + protected virtual bool IncludeNoneAsStandardValue { + get { return true; } + } + + #endregion Protected Properties + + #region Public Methods + + public override object ConvertFrom (ITypeDescriptorContext context, CultureInfo culture, object value) + { + string indexStr; + if (value != null && value is string) { + indexStr = (string) value; + if (indexStr == "(none)") + return -1; + else + return Int32.Parse (indexStr); + } + else + return base.ConvertFrom (context, culture, value); + } + + public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, + object value, Type destinationType) + { + if (value != null && destinationType == typeof (string)) { + if (value is int && (int) value == -1) + return "(none)"; + else + return value.ToString (); + } + else + return base.ConvertTo (context, culture, value, destinationType); + } + + public override StandardValuesCollection GetStandardValues (ITypeDescriptorContext context) + { + int [] stdVal = new int [] {-1}; + return new TypeConverter.StandardValuesCollection (stdVal); + } + + public override bool GetStandardValuesExclusive (ITypeDescriptorContext context) + { + return false; + } + + public override bool GetStandardValuesSupported (ITypeDescriptorContext context) + { + return true; + } + + #endregion Public Methods + } +} diff --git a/source/ShiftUI/Internal/ImageKeyConverter.cs b/source/ShiftUI/Internal/ImageKeyConverter.cs new file mode 100644 index 0000000..e70b5e1 --- /dev/null +++ b/source/ShiftUI/Internal/ImageKeyConverter.cs @@ -0,0 +1,97 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Jonathan Pobst monkey@jpobst.com +// + +using System.Drawing; +using System.ComponentModel; +using System.Collections; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI +{ + public class ImageKeyConverter : StringConverter + { + #region Constructors + public ImageKeyConverter () { } + #endregion Constructors + + #region Protected Properties + protected virtual bool IncludeNoneAsStandardValue { + get { return true; } + } + #endregion Protected Properties + + #region Public Methods + public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof (string)) + return true; + + return false; + } + + public override object ConvertFrom (ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value != null && value is string) + return (string) value; + else + return base.ConvertFrom (context, culture, value); + } + + public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, + object value, Type destinationType) + { + if (value == null) + return "(none)"; + else if (destinationType == typeof (string)) { + if (value is string && (string) value == string.Empty) + return "(none)"; + else + return value.ToString (); + } + else + return base.ConvertTo (context, culture, value, destinationType); + } + + public override StandardValuesCollection GetStandardValues (ITypeDescriptorContext context) + { + string[] stdVal = new string[] { string.Empty }; + return new TypeConverter.StandardValuesCollection (stdVal); + } + + public override bool GetStandardValuesExclusive (ITypeDescriptorContext context) + { + return true; + } + + public override bool GetStandardValuesSupported (ITypeDescriptorContext context) + { + return true; + } + #endregion Public Methods + } +} diff --git a/source/ShiftUI/Internal/ImageList.cs b/source/ShiftUI/Internal/ImageList.cs new file mode 100644 index 0000000..b983455 --- /dev/null +++ b/source/ShiftUI/Internal/ImageList.cs @@ -0,0 +1,1073 @@ +// +// ShiftUI.ImageList.cs +// +// Authors: +// Peter Bartok +// Kornél Pál +// +// Copyright (C) 2004-2005 Novell, Inc. +// Copyright (C) 2005 Kornél Pál +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +// COMPLETE + +// +// Differences between MS.NET ImageList and this implementation: +// +// This is a fully managed image list implementation. +// +// Images are stored as Format32bppArgb internally but ColorDepth is applied +// to the colors of images. Images[index] returns a Format32bppArgb copy of +// the image so this difference is only internal. +// +// MS.NET has no alpha channel support (except for icons in 32-bit mode with +// comctl32.dll version 6.0) but this implementation has full alpha channel +// support in 32-bit mode. +// +// Handle should be an HIMAGELIST returned by ImageList_Create. This +// implementation uses (IntPtr)(-1) that is a non-zero but invalid handle. +// +// MS.NET destroys handles using the garbage collector this implementation +// does the same with Image objects stored in an ArrayList. +// +// MS.NET 1.x shares the same HIMAGELIST between ImageLists that were +// initialized from the same ImageListStreamer and doesn't update ImageSize +// and ColorDepth that are treated as bugs and MS.NET 2.0 behavior is +// implemented. +// +// MS.NET 2.0 does not clear keys when handle is destroyed that is treated as +// a bug. +// + +using System.Collections; +using System.Collections.Specialized; +using System.ComponentModel; +using System.ComponentModel.Design.Serialization; +using System.Drawing; +using System.Drawing.Design; +using System.Drawing.Imaging; +using System.Globalization; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI +{ + [DefaultProperty("Images")] + //[Designer("ShiftUI.Design.ImageListDesigner, " + Consts.AssemblySystem_Design)] + //[DesignerSerializer("ShiftUI.Design.ImageListCodeDomSerializer, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)] + [ToolboxItemFilter("ShiftUI")] + [TypeConverter(typeof(ImageListConverter))] + public sealed class ImageList : System.ComponentModel.Component + { + #region Private Fields + private const ColorDepth DefaultColorDepth = ColorDepth.Depth8Bit; + private static readonly Size DefaultImageSize = new Size(16, 16); + private static readonly Color DefaultTransparentColor = Color.Transparent; + private object tag; + private readonly ImageCollection images; + #endregion // Private Fields + + #region Sub-classes + //[Editor("ShiftUI.Design.ImageCollectionEditor, " + Consts.AssemblySystem_Design, typeof(UITypeEditor))] + public sealed class ImageCollection : IList, ICollection, IEnumerable + { + private const int AlphaMask = unchecked((int)0xFF000000); + + private static class IndexedColorDepths + { + internal static readonly ColorPalette Palette4Bit; + internal static readonly ColorPalette Palette8Bit; + private static readonly int[] squares; + + static IndexedColorDepths() + { + Bitmap bitmap; + int index; + + bitmap = new Bitmap(1, 1, PixelFormat.Format4bppIndexed); + Palette4Bit = bitmap.Palette; + bitmap.Dispose(); + + bitmap = new Bitmap(1, 1, PixelFormat.Format8bppIndexed); + Palette8Bit = bitmap.Palette; + bitmap.Dispose(); + + squares = new int[511]; + for (index = 0; index < 256; index++) + squares[255 + index] = squares[255 - index] = index * index; + } + + internal static int GetNearestColor(Color[] palette, int color) + { + int index; + int count; + int red; + int green; + int blue; + int nearestColor; + int minDistance; + int distance; + + count = palette.Length; + for (index = 0; index < count; index++) + if (palette[index].ToArgb() == color) + return color; + + red = unchecked((int)(unchecked((uint)color) >> 16) & 0xFF); + green = unchecked((int)(unchecked((uint)color) >> 8) & 0xFF); + blue = color & 0xFF; + nearestColor = AlphaMask; + minDistance = int.MaxValue; + + for (index = 0; index < count; index++) + if ((distance = squares[255 + palette[index].R - red] + squares[255 + palette[index].G - green] + squares[255 + palette[index].B - blue]) < minDistance) { + nearestColor = palette[index].ToArgb(); + minDistance = distance; + } + + return nearestColor; + } + } + + [Flags()] + private enum ItemFlags + { + None = 0, + UseTransparentColor = 1, + ImageStrip = 2 + } + + private sealed class ImageListItem + { + internal readonly object Image; + internal readonly ItemFlags Flags; + internal readonly Color TransparentColor; + internal readonly int ImageCount = 1; + + internal ImageListItem(Icon value) + { + if (value == null) + throw new ArgumentNullException("value"); + + // Icons are cloned. + this.Image = (Icon)value.Clone(); + } + + internal ImageListItem(Image value) + { + if (value == null) + throw new ArgumentNullException("value"); + + if (!(value is Bitmap)) + throw new ArgumentException("Image must be a Bitmap."); + + // Images are not cloned. + this.Image = value; + } + + internal ImageListItem(Image value, Color transparentColor) : this(value) + { + this.Flags = ItemFlags.UseTransparentColor; + this.TransparentColor = transparentColor; + } + + internal ImageListItem(Image value, int imageCount) : this(value) + { + this.Flags = ItemFlags.ImageStrip; + this.ImageCount = imageCount; + } + } + + #region ImageCollection Private Fields + private ColorDepth colorDepth = DefaultColorDepth; + private Size imageSize = DefaultImageSize; + private Color transparentColor = DefaultTransparentColor; + private ArrayList list = new ArrayList(); + private ArrayList keys = new ArrayList(); + private int count; + private bool handleCreated; + private int lastKeyIndex = -1; + private readonly ImageList owner; + #endregion // ImageCollection Private Fields + + #region ImageCollection Internal Constructors + // For use in ImageList + internal ImageCollection(ImageList owner) + { + this.owner = owner; + } + #endregion // ImageCollection Internal Constructor + + #region ImageCollection Internal Instance Properties + // For use in ImageList + internal ColorDepth ColorDepth { + get { + return this.colorDepth; + } + + set { + if (!Enum.IsDefined(typeof(ColorDepth), value)) + throw new InvalidEnumArgumentException("value", (int)value, typeof(ColorDepth)); + + if (this.colorDepth != value) { + this.colorDepth = value; + RecreateHandle(); + } + } + } + + // For use in ImageList + internal IntPtr Handle { + get { + CreateHandle(); + return (IntPtr)(-1); + } + } + + // For use in ImageList + internal bool HandleCreated { + get { + return this.handleCreated; + } + } + + // For use in ImageList + internal Size ImageSize { + get { + return this.imageSize; + } + + set { + if (value.Width < 1 || value.Width > 256 || value.Height < 1 || value.Height > 256) + throw new ArgumentException("ImageSize.Width and Height must be between 1 and 256", "value"); + + if (this.imageSize != value) { + this.imageSize = value; + RecreateHandle(); + } + } + } + + // For use in ImageList + internal ImageListStreamer ImageStream { + get { + return this.Empty ? null : new ImageListStreamer(this); + } + + set { + int index; + Image[] streamImages; + + if (value == null) { + if (this.handleCreated) + DestroyHandle(); + else + this.Clear(); + } + // Only deserialized ImageListStreamers are used. + else if ((streamImages = value.Images) != null) { + this.list = new ArrayList(streamImages.Length); + this.count = 0; + this.handleCreated = true; + this.keys = new ArrayList(streamImages.Length); + + for (index = 0; index < streamImages.Length; index++) { + list.Add((Image)streamImages[index].Clone()); + keys.Add(null); + } + + // Invalid ColorDepth values are ignored. + if (Enum.IsDefined(typeof(ColorDepth), value.ColorDepth)) + this.colorDepth = (ColorDepth)value.ColorDepth; + this.imageSize = value.ImageSize; + + // Event is raised even when handle was not created yet. + owner.OnRecreateHandle(); + } + } + } + + // For use in ImageList + internal Color TransparentColor { + get { + return this.transparentColor; + } + + set { + this.transparentColor = value; + } + } + #endregion // ImageCollection Internal Instance Properties + + #region ImageCollection Public Instance Properties + [Browsable(false)] + public int Count { + get { + return this.handleCreated ? list.Count : this.count; + } + } + + public bool Empty { + get { + return this.Count == 0; + } + } + + public bool IsReadOnly { + get { + return false; + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Image this[int index] { + get { + return (Image)GetImage(index).Clone(); + } + + set { + Image image; + + if (index < 0 || index >= this.Count) + throw new ArgumentOutOfRangeException("index"); + + if (value == null) + throw new ArgumentNullException("value"); + + if (!(value is Bitmap)) + throw new ArgumentException("Image must be a Bitmap."); + + image = CreateImage(value, this.transparentColor); + CreateHandle(); + list[index] = image; + } + } + + public Image this[string key] { + get { + int index; + + return (index = IndexOfKey(key)) == -1 ? null : this[index]; + } + } + + public StringCollection Keys { + get { + int index; + string key; + StringCollection keyCollection; + + // Returns all keys even when there are more keys than + // images. Null keys are returned as empty strings. + + keyCollection = new StringCollection(); + for (index = 0; index < keys.Count; index++) + keyCollection.Add(((key = (string)keys[index]) == null || key.Length == 0) ? string.Empty : key); + + return keyCollection; + } + } + #endregion // ImageCollection Public Instance Properties + + #region ImageCollection Private Static Methods + private static bool CompareKeys(string key1, string key2) + { + // Keys are case-insensitive and keys with different length + // are not equal even when string.Compare treats them equal. + + if (key1 == null || key2 == null || key1.Length != key2.Length) + return false; + + return string.Compare(key1, key2, true, CultureInfo.InvariantCulture) == 0; + } + #endregion // ImageCollection Private Static Methods + + #region ImageCollection Private Instance Methods + private int AddItem(string key, ImageListItem item) + { + int itemIndex; + int index; + + if (this.handleCreated) + itemIndex = AddItemInternal(item); + else { + // Image strips are counted as a single item in the return + // value of Add and AddStrip until handle is created. + + itemIndex = list.Add(item); + this.count += item.ImageCount; + } + + if ((item.Flags & ItemFlags.ImageStrip) == 0) + keys.Add(key); + else + for (index = 0; index < item.ImageCount; index++) + keys.Add(null); + + return itemIndex; + } + + internal event EventHandler Changed; + + private int AddItemInternal(ImageListItem item) + { + if (Changed != null) + Changed (this, EventArgs.Empty); + + if (item.Image is Icon) { + int imageWidth; + int imageHeight; + Bitmap bitmap; + Graphics graphics; + + bitmap = new Bitmap(imageWidth = this.imageSize.Width, imageHeight = this.imageSize.Height, PixelFormat.Format32bppArgb); + graphics = Graphics.FromImage(bitmap); + graphics.DrawIcon((Icon)item.Image, new Rectangle(0, 0, imageWidth, imageHeight)); + graphics.Dispose(); + + ReduceColorDepth(bitmap); + return list.Add(bitmap); + } + else if ((item.Flags & ItemFlags.ImageStrip) == 0) + return list.Add(CreateImage((Image)item.Image, (item.Flags & ItemFlags.UseTransparentColor) == 0 ? this.transparentColor : item.TransparentColor)); + else { + int imageX; + int width; + int imageWidth; + int imageHeight; + int index; + Image image; + Bitmap bitmap; + Graphics graphics; + Rectangle imageRect; + ImageAttributes imageAttributes; + + // When ImageSize was changed after adding image strips + // Count will return invalid values based on old ImageSize + // but when creating handle either ArgumentException will + // be thrown or image strip will be added according to the + // new ImageSize. This can result in image count + // difference that can result in exceptions in methods + // that use Count before creating handle. In addition this + // can result in the loss of sync with keys. When doing + // the same after handle was created there are no problems + // as handle will be recreated after changing ImageSize + // that results in the loss of images added previously. + + if ((width = (image = (Image)item.Image).Width) == 0 || (width % (imageWidth = this.imageSize.Width)) != 0) + throw new ArgumentException("Width of image strip must be a positive multiple of ImageSize.Width.", "value"); + + if (image.Height != (imageHeight = this.imageSize.Height)) + throw new ArgumentException("Height of image strip must be equal to ImageSize.Height.", "value"); + + imageRect = new Rectangle(0, 0, imageWidth, imageHeight); + if (this.transparentColor.A == 0) + imageAttributes = null; + else { + imageAttributes = new ImageAttributes(); + imageAttributes.SetColorKey(this.transparentColor, this.transparentColor); + } + + index = list.Count; + for (imageX = 0; imageX < width; imageX += imageWidth) { + bitmap = new Bitmap(imageWidth, imageHeight, PixelFormat.Format32bppArgb); + graphics = Graphics.FromImage(bitmap); + graphics.DrawImage(image, imageRect, imageX, 0, imageWidth, imageHeight, GraphicsUnit.Pixel, imageAttributes); + graphics.Dispose(); + + ReduceColorDepth(bitmap); + list.Add(bitmap); + } + + if (imageAttributes != null) + imageAttributes.Dispose(); + + return index; + } + } + + private void CreateHandle() + { + int index; + ArrayList items; + + if (!this.handleCreated) { + items = this.list; + this.list = new ArrayList(this.count); + this.count = 0; + this.handleCreated = true; + + for (index = 0; index < items.Count; index++) + AddItemInternal((ImageListItem)items[index]); + } + } + + private Image CreateImage(Image value, Color transparentColor) + { + int imageWidth; + int imageHeight; + ImageAttributes imageAttributes; + + if (transparentColor.A == 0) + imageAttributes = null; + else { + imageAttributes = new ImageAttributes(); + imageAttributes.SetColorKey (transparentColor, transparentColor); + } + + var bitmap = new Bitmap (imageWidth = this.imageSize.Width, imageHeight = this.imageSize.Height, PixelFormat.Format32bppArgb); + using (var graphics = Graphics.FromImage (bitmap)) + graphics.DrawImage (value, new Rectangle(0, 0, imageWidth, imageHeight), 0, 0, value.Width, value.Height, GraphicsUnit.Pixel, imageAttributes); + + if (imageAttributes != null) + imageAttributes.Dispose (); + + ReduceColorDepth (bitmap); + return bitmap; + } + + private void RecreateHandle() + { + if (this.handleCreated) { + DestroyHandle(); + this.handleCreated = true; + owner.OnRecreateHandle(); + } + } + + private unsafe void ReduceColorDepth(Bitmap bitmap) + { + byte* pixelPtr; + byte* lineEndPtr; + byte* linePtr; + int line; + int pixel; + int height; + int widthBytes; + int stride; + BitmapData bitmapData; + Color[] palette; + + if (this.colorDepth < ColorDepth.Depth32Bit) { + bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + try { + linePtr = (byte*)bitmapData.Scan0; + height = bitmapData.Height; + widthBytes = bitmapData.Width << 2; + stride = bitmapData.Stride; + + if (this.colorDepth < ColorDepth.Depth16Bit) { + palette = (this.colorDepth < ColorDepth.Depth8Bit ? IndexedColorDepths.Palette4Bit : IndexedColorDepths.Palette8Bit).Entries; + + for (line = 0; line < height; line++) { + lineEndPtr = linePtr + widthBytes; + for (pixelPtr = linePtr; pixelPtr < lineEndPtr; pixelPtr += 4) + *(int*)pixelPtr = ((pixel = *(int*)pixelPtr) & AlphaMask) == 0 ? 0x00000000 : IndexedColorDepths.GetNearestColor(palette, pixel | AlphaMask); + linePtr += stride; + } + } + else if (this.colorDepth < ColorDepth.Depth24Bit) { + for (line = 0; line < height; line++) { + lineEndPtr = linePtr + widthBytes; + for (pixelPtr = linePtr; pixelPtr < lineEndPtr; pixelPtr += 4) + *(int*)pixelPtr = ((pixel = *(int*)pixelPtr) & AlphaMask) == 0 ? 0x00000000 : (pixel & 0x00F8F8F8) | AlphaMask; + linePtr += stride; + } + } + else { + for (line = 0; line < height; line++) { + lineEndPtr = linePtr + widthBytes; + for (pixelPtr = linePtr; pixelPtr < lineEndPtr; pixelPtr += 4) + *(int*)pixelPtr = ((pixel = *(int*)pixelPtr) & AlphaMask) == 0 ? 0x00000000 : pixel | AlphaMask; + linePtr += stride; + } + } + } + finally { + bitmap.UnlockBits(bitmapData); + } + } + } + #endregion // ImageCollection Private Instance Methods + + #region ImageCollection Internal Instance Methods + // For use in ImageList + internal void DestroyHandle() + { + if (this.handleCreated) { + this.list = new ArrayList(); + this.count = 0; + this.handleCreated = false; + keys = new ArrayList(); + } + } + + // For use in ImageList + internal Image GetImage(int index) + { + if (index < 0 || index >= this.Count) + throw new ArgumentOutOfRangeException("index"); + + CreateHandle(); + return (Image)list[index]; + } + + // For use in ImageListStreamer + internal Image[] ToArray() + { + Image[] images; + + // Handle is created even when the list is empty. + CreateHandle(); + images = new Image[list.Count]; + list.CopyTo(images); + return images; + } + #endregion // ImageCollection Internal Instance Methods + + #region ImageCollection Public Instance Methods + public void Add(Icon value) + { + Add(null, value); + } + + public void Add(Image value) + { + Add(null, value); + } + + public int Add(Image value, Color transparentColor) + { + return AddItem(null, new ImageListItem(value, transparentColor)); + } + + public void Add(string key, Icon icon) + { + // Argument has name icon but exceptions use name value. + AddItem(key, new ImageListItem(icon)); + } + + public void Add(string key, Image image) + { + // Argument has name image but exceptions use name value. + AddItem(key, new ImageListItem(image)); + } + + public void AddRange(Image[] images) + { + int index; + + if (images == null) + throw new ArgumentNullException("images"); + + for (index = 0; index < images.Length; index++) + Add(images[index]); + } + + public int AddStrip(Image value) + { + int width; + int imageWidth; + + if (value == null) + throw new ArgumentNullException("value"); + + if ((width = value.Width) == 0 || (width % (imageWidth = this.imageSize.Width)) != 0) + throw new ArgumentException("Width of image strip must be a positive multiple of ImageSize.Width.", "value"); + + if (value.Height != this.imageSize.Height) + throw new ArgumentException("Height of image strip must be equal to ImageSize.Height.", "value"); + + return AddItem(null, new ImageListItem(value, width / imageWidth)); + } + + public void Clear() + { + list.Clear(); + if (!this.handleCreated) + this.count = 0; + keys.Clear(); + } + + //[EditorBrowsable(EditorBrowsableState.Never)] + public bool Contains(Image image) + { + throw new NotSupportedException(); + } + + public bool ContainsKey(string key) + { + return IndexOfKey(key) != -1; + } + + public IEnumerator GetEnumerator() + { + Image[] images = new Image[this.Count]; + int index; + + if (images.Length != 0) { + // Handle is created only when there are images. + CreateHandle(); + + for (index = 0; index < images.Length; index++) + images[index] = (Image)((Image)list[index]).Clone(); + } + + return images.GetEnumerator(); + } + + //[EditorBrowsable(EditorBrowsableState.Never)] + public int IndexOf(Image image) + { + throw new NotSupportedException(); + } + + public int IndexOfKey(string key) + { + int index; + + if (key != null && key.Length != 0) { + // When last IndexOfKey was successful and the same key was + // assigned to an image with a lower index than the last + // result and the key of the last result equals to key + // argument the last result is returned. + + if (this.lastKeyIndex >= 0 && this.lastKeyIndex < this.Count && CompareKeys((string)keys[this.lastKeyIndex], key)) + return this.lastKeyIndex; + + // Duplicate keys are allowed and first match is returned. + for (index = 0; index < this.Count; index++) + if (CompareKeys((string)keys[index], key)) + return this.lastKeyIndex = index; + } + + return this.lastKeyIndex = -1; + } + + //[EditorBrowsable(EditorBrowsableState.Never)] + public void Remove(Image image) + { + throw new NotSupportedException(); + } + + public void RemoveAt(int index) + { + if (index < 0 || index >= this.Count) + throw new ArgumentOutOfRangeException("index"); + + CreateHandle(); + list.RemoveAt(index); + keys.RemoveAt(index); + if (Changed != null) + Changed (this, EventArgs.Empty); + } + + public void RemoveByKey(string key) + { + int index; + + if ((index = IndexOfKey(key)) != -1) + RemoveAt(index); + } + + public void SetKeyName(int index, string name) + { + // Only SetKeyName throws IndexOutOfRangeException. + if (index < 0 || index >= this.Count) + throw new IndexOutOfRangeException(); + + keys[index] = name; + } + #endregion // ImageCollection Public Instance Methods + + #region ImageCollection Interface Properties + object IList.this[int index] { + get { + return this[index]; + } + + set { + if (!(value is Image)) + throw new ArgumentException("value"); + + this[index] = (Image)value; + } + } + + bool IList.IsFixedSize { + get { + return false; + } + } + + bool ICollection.IsSynchronized { + get { + return false; + } + } + + object ICollection.SyncRoot { + get { + return this; + } + } + #endregion // ImageCollection Interface Properties + + #region ImageCollection Interface Methods + int IList.Add(object value) + { + int index; + + if (!(value is Image)) + throw new ArgumentException("value"); + + index = this.Count; + this.Add((Image)value); + return index; + } + + bool IList.Contains(object image) + { + return image is Image ? this.Contains ((Image) image) : false; + } + + int IList.IndexOf (object image) + { + return image is Image ? this.IndexOf ((Image) image) : -1; + } + + void IList.Insert(int index, object value) + { + throw new NotSupportedException(); + } + + void IList.Remove (object image) + { + if (image is Image) + this.Remove ((Image) image); + } + + void ICollection.CopyTo(Array dest, int index) + { + for (int imageIndex = 0; imageIndex < this.Count; imageIndex++) + dest.SetValue (this[imageIndex], index++); + } + #endregion // ImageCollection Interface Methods + } + #endregion // Sub-classes + + #region Public Constructors + public ImageList() + { + images = new ImageCollection(this); + } + + public ImageList(System.ComponentModel.IContainer container) : this() + { + container.Add(this); + } + #endregion // Public Constructors + + #region Private Instance Methods + private void OnRecreateHandle() + { + EventHandler eh = (EventHandler)(Events [RecreateHandleEvent]); + if (eh != null) + eh (this, EventArgs.Empty); + } + + // MS's TypeDescriptor stuff apparently uses + // non-public ShouldSerialize* methods, because it + // picks up this behavior even though the methods + // aren't public. we can't make them private, though, + // without adding compiler warnings. so, make then + // internal instead. + + internal bool ShouldSerializeTransparentColor () + { + return this.TransparentColor != Color.LightGray; + } + + internal bool ShouldSerializeColorDepth() + { + // ColorDepth is serialized in ImageStream when non-empty. + // It is serialized even if it has its default value when empty. + return images.Empty; + } + + internal bool ShouldSerializeImageSize() + { + // ImageSize is serialized in ImageStream when non-empty. + // It is serialized even if it has its default value when empty. + return images.Empty; + } + + internal void ResetColorDepth () + { + this.ColorDepth = DefaultColorDepth; + } + + internal void ResetImageSize () + { + this.ImageSize = DefaultImageSize; + } + + internal void ResetTransparentColor () + { + this.TransparentColor = Color.LightGray; + } + #endregion // Private Instance Methods + + #region Public Instance Properties + public ColorDepth ColorDepth { + get { + return images.ColorDepth; + } + + set { + images.ColorDepth = value; + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IntPtr Handle { + get { + return images.Handle; + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool HandleCreated { + get { + return images.HandleCreated; + } + } + + [DefaultValue(null)] + [MergableProperty(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ImageCollection Images { + get { + return this.images; + } + } + + [Localizable(true)] + public Size ImageSize { + get { + return images.ImageSize; + } + + set { + images.ImageSize = value; + } + } + + [Browsable(false)] + [DefaultValue(null)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public ImageListStreamer ImageStream { + get { + return images.ImageStream; + } + + set { + images.ImageStream = value; + } + } + + [Bindable(true)] + [DefaultValue(null)] + [Localizable(false)] + [TypeConverter(typeof(StringConverter))] + public object Tag { + get { + return this.tag; + } + + set { + this.tag = value; + } + } + + public Color TransparentColor { + get { + return images.TransparentColor; + } + + set { + images.TransparentColor = value; + } + } + #endregion // Public Instance Properties + + #region Public Instance Methods + public void Draw(Graphics g, Point pt, int index) + { + this.Draw(g, pt.X, pt.Y, index); + } + + public void Draw(Graphics g, int x, int y, int index) + { + g.DrawImage(images.GetImage(index), x, y); + } + + public void Draw(Graphics g, int x, int y, int width, int height, int index) + { + g.DrawImage(images.GetImage(index), x, y, width, height); + } + + public override string ToString() + { + return base.ToString() + " Images.Count: " + images.Count.ToString() + ", ImageSize: " + this.ImageSize.ToString(); + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + protected override void Dispose(bool disposing) + { + if (disposing) + images.DestroyHandle(); + + base.Dispose(disposing); + } + #endregion // Protected Instance Methods + + #region Events + static object RecreateHandleEvent = new object (); + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public event EventHandler RecreateHandle { + add { Events.AddHandler (RecreateHandleEvent, value); } + remove { Events.RemoveHandler (RecreateHandleEvent, value); } + } + #endregion // Events + } +} diff --git a/source/ShiftUI/Internal/ImageListConverter.cs b/source/ShiftUI/Internal/ImageListConverter.cs new file mode 100644 index 0000000..8074d03 --- /dev/null +++ b/source/ShiftUI/Internal/ImageListConverter.cs @@ -0,0 +1,44 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. +// +// Authors: +// Matthias Felgner matthiasf@voelcker.com +// + +// COMPLETE + +using System.ComponentModel; + + +namespace ShiftUI { + internal class ImageListConverter : ComponentConverter { + #region Constructors + public ImageListConverter() : base(typeof(ImageList)) { + } + #endregion Constructors + + #region Public Methods + public override bool GetPropertiesSupported(ITypeDescriptorContext context){ + return true; + } + #endregion Public Methods + } +} diff --git a/source/ShiftUI/Internal/ImageListStreamer.cs b/source/ShiftUI/Internal/ImageListStreamer.cs new file mode 100644 index 0000000..3186747 --- /dev/null +++ b/source/ShiftUI/Internal/ImageListStreamer.cs @@ -0,0 +1,338 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2002-2006 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// Gonzalo Paniagua Javier (gonzalo@ximian.com) +// +// Based on work done by: +// Dennis Hayes (dennish@Raytek.com) +// Aleksey Ryabchuk (ryabchuk@yahoo.com) + +using System.IO; +using System.Drawing; +using System.Collections; +using System.Drawing.Imaging; +using System.Runtime.Serialization; +using System.Runtime.InteropServices; +using System; + + +namespace ShiftUI { + [Serializable] + public sealed class ImageListStreamer : ISerializable { + readonly ImageList.ImageCollection imageCollection; + Image [] images; + Size image_size; + Color back_color; + + internal ImageListStreamer (ImageList.ImageCollection imageCollection) + { + this.imageCollection = imageCollection; + } + + private ImageListStreamer (SerializationInfo info, StreamingContext context) + { + byte [] data = (byte []) info.GetValue ("Data", typeof (byte [])); + if (data == null || data.Length <= 4) { // 4 is the signature + return; + } + + // check the signature ( 'MSFt' ) + if (data [0] != 77 || data [1] != 83 || data [2] != 70 || data [3] != 116) { + return; + } + + MemoryStream decoded = GetDecodedStream (data, 4, data.Length - 4); + decoded.Position = 4; // jumps over 'magic' and 'version', which are 16-bits each + + BinaryReader reader = new BinaryReader (decoded); + ushort nimages = reader.ReadUInt16 (); + reader.ReadUInt16 (); // cMaxImage + ushort grow = reader.ReadUInt16 (); // cGrow + ushort cx = reader.ReadUInt16 (); + ushort cy = reader.ReadUInt16 (); + uint bkcolor = reader.ReadUInt32 (); + back_color = Color.FromArgb ((int) bkcolor); + reader.ReadUInt16 (); // flags + + short [] ovls = new short [4]; + for (int i = 0; i < 4; i++) { + ovls[i] = reader.ReadInt16 (); + } + + byte [] decoded_buffer = decoded.GetBuffer (); + int bmp_offset = 28; + // FileSize field from the bitmap file header + int filesize = decoded_buffer [bmp_offset + 2] + (decoded_buffer [bmp_offset + 3] << 8) + + (decoded_buffer [bmp_offset + 4] << 16) + (decoded_buffer [bmp_offset + 5] << 24); + // ImageSize field from the info header (can be 0) + int imagesize = decoded_buffer [bmp_offset + 34] + (decoded_buffer [bmp_offset + 35] << 8) + + (decoded_buffer [bmp_offset + 36] << 16) + (decoded_buffer [bmp_offset + 37] << 24); + + int bmp_length = imagesize + filesize; + MemoryStream bmpms = new MemoryStream (decoded_buffer, bmp_offset, bmp_length); + Bitmap bmp = null; + Bitmap mask = null; + bmp = new Bitmap (bmpms); + MemoryStream mask_stream = new MemoryStream (decoded_buffer, + bmp_offset + bmp_length, + (int) (decoded.Length - bmp_offset - bmp_length)); + + if (mask_stream.Length > 0) + mask = new Bitmap (mask_stream); + + if (bkcolor == 0xFFFFFFFF) + back_color = bmp.GetPixel (0, 0); + + if (mask != null) { + int width = bmp.Width; + int height = bmp.Height; + Bitmap newbmp = new Bitmap (bmp); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + Color mcolor = mask.GetPixel (x, y); + if (mcolor.B != 0) { + newbmp.SetPixel (x, y, Color.Transparent); + } + } + } + bmp.Dispose (); + bmp = newbmp; + mask.Dispose (); + mask = null; + } + images = new Image [nimages]; + image_size = new Size (cx, cy); + Rectangle dest_rect = new Rectangle (0, 0, cx, cy); + if (grow * bmp.Width > cx) // Some images store a wrong 'grow' factor + grow = (ushort) (bmp.Width / cx); + + for (int r = 0 ; r < nimages ; r++) { + int col = r % grow; + int row = r / grow; + Rectangle area = new Rectangle (col * cx, row * cy, cx, cy); + Bitmap b = new Bitmap (cx, cy); + using (Graphics g = Graphics.FromImage (b)) { + g.DrawImage (bmp, dest_rect, area, GraphicsUnit.Pixel); + } + + images [r] = b; + } + bmp.Dispose (); + } + + /* + static void WriteToFile (MemoryStream st) + { + st.Position = 0; + FileStream fs = File.OpenWrite (Path.GetTempFileName ()); + Console.WriteLine ("Writing to {0}", fs.Name); + st.WriteTo (fs); + fs.Close (); + } + */ + + static byte [] header = new byte []{ 77, 83, 70, 116, 73, 76, 1, 1 }; + public void GetObjectData (SerializationInfo si, StreamingContext context) + { + MemoryStream stream = new MemoryStream (); + BinaryWriter writer = new BinaryWriter (stream); + writer.Write (header); + + Image [] images = (imageCollection != null) ? imageCollection.ToArray () : this.images; + int cols = 4; + int rows = images.Length / cols; + if (images.Length % cols > 0) + ++rows; + + writer.Write ((ushort) images.Length); + writer.Write ((ushort) images.Length); + writer.Write ((ushort) 0x4); + writer.Write ((ushort) (images [0].Width)); + writer.Write ((ushort) (images [0].Height)); + writer.Write (0xFFFFFFFF); //BackColor.ToArgb ()); //FIXME: should set the right one here. + writer.Write ((ushort) 0x21); + for (int i = 0; i < 4; i++) + writer.Write ((short) -1); + + Bitmap main = new Bitmap (cols * ImageSize.Width, rows * ImageSize.Height); + using (Graphics g = Graphics.FromImage (main)) { + g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), 0, 0, + main.Width, main.Height); + for (int i = 0; i < images.Length; i++) { + g.DrawImage (images [i], (i % cols) * ImageSize.Width, + (i / cols) * ImageSize.Height); + } + } + + MemoryStream tmp = new MemoryStream (); + main.Save (tmp, ImageFormat.Bmp); + tmp.WriteTo (stream); + + Bitmap mask = Get1bppMask (main); + main.Dispose (); + main = null; + + tmp = new MemoryStream (); + mask.Save (tmp, ImageFormat.Bmp); + tmp.WriteTo (stream); + mask.Dispose (); + + stream = GetRLEStream (stream, 4); + si.AddValue ("Data", stream.ToArray (), typeof (byte [])); + } + + unsafe Bitmap Get1bppMask (Bitmap main) + { + Rectangle rect = new Rectangle (0, 0, main.Width, main.Height); + Bitmap result = new Bitmap (main.Width, main.Height, PixelFormat.Format1bppIndexed); + BitmapData dresult = result.LockBits (rect, ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed); + + int w = images [0].Width; + int h = images [0].Height; + byte *scan = (byte *) dresult.Scan0.ToPointer (); + int stride = dresult.Stride; + Bitmap current = null; + for (int idx = 0; idx < images.Length; idx++) { + current = (Bitmap) images [idx]; + // Hack for newly added images. + // Probably has to be done somewhere else. + Color c1 = current.GetPixel (0, 0); + if (c1.A != 0 && c1 == back_color) + current.MakeTransparent (back_color); + // + } + + int yidx = 0; + int imgidx = 0; + int localy = 0; + int localx = 0; + int factor_y = 0; + int factor_x = 0; + for (int y = 0; y < main.Height; y++) { + if (localy == h) { + localy = 0; + factor_y += 4; + } + factor_x = 0; + localx = 0; + for (int x = 0; x < main.Width; x++) { + if (localx == w) { + localx = 0; + factor_x++; + } + imgidx = factor_y + factor_x; + if (imgidx >= images.Length) + break; + current = (Bitmap) images [imgidx]; + Color color = current.GetPixel (localx, localy); + if (color.A == 0) { + int ptridx = yidx + (x >> 3); + scan [ptridx] |= (byte) (0x80 >> (x & 7)); + } + localx++; + } + if (imgidx >= images.Length) + break; + yidx += stride; + localy++; + } + result.UnlockBits (dresult); + + return result; + } + + static MemoryStream GetDecodedStream (byte [] bytes, int offset, int size) + { + byte [] buffer = new byte [512]; + int position = 0; + int count, data; + MemoryStream result = new MemoryStream (); + while (size > 0) { + count = (int) bytes [offset++]; + data = (int) bytes [offset++]; + if ((512 - count) < position) { + result.Write (buffer, 0, position); + position = 0; + } + + for (int i = 0; i < count; i++) + buffer [position++] = (byte) data; + size -= 2; + } + + if (position > 0) + result.Write (buffer, 0, position); + + result.Position = 0; + return result; + } + + //TODO: OptimizeMe + static MemoryStream GetRLEStream (MemoryStream input, int start) + { + MemoryStream result = new MemoryStream (); + byte [] ibuffer = input.GetBuffer (); + result.Write (ibuffer, 0, start); + input.Position = start; + + int prev = -1; + int count = 0; + int current; + while ((current = input.ReadByte ()) != -1) { + if (prev != current || count == 255) { + if (prev != -1) { + result.WriteByte ((byte) count); + result.WriteByte ((byte) prev); + } + prev = current; + count = 0; + } + count++; + } + + if (count > 0) { + result.WriteByte ((byte) count); + result.WriteByte ((byte) current); + } + + return result; + } + + internal Image [] Images { + get { return images; } + } + + internal Size ImageSize { + get { return image_size; } + } + + internal ColorDepth ColorDepth { + get { return ColorDepth.Depth32Bit; } + } + + internal Color BackColor { + get { return back_color; } + } + } +} + diff --git a/source/ShiftUI/Internal/InternalWindowManager.cs b/source/ShiftUI/Internal/InternalWindowManager.cs new file mode 100644 index 0000000..95fae49 --- /dev/null +++ b/source/ShiftUI/Internal/InternalWindowManager.cs @@ -0,0 +1,1211 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// +// + + +using System; +using System.Drawing; +using System.Runtime.InteropServices; + + +namespace ShiftUI { + + internal abstract class InternalWindowManager { + private TitleButtons title_buttons; + internal Form form; + + // moving windows + internal Point start; + internal State state; + protected Point clicked_point; + private FormPos sizing_edge; + internal Rectangle virtual_position; + + private Rectangle normal_bounds; + private Rectangle iconic_bounds; + + + public enum State { + Idle, + Moving, + Sizing, + } + + [Flags] + public enum FormPos { + None, + + TitleBar = 1, + + Top = 2, + Left = 4, + Right = 8, + Bottom = 16, + + TopLeft = Top | Left, + TopRight = Top | Right, + + BottomLeft = Bottom | Left, + BottomRight = Bottom | Right, + + AnyEdge = Top | Left | Right | Bottom, + } + + public InternalWindowManager (Form form) + { + this.form = form; + + form.SizeChanged += new EventHandler (FormSizeChangedHandler); + + title_buttons = new TitleButtons (form); + ThemeEngine.Current.ManagedWindowSetButtonLocations (this); + } + + public Form Form { + get { return form; } + } + + public int IconWidth { + get { return TitleBarHeight - 5; } + } + + public TitleButtons TitleButtons { + get { + return title_buttons; + } + } + internal Rectangle NormalBounds { + get { + return normal_bounds; + } + set { + normal_bounds = value; + } + } + internal Size IconicSize { + get { + return SystemInformation.MinimizedWindowSize; + } + } + + internal Rectangle IconicBounds { + get { + if (iconic_bounds == Rectangle.Empty) + return Rectangle.Empty; + Rectangle result = iconic_bounds; + result.Y = Form.Parent.ClientRectangle.Bottom - iconic_bounds.Y; + return result; + } + set { + iconic_bounds = value; + iconic_bounds.Y = Form.Parent.ClientRectangle.Bottom - iconic_bounds.Y; + } + } + + internal virtual Rectangle MaximizedBounds { + get { + return Form.Parent.ClientRectangle; + } + } + + public virtual void UpdateWindowState (FormWindowState old_window_state, FormWindowState new_window_state, bool force) + { + if (old_window_state == FormWindowState.Normal) { + NormalBounds = form.Bounds; + } else if (old_window_state == FormWindowState.Minimized) { + IconicBounds = form.Bounds; + } + + switch (new_window_state) { + case FormWindowState.Minimized: + if (IconicBounds == Rectangle.Empty) { + Size size = IconicSize; + Point location = new Point (0, Form.Parent.ClientSize.Height - size.Height); + IconicBounds = new Rectangle (location, size); + } + form.Bounds = IconicBounds; + break; + case FormWindowState.Maximized: + form.Bounds = MaximizedBounds; + break; + case FormWindowState.Normal: + form.Bounds = NormalBounds; + break; + } + + UpdateWindowDecorations (new_window_state); + form.ResetCursor (); + } + + public virtual void UpdateWindowDecorations (FormWindowState window_state) + { + ThemeEngine.Current.ManagedWindowSetButtonLocations (this); + if (form.IsHandleCreated) + XplatUI.RequestNCRecalc (form.Handle); + } + + public virtual bool WndProc (ref Message m) + { +#if debug + Console.WriteLine(DateTime.Now.ToLongTimeString () + " " + this.GetType () .Name + " (Handle={0},Text={1}) received message {2}", form.IsHandleCreated ? form.Handle : IntPtr.Zero, form.Text, m.ToString ()); +#endif + + switch ((Msg)m.Msg) { + + + // The mouse handling messages are actually + // not WM_NC* messages except for the first button and NCMOVEs + // down because we capture on the form + + case Msg.WM_MOUSEMOVE: + return HandleMouseMove (form, ref m); + + case Msg.WM_LBUTTONUP: + HandleLButtonUp (ref m); + break; + + case Msg.WM_RBUTTONDOWN: + return HandleRButtonDown (ref m); + + case Msg.WM_LBUTTONDOWN: + return HandleLButtonDown (ref m); + + case Msg.WM_LBUTTONDBLCLK: + return HandleLButtonDblClick (ref m); + + case Msg.WM_PARENTNOTIFY: + if (Widget.LowOrder(m.WParam.ToInt32()) == (int) Msg.WM_LBUTTONDOWN) + Activate (); + break; + + case Msg.WM_NCHITTEST: + return HandleNCHitTest (ref m); + + // Return true from these guys, otherwise win32 will mess up z-order + case Msg.WM_NCLBUTTONUP: + HandleNCLButtonUp (ref m); + return true; + + case Msg.WM_NCLBUTTONDOWN: + HandleNCLButtonDown (ref m); + return true; + + case Msg.WM_NCMOUSEMOVE: + HandleNCMouseMove (ref m); + return true; + + case Msg.WM_NCLBUTTONDBLCLK: + HandleNCLButtonDblClick (ref m); + break; + + case Msg.WM_NCMOUSELEAVE: + HandleNCMouseLeave (ref m); + break; + + case Msg.WM_MOUSELEAVE: + HandleMouseLeave (ref m); + break; + + case Msg.WM_NCCALCSIZE: + return HandleNCCalcSize (ref m); + + case Msg.WM_NCPAINT: + return HandleNCPaint (ref m); + } + + return false; + } + + protected virtual bool HandleNCPaint (ref Message m) + { + PaintEventArgs pe = XplatUI.PaintEventStart (ref m, form.Handle, false); + + Rectangle clip; + + if (form.ActiveMenu != null) { + Point pnt; + + pnt = GetMenuOrigin (); + + // The entire menu has to be in the clip rectangle because the + // control buttons are right-aligned and otherwise they would + // stay painted when the window gets resized. + clip = new Rectangle (pnt.X, pnt.Y, form.ClientSize.Width, 0); + clip = Rectangle.Union (clip, pe.ClipRectangle); + pe.SetClip (clip); + pe.Graphics.SetClip (clip); + + form.ActiveMenu.Draw (pe, new Rectangle (pnt.X, pnt.Y, form.ClientSize.Width, 0)); + } + if (HasBorders || IsMinimized && !(Form.IsMdiChild && IsMaximized)) { + // clip region is not correct on win32. + // use the entire form's area. + clip = new Rectangle (0, 0, form.Width, form.Height); + ThemeEngine.Current.DrawManagedWindowDecorations (pe.Graphics, clip, this); + } + XplatUI.PaintEventEnd (ref m, form.Handle, false); + return true; + } + + protected virtual bool HandleNCCalcSize (ref Message m) + { + XplatUIWin32.NCCALCSIZE_PARAMS ncp; + XplatUIWin32.RECT rect; + + if (m.WParam == (IntPtr)1) { + ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure (m.LParam, + typeof (XplatUIWin32.NCCALCSIZE_PARAMS)); + + ncp.rgrc1 = NCCalcSize (ncp.rgrc1); + + Marshal.StructureToPtr (ncp, m.LParam, true); + } else { + rect = (XplatUIWin32.RECT) Marshal.PtrToStructure (m.LParam, typeof (XplatUIWin32.RECT)); + + rect = NCCalcSize (rect); + + Marshal.StructureToPtr (rect, m.LParam, true); + } + + return true; + } + + protected virtual XplatUIWin32.RECT NCCalcSize (XplatUIWin32.RECT proposed_window_rect) + { + int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this); + + if (HasBorders) { + proposed_window_rect.top += TitleBarHeight + bw; + proposed_window_rect.bottom -= bw; + proposed_window_rect.left += bw; + proposed_window_rect.right -= bw; + } + + if (XplatUI.RequiresPositiveClientAreaSize) { + // This is necessary for Linux, can't handle <= 0-sized + // client areas correctly. + if (proposed_window_rect.right <= proposed_window_rect.left) { + proposed_window_rect.right += proposed_window_rect.left - proposed_window_rect.right + 1; + } + if (proposed_window_rect.top >= proposed_window_rect.bottom) { + proposed_window_rect.bottom += proposed_window_rect.top - proposed_window_rect.bottom + 1; + } + } + + return proposed_window_rect; + } + + protected virtual bool HandleNCHitTest (ref Message m) + { + + int x = Widget.LowOrder ((int)m.LParam.ToInt32 ()); + int y = Widget.HighOrder ((int)m.LParam.ToInt32 ()); + + NCPointToClient (ref x, ref y); + + FormPos pos = FormPosForCoords (x, y); + + if (pos == FormPos.TitleBar) { + m.Result = new IntPtr ((int)HitTest.HTCAPTION); + return true; + } + + if (!IsSizable) + return false; + + switch (pos) { + case FormPos.Top: + m.Result = new IntPtr ((int)HitTest.HTTOP); + break; + case FormPos.Left: + m.Result = new IntPtr ((int)HitTest.HTLEFT); + break; + case FormPos.Right: + m.Result = new IntPtr ((int)HitTest.HTRIGHT); + break; + case FormPos.Bottom: + m.Result = new IntPtr ((int)HitTest.HTBOTTOM); + break; + case FormPos.TopLeft: + m.Result = new IntPtr ((int)HitTest.HTTOPLEFT); + break; + case FormPos.TopRight: + m.Result = new IntPtr ((int)HitTest.HTTOPRIGHT); + break; + case FormPos.BottomLeft: + m.Result = new IntPtr ((int)HitTest.HTBOTTOMLEFT); + break; + case FormPos.BottomRight: + m.Result = new IntPtr ((int)HitTest.HTBOTTOMRIGHT); + break; + default: + // We return false so that DefWndProc handles things + return false; + } + return true; + } + + public virtual void UpdateBorderStyle (FormBorderStyle border_style) + { + if (form.IsHandleCreated) { + XplatUI.SetBorderStyle (form.Handle, border_style); + } + + if (ShouldRemoveWindowManager (border_style)) { + form.RemoveWindowManager (); + return; + } + + ThemeEngine.Current.ManagedWindowSetButtonLocations (this); + } + + + + public virtual void SetWindowState (FormWindowState old_state, FormWindowState window_state) + { + UpdateWindowState (old_state, window_state, false); + } + + public virtual FormWindowState GetWindowState () + { + return form.window_state; + } + + public virtual void PointToClient (ref int x, ref int y) + { + // toolwindows stay in screencoords we just have to make sure + // they obey the working area + Rectangle working = SystemInformation.WorkingArea; + + if (x > working.Right) + x = working.Right; + if (x < working.Left) + x = working.Left; + + if (y < working.Top) + y = working.Top; + if (y > working.Bottom) + y = working.Bottom; + } + + public virtual void PointToScreen (ref int x, ref int y) + { + XplatUI.ClientToScreen (form.Handle, ref x, ref y); + } + + protected virtual bool ShouldRemoveWindowManager (FormBorderStyle style) + { + return style != FormBorderStyle.FixedToolWindow && style != FormBorderStyle.SizableToolWindow; + } + + public bool IconRectangleContains (int x, int y) + { + if (!ShowIcon) + return false; + + Rectangle icon = ThemeEngine.Current.ManagedWindowGetTitleBarIconArea (this); + return icon.Contains (x, y); + } + + public bool ShowIcon { + get { + if (!Form.ShowIcon) + return false; + if (!HasBorders) + return false; + if (IsMinimized) + return true; + if (IsToolWindow || Form.FormBorderStyle == FormBorderStyle.FixedDialog) + return false; + return true; + } + } + + protected virtual void Activate () + { + form.Invalidate (true); + form.Update (); + } + + public virtual bool IsActive { + get { + return true; + } + } + + + private void FormSizeChangedHandler (object sender, EventArgs e) + { + if (form.IsHandleCreated) { + ThemeEngine.Current.ManagedWindowSetButtonLocations (this); + XplatUI.InvalidateNC (form.Handle); + } + } + + protected virtual bool HandleRButtonDown (ref Message m) + { + Activate (); + return false; + } + + protected virtual bool HandleLButtonDown (ref Message m) + { + Activate (); + return false; + } + + protected virtual bool HandleLButtonDblClick(ref Message m) + { + return false; + } + + protected virtual bool HandleNCMouseLeave (ref Message m) + { + int x = Widget.LowOrder ((int)m.LParam.ToInt32 ()); + int y = Widget.HighOrder ((int)m.LParam.ToInt32 ()); + + NCPointToClient (ref x, ref y); + FormPos pos = FormPosForCoords (x, y); + + if (pos != FormPos.TitleBar) { + HandleTitleBarLeave (x, y); + return true; + } + + return true; + } + + protected virtual bool HandleNCMouseMove (ref Message m) + { + int x = Widget.LowOrder((int)m.LParam.ToInt32( )); + int y = Widget.HighOrder((int)m.LParam.ToInt32( )); + + NCPointToClient (ref x, ref y); + FormPos pos = FormPosForCoords (x, y); + + if (pos == FormPos.TitleBar) { + HandleTitleBarMouseMove (x, y); + return true; + } + + if (form.ActiveMenu != null && XplatUI.IsEnabled (form.Handle)) { + MouseEventArgs mea = new MouseEventArgs (Form.FromParamToMouseButtons (m.WParam.ToInt32 ()), form.mouse_clicks, x, y, 0); + form.ActiveMenu.OnMouseMove (form, mea); + } + + return true; + + } + + protected virtual bool HandleNCLButtonDown (ref Message m) + { + Activate (); + + start = Cursor.Position; + virtual_position = form.Bounds; + + int x = Widget.LowOrder ((int) m.LParam.ToInt32 ()); + int y = Widget.HighOrder ((int) m.LParam.ToInt32 ()); + + // Need to adjust because we are in NC land + NCPointToClient (ref x, ref y); + FormPos pos = FormPosForCoords (x, y); + + if (form.ActiveMenu != null && XplatUI.IsEnabled (form.Handle)) { + MouseEventArgs mea = new MouseEventArgs (Form.FromParamToMouseButtons (m.WParam.ToInt32 ()), form.mouse_clicks, x, y - TitleBarHeight, 0); + form.ActiveMenu.OnMouseDown (form, mea); + } + + if (pos == FormPos.TitleBar) { + HandleTitleBarDown (x, y); + return true; + } + + if (IsSizable) { + if ((pos & FormPos.AnyEdge) == 0) + return false; + + virtual_position = form.Bounds; + state = State.Sizing; + sizing_edge = pos; + form.Capture = true; + return true; + } + + return false; + } + + protected virtual void HandleNCLButtonDblClick (ref Message m) + { + int x = Widget.LowOrder ((int)m.LParam.ToInt32 ()); + int y = Widget.HighOrder ((int)m.LParam.ToInt32 ()); + + // Need to adjust because we are in NC land + NCPointToClient (ref x, ref y); + + FormPos pos = FormPosForCoords (x, y); + if (pos == FormPos.TitleBar || pos == FormPos.Top) + HandleTitleBarDoubleClick (x, y); + + } + + protected virtual void HandleTitleBarDoubleClick (int x, int y) + { + + } + + protected virtual void HandleTitleBarLeave (int x, int y) + { + title_buttons.MouseLeave (x, y); + } + + protected virtual void HandleTitleBarMouseMove (int x, int y) + { + if (title_buttons.MouseMove (x, y)) + XplatUI.InvalidateNC (form.Handle); + } + + protected virtual void HandleTitleBarUp (int x, int y) + { + title_buttons.MouseUp (x, y); + + return; + } + + protected virtual void HandleTitleBarDown (int x, int y) + { + title_buttons.MouseDown (x, y); + + if (!TitleButtons.AnyPushedTitleButtons && !IsMaximized) { + state = State.Moving; + clicked_point = new Point (x, y); + if (form.Parent != null) { + form.CaptureWithConfine (form.Parent); + } else { + form.Capture = true; + } + } + + XplatUI.InvalidateNC (form.Handle); + } + + private bool HandleMouseMove (Form form, ref Message m) + { + switch (state) { + case State.Moving: + HandleWindowMove (m); + return true; + case State.Sizing: + HandleSizing (m); + return true; + } + + return false; + } + + private void HandleMouseLeave (ref Message m) + { + form.ResetCursor (); + } + + protected virtual void HandleWindowMove (Message m) + { + Point move = MouseMove (Cursor.Position); + + UpdateVP (virtual_position.X + move.X, virtual_position.Y + move.Y, + virtual_position.Width, virtual_position.Height); + } + + private void HandleSizing (Message m) + { + Rectangle pos = virtual_position; + int mw; + int mh; + if (IsToolWindow) { + int border_width = BorderWidth; + mw = 2 * (border_width + Theme.ManagedWindowSpacingAfterLastTitleButton) + ThemeEngine.Current.ManagedWindowButtonSize (this).Width; + mh = 2 * border_width + TitleBarHeight; + } else { + Size minimum_size = SystemInformation.MinWindowTrackSize; + mw = minimum_size.Width; + mh = minimum_size.Height; + } + int x = Cursor.Position.X; + int y = Cursor.Position.Y; + + PointToClient (ref x, ref y); + + if ((sizing_edge & FormPos.Top) != 0) { + if (pos.Bottom - y < mh) + y = pos.Bottom - mh; + pos.Height = pos.Bottom - y; + pos.Y = y; + } else if ((sizing_edge & FormPos.Bottom) != 0) { + int height = y - pos.Top; + if (height <= mh) + height = mh; + pos.Height = height; + } + + if ((sizing_edge & FormPos.Left) != 0) { + if (pos.Right - x < mw) + x = pos.Right - mw; + pos.Width = pos.Right - x; + pos.X = x; + } else if ((sizing_edge & FormPos.Right) != 0) { + int width = x - form.Left; + if (width <= mw) + width = mw; + pos.Width = width; + } + + UpdateVP (pos); + } + + public bool IsMaximized { + get { return GetWindowState () == FormWindowState.Maximized; } + } + + public bool IsMinimized { + get { return GetWindowState () == FormWindowState.Minimized; } + } + + public bool IsSizable { + get { + switch (form.FormBorderStyle) { + case FormBorderStyle.Sizable: + case FormBorderStyle.SizableToolWindow: + return (form.window_state != FormWindowState.Minimized); + default: + return false; + } + } + } + + public bool HasBorders { + get { + return form.FormBorderStyle != FormBorderStyle.None; + } + } + + public bool IsToolWindow { + get { + if (form.FormBorderStyle == FormBorderStyle.SizableToolWindow || + form.FormBorderStyle == FormBorderStyle.FixedToolWindow || + form.GetCreateParams().IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) + return true; + return false; + } + } + + public int TitleBarHeight { + get { + return ThemeEngine.Current.ManagedWindowTitleBarHeight (this); + } + } + + public int BorderWidth { + get { + return ThemeEngine.Current.ManagedWindowBorderWidth (this); + } + } + + public virtual int MenuHeight { + get { + return (form.Menu != null ? ThemeEngine.Current.MenuHeight : 0); + } + } + + protected void UpdateVP (Rectangle r) + { + UpdateVP (r.X, r.Y, r.Width, r.Height); + } + + protected void UpdateVP (Point loc, int w, int h) + { + UpdateVP (loc.X, loc.Y, w, h); + } + + protected void UpdateVP (int x, int y, int w, int h) + { + virtual_position.X = x; + virtual_position.Y = y; + virtual_position.Width = w; + virtual_position.Height = h; + + DrawVirtualPosition (virtual_position); + } + + protected virtual void HandleLButtonUp (ref Message m) + { + if (state == State.Idle) + return; + + ClearVirtualPosition (); + + form.Capture = false; + if (state == State.Moving && form.Location != virtual_position.Location) + form.Location = virtual_position.Location; + else if (state == State.Sizing && form.Bounds != virtual_position) + form.Bounds = virtual_position; + state = State.Idle; + + OnWindowFinishedMoving (); + } + + private bool HandleNCLButtonUp (ref Message m) + { + if (form.Capture) { + ClearVirtualPosition (); + + form.Capture = false; + state = State.Idle; + if (form.MdiContainer != null) + form.MdiContainer.SizeScrollBars(); + } + + int x = Widget.LowOrder ((int) m.LParam.ToInt32 ()); + int y = Widget.HighOrder ((int) m.LParam.ToInt32 ()); + + NCPointToClient (ref x, ref y); + FormPos pos = FormPosForCoords (x, y); + + if (pos == FormPos.TitleBar) { + HandleTitleBarUp (x, y); + return true; + } + + return true; + } + + protected void DrawTitleButton (Graphics dc, TitleButton button, Rectangle clip) + { + if (!button.Rectangle.IntersectsWith (clip)) + return; + + ThemeEngine.Current.ManagedWindowDrawMenuButton (dc, button, clip, this); + } + + public virtual void DrawMaximizedButtons (object sender, PaintEventArgs pe) + { + } + + protected Point MouseMove (Point pos) + { + return new Point (pos.X - start.X, pos.Y - start.Y); + } + + protected virtual void DrawVirtualPosition (Rectangle virtual_position) + { + form.Bounds = virtual_position; + start = Cursor.Position; + } + + protected virtual void ClearVirtualPosition () + { + + } + + protected virtual void OnWindowFinishedMoving () + { + } + + protected virtual void NCPointToClient(ref int x, ref int y) { + form.PointToClient(ref x, ref y); + NCClientToNC (ref x, ref y); + } + + protected virtual void NCClientToNC (ref int x, ref int y) { + y += TitleBarHeight; + y += BorderWidth; + y += MenuHeight; + } + + internal Point GetMenuOrigin () + { + return new Point (BorderWidth, BorderWidth + TitleBarHeight); + } + + protected FormPos FormPosForCoords (int x, int y) + { + int bw = BorderWidth; + if (y < TitleBarHeight + bw) { + // Console.WriteLine ("A"); + if (y > bw && x > bw && + x < form.Width - bw) + return FormPos.TitleBar; + + if (x < bw || (x < 20 && y < bw)) + return FormPos.TopLeft; + + if (x > form.Width - bw || + (x > form.Width - 20 && y < bw)) + return FormPos.TopRight; + + if (y < bw) + return FormPos.Top; + + } else if (y > form.Height - 20) { + // Console.WriteLine ("B"); + if (x < bw || + (x < 20 && y > form.Height - bw)) + return FormPos.BottomLeft; + + if (x > form.Width - (bw * 2) || + (x > form.Width - 20 && + y > form.Height - bw)) + return FormPos.BottomRight; + + if (y > form.Height - (bw * 2)) + return FormPos.Bottom; + + + } else if (x < bw) { + // Console.WriteLine ("C"); + return FormPos.Left; + } else if (x > form.Width - (bw * 2)) { +// Console.WriteLine ("D"); + return FormPos.Right; + } else { + // Console.WriteLine ("E {0}", form.Width - bw); + } + + return FormPos.None; + } + } + internal class TitleButton + { + public Rectangle Rectangle; + public ButtonState State; + public CaptionButton Caption; + private EventHandler Clicked; + public bool Visible; + bool entered; + + public TitleButton (CaptionButton caption, EventHandler clicked) + { + Caption = caption; + Clicked = clicked; + } + + public void OnClick () + { + if (Clicked != null) { + Clicked (this, EventArgs.Empty); + } + } + + public bool Entered { + get { return entered; } + set { entered = value; } + } + } + + internal class TitleButtons : System.Collections.IEnumerable + { + public TitleButton MinimizeButton; + public TitleButton MaximizeButton; + public TitleButton RestoreButton; + public TitleButton CloseButton; + public TitleButton HelpButton; + + public TitleButton [] AllButtons; + public bool Visible; + + private ToolTip.ToolTipWindow tooltip; + private Timer tooltip_timer; + private TitleButton tooltip_hovered_button; + private TitleButton tooltip_hidden_button; + private const int tooltip_hide_interval = 3000; + private const int tooltip_show_interval = 1000; + private Form form; + + public TitleButtons (Form frm) + { + this.form = frm; + this.Visible = true; + + MinimizeButton = new TitleButton (CaptionButton.Minimize, new EventHandler (ClickHandler)); + MaximizeButton = new TitleButton (CaptionButton.Maximize, new EventHandler (ClickHandler)); + RestoreButton = new TitleButton (CaptionButton.Restore, new EventHandler (ClickHandler)); + CloseButton = new TitleButton (CaptionButton.Close, new EventHandler (ClickHandler)); + HelpButton = new TitleButton (CaptionButton.Help, new EventHandler (ClickHandler)); + + AllButtons = new TitleButton [] { MinimizeButton, MaximizeButton, RestoreButton, CloseButton, HelpButton }; + } + + private void ClickHandler (object sender, EventArgs e) + { + if (!Visible) { + return; + } + + TitleButton button = (TitleButton) sender; + + switch (button.Caption) { + case CaptionButton.Close: + form.Close (); + break; + case CaptionButton.Help: + Console.WriteLine ("Help not implemented."); + break; + case CaptionButton.Maximize: + form.WindowState = FormWindowState.Maximized; + break; + case CaptionButton.Minimize: + form.WindowState = FormWindowState.Minimized; + break; + case CaptionButton.Restore: + form.WindowState = FormWindowState.Normal; + break; + } + } + + public TitleButton FindButton (int x, int y) + { + if (!Visible) { + return null; + } + + foreach (TitleButton button in AllButtons) { + if (button.Visible && button.Rectangle.Contains (x, y)) { + return button; + } + } + return null; + } + + public bool AnyPushedTitleButtons { + get { + if (!Visible) { + return false; + } + + foreach (TitleButton button in AllButtons) { + if (button.Visible && button.State == ButtonState.Pushed) { + return true; + } + } + return false; + } + } + + #region IEnumerable Members + + public System.Collections.IEnumerator GetEnumerator () + { + return AllButtons.GetEnumerator (); + } + #endregion + + #region ToolTip helpers + // Called from MouseMove if mouse is over a button + public void ToolTipStart (TitleButton button) + { + tooltip_hovered_button = button; + + if (tooltip_hovered_button == tooltip_hidden_button) + return; + tooltip_hidden_button = null; + + if (tooltip != null && tooltip.Visible) + ToolTipShow (true); + + if (tooltip_timer == null) { + + tooltip_timer = new Timer (); + tooltip_timer.Tick += new EventHandler (ToolTipTimerTick); + } + + tooltip_timer.Interval = tooltip_show_interval; + tooltip_timer.Start (); + tooltip_hovered_button = button; + } + + public void ToolTipTimerTick (object sender, EventArgs e) + { + if (tooltip_timer.Interval == tooltip_hide_interval) { + tooltip_hidden_button = tooltip_hovered_button; + ToolTipHide (false); + } else { + ToolTipShow (false); + } + } + // Called from timer (with only_refresh = false) + // Called from ToolTipStart if tooltip is already shown (with only_refresh = true) + public void ToolTipShow (bool only_refresh) + { + if (!form.Visible) + return; + + string text = String.Format (tooltip_hovered_button.Caption.ToString ()); + + tooltip_timer.Interval = tooltip_hide_interval; + tooltip_timer.Enabled = true; + + if (only_refresh && (tooltip == null || !tooltip.Visible)) { + return; + } + + if (tooltip == null) + tooltip = new ToolTip.ToolTipWindow (); + else if (tooltip.Text == text && tooltip.Visible) + return; + else if (tooltip.Visible) + tooltip.Visible = false; + + if (form.WindowState == FormWindowState.Maximized && form.MdiParent != null) + tooltip.Present (form.MdiParent, text); + else + tooltip.Present (form, text); + + } + + // Called from MouseLeave (with reset_hidden_button = true) + // Called from MouseDown (with reset_hidden_button = false) + // Called from MouseMove if mouse isn't over any button (with reset_hidden_button = false) + // Called from Timer if hiding (with reset_hidden_button = false) + public void ToolTipHide (bool reset_hidden_button) + { + if (tooltip_timer != null) + tooltip_timer.Enabled = false; + if (tooltip != null && tooltip.Visible) + tooltip.Visible = false; + if (reset_hidden_button) + tooltip_hidden_button = null; + } + #endregion + + public bool MouseMove (int x, int y) + { + if (!Visible) { + return false; + } + + bool any_change = false; + bool any_pushed_buttons = AnyPushedTitleButtons; + bool any_tooltip = false; + TitleButton over_button = FindButton (x, y); + + foreach (TitleButton button in this) { + if (button == null) + continue; + + if (button.State == ButtonState.Inactive) + continue; + + if (button == over_button) { + if (any_pushed_buttons) { + any_change |= button.State != ButtonState.Pushed; + button.State = ButtonState.Pushed; + } + ToolTipStart (button); + any_tooltip = true; + if (!button.Entered) { + button.Entered = true; + if (ThemeEngine.Current.ManagedWindowTitleButtonHasHotElementStyle (button, form)) + any_change = true; + } + } else { + if (any_pushed_buttons) { + any_change |= button.State != ButtonState.Normal; + button.State = ButtonState.Normal; + } + if (button.Entered) { + button.Entered = false; + if (ThemeEngine.Current.ManagedWindowTitleButtonHasHotElementStyle (button, form)) + any_change = true; + } + } + } + + if (!any_tooltip) + ToolTipHide (false); + + return any_change; + } + + public void MouseDown (int x, int y) + { + if (!Visible) { + return; + } + + ToolTipHide (false); + + foreach (TitleButton button in this) { + if (button != null && button.State != ButtonState.Inactive) { + button.State = ButtonState.Normal; + } + } + TitleButton clicked_button = FindButton (x, y); + if (clicked_button != null && clicked_button.State != ButtonState.Inactive) { + clicked_button.State = ButtonState.Pushed; + } + } + + public void MouseUp (int x, int y) + { + if (!Visible) { + return; + } + + TitleButton clicked_button = FindButton (x, y); + if (clicked_button != null && clicked_button.State != ButtonState.Inactive) { + clicked_button.OnClick (); + } + + foreach (TitleButton button in this) { + if (button == null || button.State == ButtonState.Inactive) + continue; + + button.State = ButtonState.Normal; + } + + if (clicked_button == CloseButton && !form.closing) + XplatUI.InvalidateNC (form.Handle); + + ToolTipHide (true); + } + + internal void MouseLeave (int x, int y) + { + if (!Visible) { + return; + } + + foreach (TitleButton button in this) { + if (button == null || button.State == ButtonState.Inactive) + continue; + + button.State = ButtonState.Normal; + } + + ToolTipHide (true); + } + } +} + + diff --git a/source/ShiftUI/Internal/KeyboardHandler.cs b/source/ShiftUI/Internal/KeyboardHandler.cs new file mode 100644 index 0000000..5122e7b --- /dev/null +++ b/source/ShiftUI/Internal/KeyboardHandler.cs @@ -0,0 +1,329 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Geoff Norton (gnorton@novell.com) +// +// +using System; +using System.Collections; +using System.Text; +using System.Globalization; +using System.Runtime.InteropServices; + +namespace ShiftUI.CarbonInternal { + internal class KeyboardHandler : EventHandlerBase, IEventHandler { + internal const uint kEventRawKeyDown = 1; + internal const uint kEventRawKeyRepeat = 2; + internal const uint kEventRawKeyUp = 3; + internal const uint kEventRawKeyModifiersChanged = 4; + internal const uint kEventHotKeyPressed = 5; + internal const uint kEventHotKeyReleased = 6; + + internal const uint kEventParamKeyMacCharCodes = 1801676914; + internal const uint kEventParamKeyCode = 1801678692; + internal const uint kEventParamKeyModifiers = 1802334052; + internal const uint kEventTextInputUnicodeForKeyEvent = 2; + internal const uint kEventParamTextInputSendText = 1953723512; + + internal const uint typeChar = 1413830740; + internal const uint typeUInt32 = 1835100014; + internal const uint typeUnicodeText = 1970567284; + + internal static byte [] key_filter_table; + internal static byte [] key_modifier_table; + internal static byte [] key_translation_table; + internal static byte [] char_translation_table; + + internal static bool translate_modifier = false; + + internal string ComposedString; + + static KeyboardHandler () { + // our key filter table is a 256 byte array - if the corresponding byte + // is set the key should be filtered from WM_CHAR (apple pushes unicode events + // for some keys which win32 only handles as KEYDOWN + // currently filtered: + // fn+f* == 16 + // left == 28 + // right == 29 + // up == 30 + // down == 31 + // Please update this list as well as the table as more keys are found + key_filter_table = new byte [256] { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + // our char translation table is a set of translations from mac char codes + // to win32 vkey codes + // most things map directly + char_translation_table = new byte [256] { +0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, +16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 0x25, 0x27, 0x26, 0x28, +32, 49, 34, 51, 52, 53, 55, 222, 57, 48, 56, 187, 188, 189, 190, 191, +48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 186, 60, 61, 62, 63, +50, 65, 66, 67, 68, 187, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, +80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 219, 220, 221, 54, 189, +192, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, +80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 0x2e, +128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, +144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, +160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, +176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, +192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, +208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, +224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, +240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 + }; + key_translation_table = new byte [256] { +0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, +16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, +32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, +48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, +64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, +80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, +0x74, 0x75, 0x76, 0x72, 0x77, 0x78, 0x79, 103, 104, 105, 106, 107, 108, 109, 0x7a, 0x7b, +112, 113, 114, 115, 116, 117, 0x73, 119, 0x71, 121, 0x70, 123, 124, 125, 126, 127, +128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, +144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, +160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, +176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, +192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, +208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, +224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, +240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 + }; + // the key modifier table is a state table of the possible modifier keys + // apple currently only goes up to 1 << 14 keys, we've extended this to 32 + // bytes as thats the size that apple uses + key_modifier_table = new byte [32]; + } + + internal KeyboardHandler (XplatUICarbon driver) : base (driver) {} + + private void ModifierToVirtualKey (int i, ref MSG msg, bool down) { + msg.hwnd = XplatUICarbon.FocusWindow; + + if (i == 9 || i == 13) { + msg.message = (down ? Msg.WM_KEYDOWN : Msg.WM_KEYUP); + msg.wParam = (IntPtr) VirtualKeys.VK_SHIFT; + msg.lParam = IntPtr.Zero; + return; + } + if (i == 12 || i == 14) { + msg.message = (down ? Msg.WM_KEYDOWN : Msg.WM_KEYUP); + msg.wParam = (IntPtr) VirtualKeys.VK_CONTROL; + msg.lParam = IntPtr.Zero; + return; + } + if (i == 8) { + msg.message = (down ? Msg.WM_SYSKEYDOWN : Msg.WM_SYSKEYUP); + msg.wParam = (IntPtr) VirtualKeys.VK_MENU; + msg.lParam = new IntPtr (0x20000000); + return; + } + + return; + } + + public void ProcessModifiers (IntPtr eventref, ref MSG msg) { + // we get notified when modifiers change, but not specifically what changed + UInt32 modifiers = 0; + + GetEventParameter (eventref, kEventParamKeyModifiers, typeUInt32, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (UInt32)), IntPtr.Zero, ref modifiers); + + for (int i = 0; i < 32; i++) { + if (key_modifier_table [i] == 0x01 && (modifiers & (1 << i)) == 0) { + ModifierToVirtualKey (i, ref msg, false); + key_modifier_table [i] = 0x00; + return; + } else if (key_modifier_table [i] == 0x00 && (modifiers & (1 << i)) == (1 << i)) { + ModifierToVirtualKey (i, ref msg, true); + key_modifier_table [i] = 0x01; + return; + } + } + + return; + } + + public void ProcessText (IntPtr eventref, ref MSG msg) { + UInt32 size = 0; + IntPtr buffer = IntPtr.Zero; + byte [] bdata; + + // get the size of the unicode buffer + GetEventParameter (eventref, kEventParamTextInputSendText, typeUnicodeText, IntPtr.Zero, 0, ref size, IntPtr.Zero); + + buffer = Marshal.AllocHGlobal ((int) size); + bdata = new byte [size]; + + // get the actual text buffer + GetEventParameter (eventref, kEventParamTextInputSendText, typeUnicodeText, IntPtr.Zero, size, IntPtr.Zero, buffer); + + Marshal.Copy (buffer, bdata, 0, (int) size); + Marshal.FreeHGlobal (buffer); + + if (key_filter_table [bdata [0]] == 0x00) { + if (size == 1) { + msg.message = Msg.WM_CHAR; + msg.wParam = BitConverter.IsLittleEndian ? (IntPtr) bdata [0] : (IntPtr) bdata [size-1]; + msg.lParam = IntPtr.Zero; + msg.hwnd = XplatUICarbon.FocusWindow; + } else { + msg.message = Msg.WM_IME_COMPOSITION; + Encoding enc = BitConverter.IsLittleEndian ? Encoding.Unicode : Encoding.BigEndianUnicode; + ComposedString = enc.GetString (bdata); + msg.hwnd = XplatUICarbon.FocusWindow; + } + } + } + + public void ProcessKeyPress (IntPtr eventref, ref MSG msg) { + byte charCode = 0x0; + byte keyCode = 0x0; + + GetEventParameter (eventref, kEventParamKeyMacCharCodes, typeChar, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (byte)), IntPtr.Zero, ref charCode); + GetEventParameter (eventref, kEventParamKeyCode, typeUInt32, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (byte)), IntPtr.Zero, ref keyCode); + + msg.lParam = (IntPtr) charCode; + msg.wParam = charCode == 0x10 ? (IntPtr) key_translation_table [keyCode] : (IntPtr) char_translation_table [charCode]; + msg.hwnd = XplatUICarbon.FocusWindow; + } + + public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) { + uint klass = EventHandler.GetEventClass (eventref); + bool result = true; + + if (klass == EventHandler.kEventClassTextInput) { + switch (kind) { + case kEventTextInputUnicodeForKeyEvent: + ProcessText (eventref, ref msg); + break; + default: + Console.WriteLine ("WARNING: KeyboardHandler.ProcessEvent default handler for kEventClassTextInput should not be reached"); + break; + } + } else if (klass == EventHandler.kEventClassKeyboard) { + switch (kind) { + case kEventRawKeyDown: + case kEventRawKeyRepeat: + msg.message = Msg.WM_KEYDOWN; + ProcessKeyPress (eventref, ref msg); + break; + case kEventRawKeyUp: + msg.message = Msg.WM_KEYUP; + ProcessKeyPress (eventref, ref msg); + break; + case kEventRawKeyModifiersChanged: + ProcessModifiers (eventref, ref msg); + break; + default: + Console.WriteLine ("WARNING: KeyboardHandler.ProcessEvent default handler for kEventClassKeyboard should not be reached"); + break; + } + } else { + Console.WriteLine ("WARNING: KeyboardHandler.ProcessEvent default handler for kEventClassTextInput should not be reached"); + } + + return result; + } + + public bool TranslateMessage (ref MSG msg) { + bool res = false; + + if (msg.message >= Msg.WM_KEYFIRST && msg.message <= Msg.WM_KEYLAST) + res = true; + + if (msg.message != Msg.WM_KEYDOWN && msg.message != Msg.WM_SYSKEYDOWN && msg.message != Msg.WM_KEYUP && msg.message != Msg.WM_SYSKEYUP && msg.message != Msg.WM_CHAR && msg.message != Msg.WM_SYSCHAR) + return res; + + if (key_modifier_table [8] == 0x01 && key_modifier_table [12] == 0x00 && key_modifier_table [14] == 0x00) { + if (msg.message == Msg.WM_KEYDOWN) { + msg.message = Msg.WM_SYSKEYDOWN; + } else if (msg.message == Msg.WM_CHAR) { + msg.message = Msg.WM_SYSCHAR; + translate_modifier = true; + } else if (msg.message == Msg.WM_KEYUP) { + msg.message = Msg.WM_SYSKEYUP; + } else { + return res; + } + + msg.lParam = new IntPtr (0x20000000); + } else if (msg.message == Msg.WM_SYSKEYUP && translate_modifier && msg.wParam == (IntPtr) 18) { + msg.message = Msg.WM_KEYUP; + + msg.lParam = IntPtr.Zero; + translate_modifier = false; + } + + return res; + } + + internal Keys ModifierKeys { + get { + Keys keys = Keys.None; + if (key_modifier_table [9] == 0x01 || key_modifier_table [13] == 0x01) { keys |= Keys.Shift; } + if (key_modifier_table [8] == 0x01) { keys |= Keys.Alt; } + if (key_modifier_table [12] == 0x01 || key_modifier_table [14] == 0x01) { keys |= Keys.Widget; } + return keys; + } + } + + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, ref UInt32 outsize, IntPtr data); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, IntPtr data); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref byte data); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref UInt32 data); + } + + internal enum KeyboardModifiers : uint { + activeFlag = 1 << 0, + btnState = 1 << 7, + cmdKey = 1 << 8, + shiftKey = 1 << 9, + alphaLock = 1 << 10, + optionKey = 1 << 11, + WidgetKey = 1 << 12, + rightShiftKey = 1 << 13, + rightOptionKey = 1 << 14, + rightWidgetKey = 1 << 14, + } +} diff --git a/source/ShiftUI/Internal/KeysConverter.cs b/source/ShiftUI/Internal/KeysConverter.cs new file mode 100644 index 0000000..6f24eae --- /dev/null +++ b/source/ShiftUI/Internal/KeysConverter.cs @@ -0,0 +1,139 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +using System.Collections; +using System.ComponentModel; +using System.Text; +using System; + +namespace ShiftUI { + public class KeysConverter : TypeConverter, IComparer { + #region Public Constructors + public KeysConverter() { + } + #endregion // Public Constructors + + #region Public Instance Methods + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { + if (sourceType == typeof(string)) { + return true; + } + return false; + } + + public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof (Enum[])) + return true; + + return base.CanConvertTo (context, destinationType); + } + + public int Compare(object a, object b) { + if (a is string && b is string) { + return String.Compare((string) a, (string)b); + } + return String.Compare(a.ToString(), b.ToString()); + } + + public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) { + if (value is string) { + string[] keys; + Keys key; + + keys = ((string)value).Split(new char[] {'+'}); + key = Keys.None; + + if (keys.Length > 1) { + for (int i = 0; i < keys.Length - 1; i++) { + if (keys[i].Equals("Ctrl")) { + key |= Keys.Widget; + } else { + key |= (Keys)Enum.Parse(typeof(Keys), keys[i], true); + } + } + } + if (keys [keys.Length - 1].Equals ("Ctrl")) + key |= Keys.Widget; + else + key |= (Keys)Enum.Parse(typeof(Keys), keys[keys.Length - 1], true); + return key; + } + return base.ConvertFrom (context, culture, value); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) { + if (destinationType == typeof(string)) { + StringBuilder sb; + Keys key; + + sb = new StringBuilder(); + key = (Keys)value; + + // Modifiers first + if ((key & Keys.Widget) != 0) { + sb.Append("Ctrl+"); + } + + if ((key & Keys.Alt) != 0) { + sb.Append("Alt+"); + } + + if ((key & Keys.Shift) != 0) { + sb.Append("Shift+"); + } + + // Keycode last + sb.Append(Enum.GetName(typeof(Keys), key & Keys.KeyCode)); + + return sb.ToString(); + } + return base.ConvertTo (context, culture, value, destinationType); + } + + public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) { + Keys [] stdVal = new Keys [] { Keys.D0, Keys.D1, Keys.D2, Keys.D3, Keys.D4, Keys.D5, Keys.D6, Keys.D7, + Keys.D8, Keys.D9, Keys.Alt, Keys.Back, Keys.Widget, Keys.Delete, Keys.End, Keys.Return, Keys.F1, + Keys.F10, Keys.F11, Keys.F12, Keys.F2, Keys.F3, Keys.F4, Keys.F5, Keys.F6, Keys.F7, Keys.F8, Keys.F9, + Keys.Home, Keys.Insert, Keys.Next, Keys.PageUp, Keys.Shift }; + + return new TypeConverter.StandardValuesCollection (stdVal); + } + + public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) { + + return false; + } + + public override bool GetStandardValuesSupported(ITypeDescriptorContext context) { + return true; + } + + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Internal/LayoutEngine.cs b/source/ShiftUI/Internal/LayoutEngine.cs new file mode 100644 index 0000000..7b2ce71 --- /dev/null +++ b/source/ShiftUI/Internal/LayoutEngine.cs @@ -0,0 +1,43 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Author: +// Miguel de Icaza (miguel@gnome.org) +// +// (C) 2004 Novell, Inc. +// + +using System; +using System.ComponentModel; + +namespace ShiftUI.Layout { + + public abstract class LayoutEngine { + + public virtual void InitLayout (object child, BoundsSpecified specified) + { + } + + public virtual bool Layout (object container, LayoutEventArgs layoutEventArgs) + { + return false; + } + } +} diff --git a/source/ShiftUI/Internal/LayoutSettings.cs b/source/ShiftUI/Internal/LayoutSettings.cs new file mode 100644 index 0000000..a97d744 --- /dev/null +++ b/source/ShiftUI/Internal/LayoutSettings.cs @@ -0,0 +1,40 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Author: +// Miguel de Icaza (miguel@gnome.org) +// +// (C) 2004 Novell, Inc. +// + +using System; +using System.ComponentModel; +using ShiftUI.Layout; + +namespace ShiftUI { + + public abstract class LayoutSettings { + public virtual LayoutEngine LayoutEngine { + get { + return null; + } + } + } +} diff --git a/source/ShiftUI/Internal/Line.cs b/source/ShiftUI/Internal/Line.cs new file mode 100644 index 0000000..a523047 --- /dev/null +++ b/source/ShiftUI/Internal/Line.cs @@ -0,0 +1,811 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +using System; +using System.Collections; +using System.Drawing; +using System.Drawing.Text; +using System.Text; + +namespace ShiftUI +{ + internal class Line : ICloneable, IComparable + { + #region Local Variables + + internal Document document; + // Stuff that matters for our line + internal StringBuilder text; // Characters for the line + internal float[] widths; // Width of each character; always one larger than text.Length + internal int space; // Number of elements in text and widths + internal int line_no; // Line number + internal LineTag tags; // Tags describing the text + internal int offset; // Baseline can be on the X or Y axis depending if we are in multiline mode or not + internal int height; // Height of the line (height of tallest tag) + internal int ascent; // Ascent of the line (ascent of the tallest tag) + internal HorizontalAlignment alignment; // Alignment of the line + internal int align_shift; // Pixel shift caused by the alignment + internal int indent; // Left indent for the first line + internal int hanging_indent; // Hanging indent (left indent for all but the first line) + internal int right_indent; // Right indent for all lines + internal LineEnding ending; + + // Stuff that's important for the tree + internal Line parent; // Our parent line + internal Line left; // Line with smaller line number + internal Line right; // Line with higher line number + internal LineColor color; // We're doing a black/red tree. this is the node color + static int DEFAULT_TEXT_LEN = 0; // + internal bool recalc; // Line changed + + private static Hashtable kerning_fonts = new Hashtable (); // record which fonts use kerning + #endregion // Local Variables + + #region Constructors + internal Line (Document document, LineEnding ending) + { + this.document = document; + color = LineColor.Red; + left = null; + right = null; + parent = null; + text = null; + recalc = true; + alignment = document.alignment; + + this.ending = ending; + } + + internal Line (Document document, int LineNo, string Text, Font font, Color color, LineEnding ending) : this (document, ending) + { + space = Text.Length > DEFAULT_TEXT_LEN ? Text.Length+1 : DEFAULT_TEXT_LEN; + + text = new StringBuilder (Text, space); + line_no = LineNo; + this.ending = ending; + + widths = new float[space + 1]; + + + tags = new LineTag(this, 1); + tags.Font = font; + tags.Color = color; + } + + internal Line (Document document, int LineNo, string Text, HorizontalAlignment align, Font font, Color color, LineEnding ending) : this(document, ending) + { + space = Text.Length > DEFAULT_TEXT_LEN ? Text.Length+1 : DEFAULT_TEXT_LEN; + + text = new StringBuilder (Text, space); + line_no = LineNo; + this.ending = ending; + alignment = align; + + widths = new float[space + 1]; + + + tags = new LineTag(this, 1); + tags.Font = font; + tags.Color = color; + } + + internal Line (Document document, int LineNo, string Text, LineTag tag, LineEnding ending) : this(document, ending) + { + space = Text.Length > DEFAULT_TEXT_LEN ? Text.Length+1 : DEFAULT_TEXT_LEN; + + text = new StringBuilder (Text, space); + this.ending = ending; + line_no = LineNo; + + widths = new float[space + 1]; + tags = tag; + } + + #endregion // Constructors + + #region Internal Properties + internal HorizontalAlignment Alignment { + get { return alignment; } + set { + if (alignment != value) { + alignment = value; + recalc = true; + } + } + } + + internal int HangingIndent { + get { return hanging_indent; } + set { + hanging_indent = value; + recalc = true; + } + } + + // UIA: Method used via reflection in TextRangeProvider + internal int Height { + get { return height; } + set { height = value; } + } + + internal int Indent { + get { return indent; } + set { + indent = value; + recalc = true; + } + } + + internal int LineNo { + get { return line_no; } + set { line_no = value; } + } + + internal int RightIndent { + get { return right_indent; } + set { + right_indent = value; + recalc = true; + } + } + + // UIA: Method used via reflection in TextRangeProvider + internal int Width { + get { + int res = (int) widths [text.Length]; + return res; + } + } + + internal string Text { + get { return text.ToString(); } + set { + int prev_length = text.Length; + text = new StringBuilder(value, value.Length > DEFAULT_TEXT_LEN ? value.Length + 1 : DEFAULT_TEXT_LEN); + + if (text.Length > prev_length) + Grow (text.Length - prev_length); + } + } + + // UIA: Method used via reflection in TextRangeProvider + internal int X { + get { + if (document.multiline) + return align_shift; + return offset + align_shift; + } + } + + // UIA: Method used via reflection in TextRangeProvider + internal int Y { + get { + if (!document.multiline) + return document.top_margin; + return document.top_margin + offset; + } + } + #endregion // Internal Properties + + #region Internal Methods + + /// + /// Builds a simple code to record which tags are links and how many tags + /// used to compare lines before and after to see if the scan for links + /// process has changed anything. + /// + internal void LinkRecord (StringBuilder linkRecord) + { + LineTag tag = tags; + + while (tag != null) { + if (tag.IsLink) + linkRecord.Append ("L"); + else + linkRecord.Append ("N"); + + tag = tag.Next; + } + } + + /// + /// Clears all link properties from tags + /// + internal void ClearLinks () + { + LineTag tag = tags; + + while (tag != null) { + tag.IsLink = false; + tag = tag.Next; + } + } + + public void DeleteCharacters(int pos, int count) + { + LineTag tag; + bool streamline = false; + + // Can't delete more than the line has + if (pos >= text.Length) + return; + + // Find the first tag that we are deleting from + tag = FindTag (pos + 1); + + // Remove the characters from the line + text.Remove (pos, count); + + if (tag == null) + return; + + // Check if we're crossing tag boundaries + if ((pos + count) > (tag.Start + tag.Length - 1)) { + int left; + + // We have to delete cross tag boundaries + streamline = true; + left = count; + + left -= tag.Start + tag.Length - pos - 1; + tag = tag.Next; + + // Update the start of each tag + while ((tag != null) && (left > 0)) { + // Cache tag.Length as is will be indireclty modified + // by changes to tag.Start + int tag_length = tag.Length; + tag.Start -= count - left; + + if (tag_length > left) { + left = 0; + } else { + left -= tag_length; + tag = tag.Next; + } + + } + } else { + // We got off easy, same tag + + if (tag.Length == 0) + streamline = true; + } + + // Delete empty orphaned tags at the end + LineTag walk = tag; + while (walk != null && walk.Next != null && walk.Next.Length == 0) { + LineTag t = walk; + walk.Next = walk.Next.Next; + if (walk.Next != null) + walk.Next.Previous = t; + walk = walk.Next; + } + + // Adjust the start point of any tags following + if (tag != null) { + tag = tag.Next; + while (tag != null) { + tag.Start -= count; + tag = tag.Next; + } + } + + recalc = true; + + if (streamline) + Streamline (document.Lines); + } + + // This doesn't do exactly what you would think, it just pulls off the \n part of the ending + internal void DrawEnding (Graphics dc, float y) + { + if (document.multiline) + return; + LineTag last = tags; + while (last.Next != null) + last = last.Next; + + string end_str = null; + switch (document.LineEndingLength (ending)) { + case 0: + return; + case 1: + end_str = "\u0013"; + break; + case 2: + end_str = "\u0013\u0013"; + break; + case 3: + end_str = "\u0013\u0013\u0013"; + break; + } + + TextBoxTextRenderer.DrawText (dc, end_str, last.Font, last.Color, X + widths [TextLengthWithoutEnding ()] - document.viewport_x + document.OffsetX, y, true); + } + + /// Find the tag on a line based on the character position, pos is 0-based + internal LineTag FindTag (int pos) + { + LineTag tag; + + if (pos == 0) + return tags; + + tag = this.tags; + + if (pos >= text.Length) + pos = text.Length - 1; + + while (tag != null) { + if (((tag.Start - 1) <= pos) && (pos <= (tag.Start + tag.Length - 1))) + return LineTag.GetFinalTag (tag); + + tag = tag.Next; + } + + return null; + } + + public override int GetHashCode () + { + return base.GetHashCode (); + } + + // Get the tag that contains this x coordinate + public LineTag GetTag (int x) + { + LineTag tag = tags; + + // Coord is to the left of the first character + if (x < tag.X) + return LineTag.GetFinalTag (tag); + + // All we have is a linked-list of tags, so we have + // to do a linear search. But there shouldn't be + // too many tags per line in general. + while (true) { + if (x >= tag.X && x < (tag.X + tag.Width)) + return tag; + + if (tag.Next != null) + tag = tag.Next; + else + return LineTag.GetFinalTag (tag); + } + } + + // Make sure we always have enoughs space in text and widths + internal void Grow (int minimum) + { + int length; + float[] new_widths; + + length = text.Length; + + if ((length + minimum) > space) { + // We need to grow; double the size + + if ((length + minimum) > (space * 2)) { + new_widths = new float[length + minimum * 2 + 1]; + space = length + minimum * 2; + } else { + new_widths = new float[space * 2 + 1]; + space *= 2; + } + widths.CopyTo (new_widths, 0); + + widths = new_widths; + } + } + public void InsertString (int pos, string s) + { + InsertString (pos, s, FindTag (pos)); + } + + // Inserts a string at the given position + public void InsertString (int pos, string s, LineTag tag) + { + int len = s.Length; + + // Insert the text into the StringBuilder + text.Insert (pos, s); + + // Update the start position of every tag after this one + tag = tag.Next; + + while (tag != null) { + tag.Start += len; + tag = tag.Next; + } + + // Make sure we have room in the widths array + Grow (len); + + // This line needs to be recalculated + recalc = true; + } + + /// + /// Go through all tags on a line and recalculate all size-related values; + /// returns true if lineheight changed + /// + internal bool RecalculateLine (Graphics g, Document doc) + { + return RecalculateLine (g, doc, kerning_fonts.ContainsKey (tags.Font.GetHashCode ())); + } + + private bool RecalculateLine (Graphics g, Document doc, bool handleKerning) + { + LineTag tag; + int pos; + int len; + SizeF size; + float w; + int prev_offset; + bool retval; + bool wrapped; + Line line; + int wrap_pos; + int prev_height; + int prev_ascent; + + pos = 0; + len = this.text.Length; + tag = this.tags; + prev_offset = this.offset; // For drawing optimization calculations + prev_height = this.height; + prev_ascent = this.ascent; + this.height = 0; // Reset line height + this.ascent = 0; // Reset the ascent for the line + tag.Shift = 0; // Reset shift (which should be stored as pixels, not as points) + + if (ending == LineEnding.Wrap) + widths[0] = document.left_margin + hanging_indent; + else + widths[0] = document.left_margin + indent; + + this.recalc = false; + retval = false; + wrapped = false; + + wrap_pos = 0; + + while (pos < len) { + + while (tag.Length == 0) { // We should always have tags after a tag.length==0 unless len==0 + //tag.Ascent = 0; + tag.Shift = (tag.Line.ascent - tag.Ascent) / 72; + tag = tag.Next; + } + + // kerning is a problem. The original code in this method assumed that the + // width of a string equals the sum of the widths of its characters. This is + // not true when kerning takes place during the display process. Since it's + // impossible to find out easily whether a font does kerning, and with which + // characters, we just detect that kerning must have happened and use a slower + // (but accurate) measurement for those fonts henceforth. Without handling + // kerning, many fonts for English become unreadable during typing for many + // input strings, and text in many other languages is even worse trying to + // type in TextBoxes. + // See https://bugzilla.xamarin.com/show_bug.cgi?id=26478 for details. + float newWidth; + if (handleKerning && !Char.IsWhiteSpace(text[pos])) + { + // MeasureText doesn't measure trailing spaces, so we do the best we can for those + // in the else branch. + size = TextBoxTextRenderer.MeasureText (g, text.ToString (0, pos + 1), tag.Font); + newWidth = widths[0] + size.Width; + } + else + { + size = tag.SizeOfPosition (g, pos); + w = size.Width; + newWidth = widths[pos] + w; + } + + if (Char.IsWhiteSpace (text[pos])) + wrap_pos = pos + 1; + + if (doc.wrap) { + if ((wrap_pos > 0) && (wrap_pos != len) && (newWidth + 5) > (doc.viewport_width - this.right_indent)) { + // Make sure to set the last width of the line before wrapping + widths[pos + 1] = newWidth; + + pos = wrap_pos; + len = text.Length; + doc.Split (this, tag, pos); + ending = LineEnding.Wrap; + len = this.text.Length; + + retval = true; + wrapped = true; + } else if (pos > 1 && newWidth > (doc.viewport_width - this.right_indent)) { + // No suitable wrap position was found so break right in the middle of a word + + // Make sure to set the last width of the line before wrapping + widths[pos + 1] = newWidth; + + doc.Split (this, tag, pos); + ending = LineEnding.Wrap; + len = this.text.Length; + retval = true; + wrapped = true; + } + } + + // Contract all wrapped lines that follow back into our line + if (!wrapped) { + pos++; + + widths[pos] = newWidth; + + if (pos == len) { + line = doc.GetLine (this.line_no + 1); + if ((line != null) && (ending == LineEnding.Wrap || ending == LineEnding.None)) { + // Pull the two lines together + doc.Combine (this.line_no, this.line_no + 1); + len = this.text.Length; + retval = true; + } + } + } + + if (pos == (tag.Start - 1 + tag.Length)) { + // We just found the end of our current tag + tag.Height = tag.MaxHeight (); + + // Check if we're the tallest on the line (so far) + if (tag.Height > this.height) + this.height = tag.Height; // Yep; make sure the line knows + + if (tag.Ascent > this.ascent) { + LineTag t; + + // We have a tag that has a taller ascent than the line; + t = tags; + while (t != null && t != tag) { + t.Shift = (tag.Ascent - t.Ascent) / 72; + t = t.Next; + } + + // Save on our line + this.ascent = tag.Ascent; + } else { + tag.Shift = (this.ascent - tag.Ascent) / 72; + } + + tag = tag.Next; + if (tag != null) { + tag.Shift = 0; + wrap_pos = pos; + } + } + } + + var fullText = text.ToString(); + if (!handleKerning && fullText.Length > 1 && !wrapped) + { + // Check whether kerning takes place for this string and font. + var realSize = TextBoxTextRenderer.MeasureText(g, fullText, tags.Font); + float realWidth = realSize.Width + widths[0]; + // MeasureText ignores trailing whitespace, so we will too at this point. + int length = fullText.TrimEnd().Length; + float sumWidth = widths[length]; + if (realWidth != sumWidth) + { + kerning_fonts.Add(tags.Font.GetHashCode (), true); + // Using a slightly incorrect width this time around isn't that bad. All that happens + // is that the cursor is a pixel or two off until the next character is typed. It's + // the accumulation of pixel after pixel that causes display problems. + } + } + + while (tag != null) { + tag.Shift = (tag.Line.ascent - tag.Ascent) / 72; + tag = tag.Next; + } + + if (this.height == 0) { + this.height = tags.Font.Height; + tags.Height = this.height; + tags.Shift = 0; + } + + if (prev_offset != offset || prev_height != this.height || prev_ascent != this.ascent) + retval = true; + + return retval; + } + + /// + /// Recalculate a single line using the same char for every character in the line + /// + internal bool RecalculatePasswordLine (Graphics g, Document doc) + { + LineTag tag; + int pos; + int len; + float w; + bool ret; + + pos = 0; + len = this.text.Length; + tag = this.tags; + ascent = 0; + tag.Shift = 0; + + this.recalc = false; + widths[0] = document.left_margin + indent; + + w = TextBoxTextRenderer.MeasureText (g, doc.password_char, tags.Font).Width; + + if (this.height != (int)tag.Font.Height) + ret = true; + else + ret = false; + + this.height = (int)tag.Font.Height; + tag.Height = this.height; + + this.ascent = tag.Ascent; + + while (pos < len) { + pos++; + widths[pos] = widths[pos - 1] + w; + } + + return ret; + } + + internal void Streamline (int lines) + { + LineTag current; + LineTag next; + + current = this.tags; + next = current.Next; + + // + // Catch what the loop below wont; eliminate 0 length + // tags, but only if there are other tags after us + // We only eliminate text tags if there is another text tag + // after it. Otherwise we wind up trying to type on picture tags + // + while ((current.Length == 0) && (next != null) && (next.IsTextTag)) { + tags = next; + tags.Previous = null; + current = next; + next = current.Next; + } + + + if (next == null) + return; + + while (next != null) { + // Take out 0 length tags unless it's the last tag in the document + if (current.IsTextTag && next.Length == 0 && next.IsTextTag) { + if ((next.Next != null) || (line_no != lines)) { + current.Next = next.Next; + if (current.Next != null) { + current.Next.Previous = current; + } + next = current.Next; + continue; + } + } + + if (current.Combine (next)) { + next = current.Next; + continue; + } + + current = current.Next; + next = current.Next; + } + } + + internal int TextLengthWithoutEnding () + { + return text.Length - document.LineEndingLength (ending); + } + + internal string TextWithoutEnding () + { + return text.ToString (0, text.Length - document.LineEndingLength (ending)); + } + #endregion // Internal Methods + + #region Administrative + public object Clone () + { + Line clone; + + clone = new Line (document, ending); + + clone.text = text; + + if (left != null) + clone.left = (Line)left.Clone(); + + if (left != null) + clone.left = (Line)left.Clone(); + + return clone; + } + + internal object CloneLine () + { + Line clone; + + clone = new Line (document, ending); + + clone.text = text; + + return clone; + } + + public int CompareTo (object obj) + { + if (obj == null) + return 1; + + if (! (obj is Line)) + throw new ArgumentException("Object is not of type Line", "obj"); + + if (line_no < ((Line)obj).line_no) + return -1; + else if (line_no > ((Line)obj).line_no) + return 1; + else + return 0; + } + + public override bool Equals (object obj) + { + if (obj == null) + return false; + + if (!(obj is Line)) + return false; + + if (obj == this) + return true; + + if (line_no == ((Line)obj).line_no) + return true; + + return false; + } + + public override string ToString() + { + return string.Format ("Line {0}", line_no); + } + #endregion // Administrative + } +} diff --git a/source/ShiftUI/Internal/LineTag.cs b/source/ShiftUI/Internal/LineTag.cs new file mode 100644 index 0000000..e34132c --- /dev/null +++ b/source/ShiftUI/Internal/LineTag.cs @@ -0,0 +1,618 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +using System; +using System.Collections; +using System.Drawing; +using System.Drawing.Text; +using System.Text; + +namespace ShiftUI +{ + internal class LineTag + { + #region Local Variables + // Formatting + private Font font; // System.Drawing.Font object for this tag + private Color color; // The font color for this tag + private Color back_color; // In 2.0 tags can have background colours. + private Font link_font; // Cached font used for link if IsLink + private bool is_link; // Whether this tag is a link + private string link_text; // The full link text e.g. this might be + // word-wrapped to "w" but this would be + // "www.mono-project.com" + + // Payload; text + private int start; // start, in chars; index into Line.text + // 1 based!! + + // Drawing support + private int height; // Height in pixels of the text this tag describes + private int ascent; // Ascent of the font for this tag + private int descent; // Descent of the font for this tag + private int shift; // Shift down for this tag, to stay on baseline + + // Administrative + private Line line; // The line we're on + private LineTag next; // Next tag on the same line + private LineTag previous; // Previous tag on the same line + #endregion + + #region Constructors + public LineTag (Line line, int start) + { + this.line = line; + Start = start; + link_font = null; + is_link = false; + link_text = null; + } + #endregion // Constructors + + #region Public Properties + public int Ascent { + get { return ascent; } + } + + public Color BackColor { + get { return back_color; } + set { back_color = value; } + } + + public Color ColorToDisplay { + get { + if (IsLink == true) + return Color.Blue; + + return color; + } + } + + public Color Color { + get { return color; } + set { color = value; } + } + + public int Descent { + get { return descent; } + } + + public int End { + get { return start + Length; } + } + + public Font FontToDisplay { + get { + if (IsLink) { + if (link_font == null) + link_font = new Font (font.FontFamily, font.Size, font.Style | FontStyle.Underline); + + return link_font; + } + + return font; + } + } + + public Font Font { + get { return font; } + set { + if (font != value) { + link_font = null; + font = value; + + height = Font.Height; + XplatUI.GetFontMetrics (Hwnd.GraphicsContext, Font, out ascent, out descent); + line.recalc = true; + } + } + } + + public int Height { + get { return height; } + set { height = value; } + } + + public virtual bool IsTextTag { + get { return true; } + } + + public int Length { + get { + int res = 0; + if (next != null) + res = next.start - start; + else + res = line.text.Length - (start - 1); + + return res > 0 ? res : 0; + } + } + + public Line Line { + get { return line; } + set { line = value; } + } + + public LineTag Next { + get { return next; } + set { next = value; } + } + + public LineTag Previous { + get { return previous; } + set { previous = value; } + } + + public int Shift { + get { return shift; } + set { shift = value; } + } + + public int Start { + get { return start; } + set { +#if DEBUG + if (value <= 0) + throw new Exception("Start of tag must be 1 or higher!"); + + if (this.Previous != null) { + if (this.Previous.Start == value) + System.Console.Write("Creating empty tag"); + if (this.Previous.Start > value) + throw new Exception("New tag makes an insane tag"); + } +#endif + start = value; + } + } + + public int TextEnd { + get { return start + TextLength; } + } + + public int TextLength { + get { + int res = 0; + if (next != null) + res = next.start - start; + else + res = line.TextLengthWithoutEnding () - (start - 1); + + return res > 0 ? res : 0; + } + } + + public float Width { + get { + if (Length == 0) + return 0; + return line.widths [start + Length - 1] - (start != 0 ? line.widths [start - 1] : 0); + } + } + + public float X { + get { + if (start == 0) + return line.X; + return line.X + line.widths [start - 1]; + } + } + + public bool IsLink { + get { return is_link; } + set { is_link = value; } + } + + public string LinkText { + get { return link_text; } + set { link_text = value; } + } + #endregion + + #region Public Methods + ///Break a tag into two with identical attributes; pos is 1-based; returns tag starting at >pos< or null if end-of-line + public LineTag Break (int pos) + { + LineTag new_tag; + +#if DEBUG + // Sanity + if (pos < this.Start) + throw new Exception ("Breaking at a negative point"); +#endif + +#if DEBUG + if (pos > End) + throw new Exception ("Breaking past the end of a line"); +#endif + + new_tag = new LineTag(line, pos); + new_tag.CopyFormattingFrom (this); + + new_tag.next = this.next; + this.next = new_tag; + new_tag.previous = this; + + if (new_tag.next != null) + new_tag.next.previous = new_tag; + + return new_tag; + } + + /// Combines 'this' tag with 'other' tag + public bool Combine (LineTag other) + { + if (!this.Equals (other)) + return false; + + this.next = other.next; + + if (this.next != null) + this.next.previous = this; + + return true; + } + + public void CopyFormattingFrom (LineTag other) + { + Font = other.font; + color = other.color; + back_color = other.back_color; + } + + public void Delete () + { + // If we are the only tag, we can't be deleted + if (previous == null && next == null) + return; + + // If we are the last tag, deletion is easy + if (next == null) { + previous.next = null; + return; + } + + // Easy cases gone, little tougher, delete ourself + // Update links, and start + next.previous = null; + + LineTag loop = next; + + while (loop != null) { + loop.Start -= Length; + loop = loop.next; + } + + return; + } + + public virtual void Draw (Graphics dc, Color color, float x, float y, int start, int end) + { + TextBoxTextRenderer.DrawText (dc, line.text.ToString (start, end).Replace ("\r", string.Empty), FontToDisplay, color, x, y, false); + } + + public virtual void Draw (Graphics dc, Color color, float xoff, float y, int start, int end, string text) + { + Rectangle measured_text; + Draw (dc, color, xoff, y, start, end, text, out measured_text, false); + } + + /// + /// + /// + /// 0 based start index + public virtual void Draw (Graphics dc, Color color, float xoff, float y, int drawStart, int drawEnd, + string text, out Rectangle measuredText, bool measureText) + { + if (measureText) { + int xstart = (int)line.widths [drawStart] + (int)xoff; + int xend = (int)line.widths [drawEnd] - (int)line.widths [drawStart]; + int ystart = (int)y; + int yend = (int)TextBoxTextRenderer.MeasureText (dc, Text (), FontToDisplay).Height; + + measuredText = new Rectangle (xstart, ystart, xend, yend); + } else { + measuredText = new Rectangle (); + } + + while (drawStart < drawEnd) { + int tab_index = text.IndexOf ("\t", drawStart); + + if (tab_index == -1) + tab_index = drawEnd; + + TextBoxTextRenderer.DrawText (dc, text.Substring (drawStart, tab_index - drawStart).Replace ("\r", string.Empty), FontToDisplay, color, xoff + line.widths [drawStart], y, false); + + // non multilines get the unknown char + if (!line.document.multiline && tab_index != drawEnd) + TextBoxTextRenderer.DrawText (dc, "\u0013", FontToDisplay, color, xoff + line.widths [tab_index], y, true); + + drawStart = tab_index + 1; + } + } + + /// Checks if 'this' tag describes the same formatting options as 'obj' + public override bool Equals (object obj) + { + LineTag other; + + if (obj == null) + return false; + + if (!(obj is LineTag)) + return false; + + if (obj == this) + return true; + + other = (LineTag)obj; + + if (other.IsTextTag != IsTextTag) + return false; + + if (this.IsLink != other.IsLink) + return false; + + if (this.LinkText != other.LinkText) + return false; + + if (this.font.Equals (other.font) && this.color.Equals (other.color)) + return true; + + return false; + } + + /// Finds the tag that describes the character at position 'pos' (0 based) on 'line' + public static LineTag FindTag (Line line, int pos) + { + LineTag tag = line.tags; + + // Beginning of line is a bit special + if (pos == 0) + return tag; // Not sure if we should get the final tag here + + while (tag != null) { + // [H e][l][l o _ W][o r] Text + // [1 2][3][4 5 6 7][8 9] Start + // 3 4 8 10 End + // 0 1 2 3 4 5 6 7 8 9 Pos + if ((tag.start <= pos) && (pos < tag.End)) + return GetFinalTag (tag); + + tag = tag.next; + } + + return null; + } + + /// Applies 'font' and 'brush' to characters starting at 'start' for 'length' chars; + /// Removes any previous tags overlapping the same area; + /// returns true if lineheight has changed + /// 1-based character position on line + public static bool FormatText (Line line, int formatStart, int length, Font font, Color color, Color backColor, FormatSpecified specified) + { + LineTag tag; + LineTag start_tag; + LineTag end_tag; + int end; + bool retval = false; // Assume line-height doesn't change + + // Too simple? + if (((FormatSpecified.Font & specified) == FormatSpecified.Font) && font.Height != line.height) + retval = true; + + line.recalc = true; // This forces recalculation of the line in RecalculateDocument + + // A little sanity, not sure if it's needed, might be able to remove for speed + if (length > line.text.Length) + length = line.text.Length; + + tag = line.tags; + end = formatStart + length; + + // Common special case + if ((formatStart == 1) && (length == tag.Length)) { + SetFormat (tag, font, color, backColor, specified); + return retval; + } + + // empty selection style at begining of line means + // we only need one new tag + if (formatStart == 1 && length == 0) { + line.tags.Break (1); + SetFormat (line.tags, font, color, backColor, specified); + return retval; + } + + start_tag = FindTag (line, formatStart - 1); + + // we are at an empty tag already! + // e.g. [Tag 0 - "He"][Tag 1 = 0 length][Tag 2 "llo world"] + // Find Tag will return tag 0 at position 3, but we should just + // use the empty tag after.. + if (start_tag.End == formatStart && length == 0 && start_tag.Next != null && start_tag.Next.Length == 0) { + SetFormat (start_tag.Next, font, color, backColor, specified); + return retval; + } + + // if we are at the end of a tag, we want to move to the next tag + while (start_tag.End == formatStart && start_tag.Next != null) + start_tag = start_tag.Next; + + tag = start_tag.Break (formatStart); + + // empty selection style at end of line - its the only situation + // where the rest of the tag would be empty, since we moved to the + // begining of next non empty tag + if (tag.Length == 0) { + SetFormat (tag, font, color, backColor, specified); + return retval; + } + + // empty - so we just create another tag for + // after our new (now) empty one.. + if (length == 0) { + tag.Break (formatStart); + SetFormat (tag, font, color, backColor, specified); + return retval; + } + + while (tag != null && tag.End <= end) { + SetFormat (tag, font, color, backColor, specified); + tag = tag.next; + } + + // did the last tag conveniently fit? + if (tag != null && tag.End == end) + return retval; + + /// Now do the last tag + end_tag = FindTag (line, end-1); + + if (end_tag != null) { + end_tag.Break (end); + SetFormat (end_tag, font, color, backColor, specified); + } + + return retval; + } + + // Gets the character at the x-coordinate. Index is based from the + // line, not the start of the tag. + // returns 0 based index (0 means before character at 1, 1 means at character 1) + public int GetCharIndex (int x) + { + int low = start; + int high = low + Length; + int length_no_ending = line.TextLengthWithoutEnding (); + + if (Length == 0) + return low-1; + + if (length_no_ending == 0) + return 0; + + if (x < line.widths [low]) { + if (low == 1 && x > (line.widths [1] / 2)) + return low; + return low - 1; + } + + if (x > line.widths[length_no_ending]) + return length_no_ending; + + while (low < high - 1) { + int mid = (high + low) / 2; + float width = line.widths[mid]; + + if (width < x) + low = mid; + else + high = mid; + } + + float char_width = line.widths[high] - line.widths[low]; + + if ((x - line.widths[low]) >= (char_width / 2)) + return high; + else + return low; + } + + // There can be multiple tags at the same position, we want to make + // sure we are using the very last tag at the given position + // Empty tags are necessary if style is set at a position with + // no length. + public static LineTag GetFinalTag (LineTag tag) + { + LineTag res = tag; + + while (res.Length == 0 && res.next != null && res.next.Length == 0) + res = res.next; + + return res; + } + + public override int GetHashCode () + { + return base.GetHashCode (); + } + + internal virtual int MaxHeight () + { + return font.Height; + } + + private static void SetFormat (LineTag tag, Font font, Color color, Color back_color, FormatSpecified specified) + { + if ((FormatSpecified.Font & specified) == FormatSpecified.Font) { + tag.Font = font; + } + if ((FormatSpecified.Color & specified) == FormatSpecified.Color) + tag.color = color; + if ((FormatSpecified.BackColor & specified) == FormatSpecified.BackColor) { + tag.back_color = back_color; + } + // Console.WriteLine ("setting format: {0} {1} new color {2}", color.Color, specified, tag.color.Color); + } + + public virtual SizeF SizeOfPosition (Graphics dc, int pos) + { + if (pos >= line.TextLengthWithoutEnding () && line.document.multiline) + return SizeF.Empty; + + string text = line.text.ToString (pos, 1); + switch ((int) text [0]) { + case '\t': + if (!line.document.multiline) + goto case 10; + SizeF res = TextBoxTextRenderer.MeasureText (dc, " ", font); + res.Width *= 8.0F; + return res; + case 10: + case 13: + return TextBoxTextRenderer.MeasureText (dc, "\u000D", font); + } + + return TextBoxTextRenderer.MeasureText (dc, text, font); + } + + public virtual string Text () + { + return line.text.ToString (start - 1, Length); + } + + public override string ToString () + { + if (Length > 0) + return string.Format ("{0} Tag starts at index: {1}, length: {2}, text: {3}, font: {4}", GetType (), start, Length, Text (), font.ToString ()); + + return string.Format ("Zero Length tag at index: {0}", start); + } + #endregion // Internal Methods + } +} diff --git a/source/ShiftUI/Internal/ListBindingConverter.cs b/source/ShiftUI/Internal/ListBindingConverter.cs new file mode 100644 index 0000000..46f39e5 --- /dev/null +++ b/source/ShiftUI/Internal/ListBindingConverter.cs @@ -0,0 +1,60 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// NOT COMPLETE + +using System.ComponentModel; +using System; + +namespace ShiftUI { + public class ListBindingConverter : TypeConverter { + #region Public Constructors + public ListBindingConverter() { + } + #endregion // Public Constructors + + #region Public Instance Methods + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { + if (destinationType == typeof(string)) { + return true; + } + return base.CanConvertTo (context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) { + return base.ConvertTo (context, culture, value, destinationType); + } + + public override object CreateInstance(ITypeDescriptorContext context, System.Collections.IDictionary propertyValues) { + return new Binding((string)propertyValues["PropertyName"], (object)propertyValues["DataSource"], (string)propertyValues["DataMember"]); + } + + public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) { + return true; + } + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Internal/ListBindingHelper.cs b/source/ShiftUI/Internal/ListBindingHelper.cs new file mode 100644 index 0000000..2615a33 --- /dev/null +++ b/source/ShiftUI/Internal/ListBindingHelper.cs @@ -0,0 +1,189 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Author: +// Carlos Alberto Cortez +// Ivan Zlatev +// + +using System; +using System.Collections; +using System.ComponentModel; +using System.Reflection; +using System.Collections.Generic; + +namespace ShiftUI +{ + + public static class ListBindingHelper + { + public static object GetList (object list) + { + if (list is IListSource) + return ((IListSource) list).GetList (); + return list; + } + + public static object GetList (object dataSource, string dataMember) + { + dataSource = GetList (dataSource); + if (dataSource == null || dataMember == null || dataMember.Length == 0) + return dataSource; + + PropertyDescriptor property = GetListItemProperties (dataSource).Find (dataMember, true); + if (property == null) + throw new ArgumentException ("dataMember"); + + object item = null; + + ICurrencyManagerProvider currencyManagerProvider = dataSource as ICurrencyManagerProvider; + if (currencyManagerProvider != null && currencyManagerProvider.CurrencyManager != null) { + CurrencyManager currencyManager = currencyManagerProvider.CurrencyManager; + if (currencyManager != null && currencyManager.Count > 0 && currencyManager.Current != null) + item = currencyManager.Current; + } + + if (item == null) { + if (dataSource is IEnumerable) { + if (dataSource is IList) { + IList list = (IList) dataSource; + item = list.Count > 0 ? list[0] : null; + } else { + IEnumerator e = ((IEnumerable) dataSource).GetEnumerator (); + if (e != null && e.MoveNext ()) + item = e.Current; + } + } else { + item = dataSource; + } + } + + if (item != null) + return property.GetValue (item); + return null; + } + + public static Type GetListItemType (object list) + { + return GetListItemType (list, String.Empty); + } + + public static Type GetListItemType (object dataSource, string dataMember) + { + if (dataSource == null) + return null; + + if (dataMember != null && dataMember.Length > 0) { + PropertyDescriptor property = GetProperty (dataSource, dataMember); + if (property == null) + return typeof (object); + + return property.PropertyType; + } + + if (dataSource is Array) + return dataSource.GetType ().GetElementType (); + + // IEnumerable seems to have higher precedence over IList + if (dataSource is IEnumerable) { + IEnumerator enumerator = ((IEnumerable) dataSource).GetEnumerator (); + if (enumerator.MoveNext () && enumerator.Current != null) + return enumerator.Current.GetType (); + + if (dataSource is IList || dataSource.GetType () == typeof (IList<>)) { + PropertyInfo property = GetPropertyByReflection (dataSource.GetType (), "Item"); + if (property != null) // `Item' could be interface-explicit, and thus private + return property.PropertyType; + } + + // fallback to object + return typeof (object); + } + + return dataSource.GetType (); + } + + public static PropertyDescriptorCollection GetListItemProperties (object list) + { + return GetListItemProperties (list, null); + } + + public static PropertyDescriptorCollection GetListItemProperties (object list, PropertyDescriptor [] listAccessors) + { + list = GetList (list); + + if (list == null) + return new PropertyDescriptorCollection (null); + + if (list is ITypedList) + return ((ITypedList)list).GetItemProperties (listAccessors); + + if (listAccessors == null || listAccessors.Length == 0) { + Type item_type = GetListItemType (list); + return TypeDescriptor.GetProperties (item_type, + new Attribute [] { new BrowsableAttribute (true) }); + } + + // Take into account only the first property + Type property_type = listAccessors [0].PropertyType; + if (typeof (IList).IsAssignableFrom (property_type) || typeof (IList<>).IsAssignableFrom (property_type)) { + + PropertyInfo property = GetPropertyByReflection (property_type, "Item"); + return TypeDescriptor.GetProperties (property.PropertyType); + } + + return new PropertyDescriptorCollection (new PropertyDescriptor [0]); + } + + public static PropertyDescriptorCollection GetListItemProperties (object dataSource, string dataMember, + PropertyDescriptor [] listAccessors) + { + throw new NotImplementedException (); + } + + public static string GetListName (object list, PropertyDescriptor [] listAccessors) + { + if (list == null) + return String.Empty; + + Type item_type = GetListItemType (list); + return item_type.Name; + } + + static PropertyDescriptor GetProperty (object obj, string property_name) + { + return TypeDescriptor.GetProperties (obj, + new Attribute [] { new BrowsableAttribute (true) })[property_name]; + } + + // + // Need to use reflection as we need to bypass the TypeDescriptor.GetProperties () limitations + // + static PropertyInfo GetPropertyByReflection (Type type, string property_name) + { + foreach (PropertyInfo prop in type.GetProperties (BindingFlags.Public | BindingFlags.Instance)) + if (prop.Name == property_name) + return prop; + + return null; + } + } +} diff --git a/source/ShiftUI/Internal/MONO-NOTES b/source/ShiftUI/Internal/MONO-NOTES new file mode 100644 index 0000000..2775bb9 --- /dev/null +++ b/source/ShiftUI/Internal/MONO-NOTES @@ -0,0 +1,28 @@ +Application.Idle is invoked on the same thread used to add the event + +our hacky double buffering only works on the client area, not the nc +area. need to move to a more XplatUI solution involving server-side +drawing surfaces (pixmaps in the X case). + +right now the expose/configure event aggregating is done in the +XEventThread (in the hwnd code, but in the thread running the x event +loop). There is probably a way to get it to run in the thread doing +GetMessage, probably by making GetMessage know about both the xevent +and paint queue's, and having it consume the x queue until there's +nothing left, doing the AddExpose stuff there. then, once the xqueue +is empty, consume the paint queue. This has the added benefit of +making the paint queue a ThreadQueue local thing - no locking will be +needed on it, since the only thing touching it will be the thread +running the message pump. + +why do we /nowarn:108? we lose tons of possibly important warnings due to that... + +more event work: + +CheckedListBox: nothing done. +DataGridView*: nothing done. +GridColumnStylesCollection: nothing done, no Component inheritance +GridTableStylesCollection: nothing done, no Component inheritance +MenuItem: what do we do about CloneMenu? we can't have assignment of events like that (look for the #if notyet) +MonthCalendar: nothing done. +Panel: nothing done. see whether the events should be "new" or now.. diff --git a/source/ShiftUI/Internal/MONO-TODO b/source/ShiftUI/Internal/MONO-TODO new file mode 100644 index 0000000..76397d0 --- /dev/null +++ b/source/ShiftUI/Internal/MONO-TODO @@ -0,0 +1,112 @@ +plans for XplatUIX11.cs: + + - 1 thread watching X socket, doing nothing but + XNextEvent/hwnd.Queue.Enqueue (with minimal motion + compression/key repeat detection) + + - figure out how to deal with the selection events, since they + busy loop waiting on a response from the X socket. maybe + block that thread with an event and wake it up when the + event thread get enough info? + + - Idle event raised once regardless of how many thread queues + we have (should it come from the X event thread?) + + - X11Hwnd which caches (amongst other things) the properties + for the toplevel window so we can avoid doing all those + XChangeProperty things on every single UpdateStyle call. + + - have RULES for things (like "do not call this function + except from ...", etc) and make sure they're enforced. + + - SendMessage.. can't we just insert the right message on the + hwnd's queue instead of using SendAsyncMethod? + + - what's the difference between PostMessage and SendMessage? + + - clean up the MESS that is: + GetWindowState + SetWindowState + + and especially: + SetHwndStyles + SetWMStyles + DeriveStyles + the Style handling in CreateWindow + + - multiple screens? do we care? xinerama foo? + + - fix the mostly static, somewhat instance nature of + XplatUIX11.cs. Either make it static, or make it an + instance. + + - we need to rethink the expose event handling. right now + expose events are only handled once all the other events in + the queue are handled. So, if you're resizing quickly you + get no redraws until you're done. maybe look at the + _NET_WM_SYNC_REQUEST protocol (for the resize/redraw case + specifically). Also, the current expose handling has us + accessing the invalid list/rectangle from multiple threads. + + - factor out ALL knowledge of the multiple windows + (client/whole) into the X11Hwnd class, so we can try to + factor it out. + + - clean up the systray icon stuff - right now it destroys (!) + the client_window and sets client_window == whole_window. + ugh. + + - hwnds should keep track of the width/height they report to + SWF as well as the x window's width/height. That is, we + should allow hwnds with 0,0 width/height even though X + doesn't allow it. There's some "zero_size" stuff in Hwnd, + but it still appears impossible to have 0,0 sized Widgets. + + - window (subwindow, really) destruction should move to Hwnd + if possible. + + - remove 90% of "lock (XlibLock)" usage. It's not really + needed at all, except perhaps to synchronize the + XEventThread and the PeekMessage/GetMessage methods. + + - the big synchronization problem now is the XEventQueue + class. I think all queue operations need to be done while + holding a lock, as the events are queued from the + XEventThread and dequeued from GetMessage. + +possible classes: + + - XplatUIX11 (creates the first (only?) X11Display class. + Most calls should just get the hwnd/display and make a + method call) + + - X11Display (manages the display handle, creates the event + thread, keeps ref to an X11Atoms and the X11RootHwnd) + + - XEventThread (does this need to be a separate class? can + probably just be a method in X11Display) + + - X11Hwnd (move all the style translation here? handles + property changes and caches them. window title here too) + + - X11RootHwnd (add the special root window property stuff + here) + + - X11Atoms (per display atom list. should these be properties + or fields? fields probably, with the builtins as constants). + + - Xlib (the pinvoke wrapper for Xlib calls) + +window managers we need to test again: + + - metacity on SLED/SUSE + - metacity on ubuntu edgy + - compiz on SLED + - compiz HEAD + - beryl? or should compiz be enough? + +specs: + +Extended Window Manager Hints: http://standards.freedesktop.org/wm-spec/wm-spec-latest.html +XEmbed spec: http://standards.freedesktop.org/xembed-spec/latest/ +Systray spec: http://standards.freedesktop.org/systemtray-spec/systemtray-spec-0.2.html diff --git a/source/ShiftUI/Internal/MWFCategoryAttribute.cs b/source/ShiftUI/Internal/MWFCategoryAttribute.cs new file mode 100644 index 0000000..5e348f1 --- /dev/null +++ b/source/ShiftUI/Internal/MWFCategoryAttribute.cs @@ -0,0 +1,50 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +using System.ComponentModel; +using ShiftUI; + +namespace System { + [AttributeUsage (AttributeTargets.All, AllowMultiple=false)] + internal sealed class MWFCategoryAttribute : System.ComponentModel.CategoryAttribute { + #region Constructors + public MWFCategoryAttribute() : base() { + } + + public MWFCategoryAttribute(string category) : base(category) { + } + #endregion // Constructors + + #region Methods + protected override string GetLocalizedString(string value) { + return String.Format(value); + } + + #endregion // Methods + } +} diff --git a/source/ShiftUI/Internal/MWFDescriptionAttribute.cs b/source/ShiftUI/Internal/MWFDescriptionAttribute.cs new file mode 100644 index 0000000..38ac348 --- /dev/null +++ b/source/ShiftUI/Internal/MWFDescriptionAttribute.cs @@ -0,0 +1,51 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +using System.ComponentModel; +using ShiftUI; + +namespace System { + [AttributeUsage (AttributeTargets.All, AllowMultiple=false)] + internal sealed class MWFDescriptionAttribute : System.ComponentModel.DescriptionAttribute { + #region Constructors + public MWFDescriptionAttribute() : base() { + } + + public MWFDescriptionAttribute(string category) : base(category) { + } + #endregion // Constructors + + #region Properties + public override string Description { + get { + return String.Format(base.Description); + } + } + #endregion // Properties + } +} diff --git a/source/ShiftUI/Internal/MainMenu.cs b/source/ShiftUI/Internal/MainMenu.cs new file mode 100644 index 0000000..2bb0f3f --- /dev/null +++ b/source/ShiftUI/Internal/MainMenu.cs @@ -0,0 +1,216 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// +// + +// COMPLETE + +using System.ComponentModel; +using System.Drawing; +using System; + +namespace ShiftUI +{ + [ToolboxItemFilter("ShiftUI.MainMenu", ToolboxItemFilterType.Allow)] + public class MainMenu : Menu + { + private RightToLeft right_to_left = RightToLeft.Inherit; + private Form form = null; + + public MainMenu () : base (null) + { + + } + + public MainMenu (MenuItem[] items) : base (items) + { + + } + + public MainMenu (IContainer container) : this () + { + container.Add (this); + } + + #region Events + + static object CollapseEvent = new object (); + + public event EventHandler Collapse { + add { Events.AddHandler (CollapseEvent, value); } + remove { Events.RemoveHandler (CollapseEvent, value); } + } + + #endregion Events + + #region Public Properties + [Localizable(true)] + [AmbientValue (RightToLeft.Inherit)] + public virtual RightToLeft RightToLeft { + get { return right_to_left;} + set { right_to_left = value; } + } + + #endregion Public Properties + + #region Public Methods + + public virtual MainMenu CloneMenu () + { + MainMenu new_menu = new MainMenu (); + new_menu.CloneMenu (this); + return new_menu; + } + + protected override IntPtr CreateMenuHandle () + { + return IntPtr.Zero; + } + + protected override void Dispose (bool disposing) + { + base.Dispose (disposing); + } + + public Form GetForm () + { + return form; + } + + public override string ToString () + { + return base.ToString () + ", GetForm: " + form; + } + + protected internal virtual void OnCollapse (EventArgs e) + { + EventHandler eh = (EventHandler) (Events [CollapseEvent]); + if (eh != null) + eh (this, e); + } + + #endregion Public Methods + + #region Private Methods + + internal void Draw () + { + Message m = Message.Create (Wnd.window.Handle, (int) Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero); + PaintEventArgs pe = XplatUI.PaintEventStart (ref m, Wnd.window.Handle, false); + Draw (pe, Rect); + } + + internal void Draw (Rectangle rect) + { + if (Wnd.IsHandleCreated) { + Point pt = XplatUI.GetMenuOrigin (Wnd.window.Handle); + Message m = Message.Create (Wnd.window.Handle, (int)Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero); + PaintEventArgs pevent = XplatUI.PaintEventStart (ref m, Wnd.window.Handle, false); + pevent.Graphics.SetClip (new Rectangle (rect.X + pt.X, rect.Y + pt.Y, rect.Width, rect.Height)); + Draw (pevent, Rect); + XplatUI.PaintEventEnd (ref m, Wnd.window.Handle, false); + } + } + + internal void Draw (PaintEventArgs pe) + { + Draw (pe, Rect); + } + + internal void Draw (PaintEventArgs pe, Rectangle rect) + { + if (!Wnd.IsHandleCreated) + return; + + X = rect.X; + Y = rect.Y; + Height = Rect.Height; + + ThemeEngine.Current.DrawMenuBar (pe.Graphics, this, rect); + + PaintEventHandler eh = (PaintEventHandler)(Events [PaintEvent]); + if (eh != null) + eh (this, pe); + } + + internal override void InvalidateItem (MenuItem item) + { + Draw (item.bounds); + } + + internal void SetForm (Form form) + { + this.form = form; + Wnd = form; + + if (tracker == null) { + tracker = new MenuTracker (this); + tracker.GrabControl = form; + } + } + + internal override void OnMenuChanged (EventArgs e) + { + base.OnMenuChanged (EventArgs.Empty); + if (form == null) + return; + + Rectangle clip = Rect; + Height = 0; /* need this so the theme code will re-layout the menu items + (why is the theme code doing the layout? argh) */ + + if (!Wnd.IsHandleCreated) + return; + + Message m = Message.Create (Wnd.window.Handle, (int) Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero); + PaintEventArgs pevent = XplatUI.PaintEventStart (ref m, Wnd.window.Handle, false); + pevent.Graphics.SetClip (clip); + + Draw (pevent, clip); + } + + /* Mouse events from the form */ + internal void OnMouseDown (object window, MouseEventArgs args) + { + tracker.OnMouseDown (args); + } + + internal void OnMouseMove (object window, MouseEventArgs e) + { + MouseEventArgs args = new MouseEventArgs (e.Button, e.Clicks, Widget.MousePosition.X, Widget.MousePosition.Y, e.Delta); + tracker.OnMotion (args); + } + + static object PaintEvent = new object (); + + internal event PaintEventHandler Paint { + add { Events.AddHandler (PaintEvent, value); } + remove { Events.RemoveHandler (PaintEvent, value); } + } + + #endregion Private Methods + } +} + + diff --git a/source/ShiftUI/Internal/MdiClient.cs b/source/ShiftUI/Internal/MdiClient.cs new file mode 100644 index 0000000..8c2cf8c --- /dev/null +++ b/source/ShiftUI/Internal/MdiClient.cs @@ -0,0 +1,1003 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +// NOT COMPLETE + +using System.Collections; +using System.ComponentModel; +using System.Drawing; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + [ComVisible (true)] + [ClassInterface(ClassInterfaceType.AutoDispatch)] + [DesignTimeVisible(false)] + [ToolboxItem(false)] + public sealed class MdiClient : Widget { + #region Local Variables + private int mdi_created; + private ImplicitHScrollBar hbar; + private ImplicitVScrollBar vbar; + private SizeGrip sizegrip; + private int hbar_value; + private int vbar_value; + private bool lock_sizing; + private bool initializing_scrollbars; + private int prev_bottom; + private bool setting_windowstates = false; + internal ArrayList mdi_child_list; + private string form_text; + private bool setting_form_text; + private Form active_child; + + #endregion // Local Variables + + #region Public Classes + [ComVisible (false)] + public new class WidgetCollection : Widget.WidgetCollection { + + private MdiClient owner; + + public WidgetCollection(MdiClient owner) : base(owner) { + this.owner = owner; + } + + public override void Add(Widget value) { + if ((value is Form) == false || !(((Form)value).IsMdiChild)) { + throw new ArgumentException("Form must be MdiChild"); + } + owner.mdi_child_list.Add (value); + base.Add (value); + + // newest member is the active one + Form form = (Form) value; + owner.ActiveMdiChild = form; + } + + public override void Remove(Widget value) + { + Form form = value as Form; + if (form != null) { + MdiWindowManager wm = form.WindowManager as MdiWindowManager; + if (wm != null) { + form.Closed -= wm.form_closed_handler; + } + } + + owner.mdi_child_list.Remove (value); + base.Remove (value); + } + } + #endregion // Public Classes + + #region Public Constructors + public MdiClient() + { + mdi_child_list = new ArrayList (); + BackColor = SystemColors.AppWorkspace; + Dock = DockStyle.Fill; + SetStyle (Widgetstyles.Selectable, false); + } + #endregion // Public Constructors + + internal void SendFocusToActiveChild () + { + Form active = this.ActiveMdiChild; + if (active == null) { + ParentForm.SendWidgetFocus (this); + } else { + active.SendWidgetFocus (active); + ParentForm.ActiveWidget = active; + } + } + + internal bool HorizontalScrollbarVisible { + get { return hbar != null && hbar.Visible; } + } + internal bool VerticalScrollbarVisible { + get { return vbar != null && vbar.Visible; } + } + + internal void SetParentText(bool text_changed) + { + if (setting_form_text) + return; + + setting_form_text = true; + + if (text_changed) + form_text = ParentForm.Text; + + if (ParentForm.ActiveMaximizedMdiChild == null) { + ParentForm.Text = form_text; + } else { + string childText = ParentForm.ActiveMaximizedMdiChild.form.Text; + if (childText.Length > 0) { + ParentForm.Text = form_text + " - [" + ParentForm.ActiveMaximizedMdiChild.form.Text + "]"; + } else { + ParentForm.Text = form_text; + } + } + + setting_form_text = false; + } + + internal override void OnPaintBackgroundInternal (PaintEventArgs pe) + { + if (BackgroundImage != null) + return; + + if (Parent == null || Parent.BackgroundImage == null) + return; + Parent.PaintWidgetBackground (pe); + } + + internal Form ParentForm { + get { return (Form) Parent; } + } + + protected override Widget.WidgetCollection CreateWidgetsInstance () + { + return new MdiClient.WidgetCollection (this); + } + + protected override void WndProc(ref Message m) { + switch ((Msg)m.Msg) { + case Msg.WM_NCPAINT: + PaintEventArgs pe = XplatUI.PaintEventStart (ref m, Handle, false); + + Rectangle clip; + clip = new Rectangle (0, 0, Width, Height); + + WidgetPaint.DrawBorder3D (pe.Graphics, clip, Border3DStyle.Sunken); + XplatUI.PaintEventEnd (ref m, Handle, false); + m.Result = IntPtr.Zero; + return ; + } + + base.WndProc (ref m); + } + + protected override void OnResize (EventArgs e) + { + base.OnResize (e); + + if (Parent != null && Parent.IsHandleCreated) + XplatUI.InvalidateNC (Parent.Handle); + // Should probably make this into one loop + SizeScrollBars (); + ArrangeWindows (); + } + + protected override void ScaleWidget (SizeF factor, BoundsSpecified specified) + { + // Never change the MdiClient's location + specified &= ~BoundsSpecified.Location; + + base.ScaleWidget (factor, specified); + } + + [System.ComponentModel.EditorBrowsable (EditorBrowsableState.Never)] + protected override void ScaleCore (float dx, float dy) + { + base.ScaleCore (dx, dy); + } + + protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified) + { + base.SetBoundsCore (x, y, width, height, specified); + } + + #region Public Instance Properties + [Localizable(true)] + public override System.Drawing.Image BackgroundImage { + get { + return base.BackgroundImage; + } + set { + base.BackgroundImage = value; + } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public override ImageLayout BackgroundImageLayout { + get { + return base.BackgroundImageLayout; + } + set { + base.BackgroundImageLayout = value; + } + } + + public Form [] MdiChildren { + get { + if (mdi_child_list == null) + return new Form [0]; + return (Form []) mdi_child_list.ToArray (typeof (Form)); + } + } + #endregion // Public Instance Properties + +#region Protected Instance Properties + protected override CreateParams CreateParams { + get { + CreateParams result = base.CreateParams; + result.ExStyle |= (int) WindowExStyles.WS_EX_CLIENTEDGE; + return result; + } + } + #endregion // Protected Instance Properties + + #region Public Instance Methods + public void LayoutMdi (MdiLayout value) { + + // Don't forget to always call ArrangeIconicWindows + ArrangeIconicWindows (true); + + switch (value) { + case MdiLayout.Cascade: { + int i = 0; + for (int c = Widgets.Count - 1; c >= 0; c--) { + Form form = (Form) Widgets [c]; + + if (form.WindowState == FormWindowState.Minimized) + continue; + + if (form.WindowState == FormWindowState.Maximized) + form.WindowState = FormWindowState.Normal; + + form.Width = System.Convert.ToInt32 (ClientSize.Width * 0.8); + form.Height = Math.Max ( + System.Convert.ToInt32 (ClientSize.Height * 0.8), + SystemInformation.MinimumWindowSize.Height + 2); + + int l = 22 * i; + int t = 22 * i; + + if (i != 0 && (l + form.Width > ClientSize.Width || t + form.Height > ClientSize.Height)) { + i = 0; + l = 22 * i; + t = 22 * i; + } + + form.Left = l; + form.Top = t; + + i++; + } + break; + } + case MdiLayout.TileHorizontal: + case MdiLayout.TileVertical: { + // First count number of windows to tile + int total = 0; + + // And space used by iconic windows + int clientHeight = ClientSize.Height; + + for (int i = 0; i < Widgets.Count; i++) { + Form form = Widgets [i] as Form; + + if (form == null) + continue; + + if (!form.Visible) + continue; + + if (form.WindowState == FormWindowState.Maximized) + form.WindowState = FormWindowState.Normal; + else if (form.WindowState == FormWindowState.Minimized) { + if (form.Bounds.Top < clientHeight) + clientHeight = form.Bounds.Top; + continue; + } + + total++; + } + if (total <= 0) + return; + + // Calculate desired height and width + Size newSize; + Size offset; + + if (value == MdiLayout.TileHorizontal) { + newSize = new Size(ClientSize.Width, clientHeight / total); + offset = new Size (0, newSize.Height); + } else { + newSize = new Size(ClientSize.Width / total, clientHeight); + offset = new Size (newSize.Width, 0); + } + + // Loop again and set the size and location. + Point nextLocation = Point.Empty; + + for (int i = 0; i < Widgets.Count; i++) { + Form form = Widgets [i] as Form; + + if (form == null) + continue; + + if (!form.Visible) + continue; + + if (form.WindowState == FormWindowState.Minimized) + continue; + + form.Size = newSize; + form.Location = nextLocation; + nextLocation += offset; + } + + break; + } + } + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + #endregion // Protected Instance Methods + + internal void SizeScrollBars () + { + if (lock_sizing) + return; + + if (!IsHandleCreated) + return; + + if (Widgets.Count == 0 || ((Form) Widgets [0]).WindowState == FormWindowState.Maximized) { + if (hbar != null) + hbar.Visible = false; + if (vbar != null) + vbar.Visible = false; + if (sizegrip != null) + sizegrip.Visible = false; + return; + } + + int right = 0; + int left = 0; + int top = 0; + int bottom = 0; + + foreach (Form child in Widgets) { + if (!child.Visible) + continue; + if (child.Right > right) + right = child.Right; + if (child.Left < left) { + left = child.Left; + } + + if (child.Bottom > bottom) + bottom = child.Bottom; + if (child.Top < 0) { + top = child.Top; + } + } + + int available_width = ClientSize.Width; + int available_height = ClientSize.Height; + + bool need_hbar = false; + bool need_vbar = false; + + if (right - left > available_width || left < 0) { + need_hbar = true; + available_height -= SystemInformation.HorizontalScrollBarHeight; + } + if (bottom - top > available_height || top < 0) { + need_vbar = true; + available_width -= SystemInformation.VerticalScrollBarWidth; + + if (!need_hbar && (right - left > available_width || left < 0)) { + need_hbar = true; + available_height -= SystemInformation.HorizontalScrollBarHeight; + } + } + + if (need_hbar) { + if (hbar == null) { + hbar = new ImplicitHScrollBar (); + Widgets.AddImplicit (hbar); + } + hbar.Visible = true; + CalcHBar (left, right, need_vbar); + } else if (hbar != null) + hbar.Visible = false; + + if (need_vbar) { + if (vbar == null) { + vbar = new ImplicitVScrollBar (); + Widgets.AddImplicit (vbar); + } + vbar.Visible = true; + CalcVBar (top, bottom, need_hbar); + } else if (vbar != null) + vbar.Visible = false; + + if (need_hbar && need_vbar) { + if (sizegrip == null) { + sizegrip = new SizeGrip (this.ParentForm); + Widgets.AddImplicit (sizegrip); + } + sizegrip.Location = new Point (hbar.Right, vbar.Bottom); + sizegrip.Visible = true; + XplatUI.SetZOrder (sizegrip.Handle, vbar.Handle, false, false); + } else if (sizegrip != null) { + sizegrip.Visible = false; + } + + XplatUI.InvalidateNC (Handle); + } + + private void CalcHBar (int left, int right, bool vert_vis) + { + initializing_scrollbars = true; + + hbar.Left = 0; + hbar.Top = ClientRectangle.Bottom - hbar.Height; + hbar.Width = ClientRectangle.Width - (vert_vis ? SystemInformation.VerticalScrollBarWidth : 0); + hbar.LargeChange = 50; + hbar.Minimum = Math.Min (left, 0); + hbar.Maximum = Math.Max (right - ClientSize.Width + 51 + (vert_vis ? SystemInformation.VerticalScrollBarWidth : 0), 0); + hbar.Value = 0; + hbar_value = 0; + hbar.ValueChanged += new EventHandler (HBarValueChanged); + XplatUI.SetZOrder (hbar.Handle, IntPtr.Zero, true, false); + + initializing_scrollbars = false; + } + + private void CalcVBar (int top, int bottom, bool horz_vis) + { + initializing_scrollbars = true; + + vbar.Top = 0; + vbar.Left = ClientRectangle.Right - vbar.Width; + vbar.Height = ClientRectangle.Height - (horz_vis ? SystemInformation.HorizontalScrollBarHeight : 0); + vbar.LargeChange = 50; + vbar.Minimum = Math.Min (top, 0); + vbar.Maximum = Math.Max (bottom - ClientSize.Height + 51 + (horz_vis ? SystemInformation.HorizontalScrollBarHeight : 0), 0); + vbar.Value = 0; + vbar_value = 0; + vbar.ValueChanged += new EventHandler (VBarValueChanged); + XplatUI.SetZOrder (vbar.Handle, IntPtr.Zero, true, false); + + initializing_scrollbars = false; + } + + private void HBarValueChanged (object sender, EventArgs e) + { + if (initializing_scrollbars) + return; + + if (hbar.Value == hbar_value) + return; + + lock_sizing = true; + + try { + int diff = hbar_value - hbar.Value; + foreach (Form child in Widgets) { + child.Left += diff; + } + } finally { + lock_sizing = false; + } + + hbar_value = hbar.Value; + } + + private void VBarValueChanged (object sender, EventArgs e) + { + if (initializing_scrollbars) + return; + + if (vbar.Value == vbar_value) + return; + + lock_sizing = true; + + try { + int diff = vbar_value - vbar.Value; + foreach (Form child in Widgets) { + child.Top += diff; + } + } finally { + lock_sizing = false; + } + + vbar_value = vbar.Value; + } + + private void ArrangeWindows () + { + if (!IsHandleCreated) + return; + + int change = 0; + if (prev_bottom != -1) + change = Bottom - prev_bottom; + + foreach (Widget c in Widgets) { + Form child = c as Form; + + if (c == null || !child.Visible) + continue; + + MdiWindowManager wm = child.WindowManager as MdiWindowManager; + if (wm.GetWindowState () == FormWindowState.Maximized) + child.Bounds = wm.MaximizedBounds; + + if (wm.GetWindowState () == FormWindowState.Minimized) { + child.Top += change; + } + + } + + prev_bottom = Bottom; + } + + internal void ArrangeIconicWindows (bool rearrange_all) + { + Rectangle rect = Rectangle.Empty; + + lock_sizing = true; + foreach (Form form in Widgets) { + if (form.WindowState != FormWindowState.Minimized) + continue; + + MdiWindowManager wm = (MdiWindowManager) form.WindowManager; + + if (wm.IconicBounds != Rectangle.Empty && !rearrange_all) { + if (form.Bounds != wm.IconicBounds) + form.Bounds = wm.IconicBounds; + continue; + } + + bool success = true; + int startx, starty, currentx, currenty; + + rect.Size = wm.IconicSize; + + startx = 0; + starty = ClientSize.Height - rect.Height; + currentx = startx; + currenty = starty; + + do { + rect.X = currentx; + rect.Y = currenty; + success = true; + foreach (Form form2 in Widgets) { + if (form2 == form || form2.window_state != FormWindowState.Minimized) + continue; + + if (form2.Bounds.IntersectsWith(rect)) { + success = false; + break; + } + } + if (!success) { + currentx += rect.Width; + if (currentx + rect.Width > Right) { + currentx = startx; + currenty -= rect.Height; + } + } + } while (!success); + wm.IconicBounds = rect; + form.Bounds = wm.IconicBounds; + } + lock_sizing = false; + } + + internal void ChildFormClosed (Form form) + { + FormWindowState closed_form_windowstate = form.WindowState; + + form.Visible = false; + Widgets.Remove (form); + + if (Widgets.Count == 0) { + ((MdiWindowManager) form.window_manager).RaiseDeactivate (); + } else if (closed_form_windowstate == FormWindowState.Maximized) { + Form current = (Form) Widgets [0]; + current.WindowState = FormWindowState.Maximized; + ActivateChild(current); + } + + if (Widgets.Count == 0) { + XplatUI.RequestNCRecalc (Parent.Handle); + ParentForm.PerformLayout (); + + // If we closed the last child, unmerge the menus. + // If it's not the last child, the menu will be unmerged + // when another child takes focus. + MenuStrip parent_menu = form.MdiParent.MainMenuStrip; + + if (parent_menu != null) + if (parent_menu.IsCurrentlyMerged) + ToolStripManager.RevertMerge (parent_menu); + } + SizeScrollBars (); + SetParentText (false); + form.Dispose(); + } + + internal void ActivateNextChild () + { + if (Widgets.Count < 1) + return; + if (Widgets.Count == 1 && Widgets[0] == ActiveMdiChild) + return; + + Form front = (Form) Widgets [0]; + Form form = (Form) Widgets [1]; + + ActivateChild (form); + front.SendToBack (); + } + + internal void ActivatePreviousChild () + { + if (Widgets.Count <= 1) + return; + + Form back = (Form) Widgets [Widgets.Count - 1]; + + ActivateChild (back); + } + + internal void ActivateChild (Form form) + { + if (Widgets.Count < 1) + return; + + if (ParentForm.is_changing_visible_state > 0) + return; + + Form current = (Form) Widgets [0]; + bool raise_deactivate = ParentForm.ActiveWidget == current; + + // We want to resize the new active form before it is + // made active to avoid flickering. Can't do it in the + // normal way (form.WindowState = Maximized) since it's not + // active yet and everything would just return to before. + // We also won't suspend layout, this way the layout will + // happen before the form is made active (and in many cases + // before it is visible, which avoids flickering as well). + MdiWindowManager wm = (MdiWindowManager)form.WindowManager; + + if (current.WindowState == FormWindowState.Maximized && form.WindowState != FormWindowState.Maximized && form.Visible) { + FormWindowState old_state = form.window_state; + SetWindowState (form, old_state, FormWindowState.Maximized, true); + wm.was_minimized = form.window_state == FormWindowState.Minimized; + form.window_state = FormWindowState.Maximized; + SetParentText (false); + } + + form.BringToFront (); + form.SendWidgetFocus (form); + SetWindowStates (wm); + if (current != form) { + form.has_focus = false; + if (current.IsHandleCreated) + XplatUI.InvalidateNC (current.Handle); + if (form.IsHandleCreated) + XplatUI.InvalidateNC (form.Handle); + if (raise_deactivate) { + MdiWindowManager current_wm = (MdiWindowManager) current.window_manager; + current_wm.RaiseDeactivate (); + + } + } + active_child = (Form) Widgets [0]; + + if (active_child.Visible) { + bool raise_activated = ParentForm.ActiveWidget != active_child; + ParentForm.ActiveWidget = active_child; + if (raise_activated) { + MdiWindowManager active_wm = (MdiWindowManager) active_child.window_manager; + active_wm.RaiseActivated (); + } + } + } + + internal override IntPtr AfterTopMostWidget () + { + // order of scrollbars: + // top = vertical + // sizegrid + // bottom = horizontal + if (hbar != null && hbar.Visible) + return hbar.Handle; + // no need to check for sizegrip since it will only + // be visible if hbar is visible. + if (vbar != null && vbar.Visible) + return vbar.Handle; + + return base.AfterTopMostWidget (); + } + + internal bool SetWindowStates (MdiWindowManager wm) + { + /* + MDI WindowState behaviour: + - If the active window is maximized, all other maximized windows are normalized. + - If a normal window gets focus and the original active window was maximized, + the normal window gets maximized and the original window gets normalized. + - If a minimized window gets focus and the original window was maximized, + the minimzed window gets maximized and the original window gets normalized. + If the ex-minimized window gets deactivated, it will be normalized. + */ + Form form = wm.form; + + if (setting_windowstates) { + return false; + } + + if (!form.Visible) + return false; + + bool is_active = wm.IsActive; + bool maximize_this = false; + + if (!is_active){ + return false; + } + + ArrayList minimize_these = new ArrayList (); + ArrayList normalize_these = new ArrayList (); + + setting_windowstates = true; + foreach (Form frm in mdi_child_list) { + if (frm == form) { + continue; + } else if (!frm.Visible){ + continue; + } + if (frm.WindowState == FormWindowState.Maximized && is_active) { + maximize_this = true; + if (((MdiWindowManager) frm.window_manager).was_minimized) { + minimize_these.Add (frm); + } else { + normalize_these.Add (frm); + } + } + } + + if (maximize_this && form.WindowState != FormWindowState.Maximized) { + wm.was_minimized = form.window_state == FormWindowState.Minimized; + form.WindowState = FormWindowState.Maximized; + } + + foreach (Form frm in minimize_these) + frm.WindowState = FormWindowState.Minimized; + + foreach (Form frm in normalize_these) + frm.WindowState = FormWindowState.Normal; + + + SetParentText (false); + + XplatUI.RequestNCRecalc (ParentForm.Handle); + XplatUI.RequestNCRecalc (Handle); + + SizeScrollBars (); + + setting_windowstates = false; + + if (form.MdiParent.MainMenuStrip != null) + form.MdiParent.MainMenuStrip.RefreshMdiItems (); + + // Implicit menu strip merging + // - When child is activated + // - Parent form must have a MainMenuStrip + // - Find the first menustrip on the child + // - Merge + MenuStrip parent_menu = form.MdiParent.MainMenuStrip; + + if (parent_menu != null) { + if (parent_menu.IsCurrentlyMerged) + ToolStripManager.RevertMerge (parent_menu); + + MenuStrip child_menu = LookForChildMenu (form); + + if (form.WindowState != FormWindowState.Maximized) + RemoveControlMenuItems (wm); + + if (form.WindowState == FormWindowState.Maximized) { + bool found = false; + + foreach (ToolStripItem tsi in parent_menu.Items) { + if (tsi is MdiWidgetStrip.SystemMenuItem) { + (tsi as MdiWidgetStrip.SystemMenuItem).MdiForm = form; + found = true; + } else if (tsi is MdiWidgetStrip.WidgetBoxMenuItem) { + (tsi as MdiWidgetStrip.WidgetBoxMenuItem).MdiForm = form; + found = true; + } + } + + if (!found) { + parent_menu.SuspendLayout (); + parent_menu.Items.Insert (0, new MdiWidgetStrip.SystemMenuItem (form)); + parent_menu.Items.Add (new MdiWidgetStrip.WidgetBoxMenuItem (form, MdiWidgetStrip.ControlBoxType.Close)); + parent_menu.Items.Add (new MdiWidgetStrip.WidgetBoxMenuItem (form, MdiWidgetStrip.ControlBoxType.Max)); + parent_menu.Items.Add (new MdiWidgetStrip.WidgetBoxMenuItem (form, MdiWidgetStrip.ControlBoxType.Min)); + parent_menu.ResumeLayout (); + } + } + + if (child_menu != null) + ToolStripManager.Merge (child_menu, parent_menu); + } + + return maximize_this; + } + + private MenuStrip LookForChildMenu (Widget parent) + { + foreach (Widget c in parent.Widgets) { + if (c is MenuStrip) + return (MenuStrip)c; + + if (c is ToolStripContainer || c is ToolStripPanel) { + MenuStrip ms = LookForChildMenu (c); + + if (ms != null) + return ms; + } + } + + return null; + } + + internal void RemoveControlMenuItems (MdiWindowManager wm) + { + Form form = wm.form; + MenuStrip parent_menu = form.MdiParent.MainMenuStrip; + + // Only remove the items if the form requesting still owns the menu items + if (parent_menu != null) { + parent_menu.SuspendLayout (); + + for (int i = parent_menu.Items.Count - 1; i >= 0; i--) { + if (parent_menu.Items[i] is MdiWidgetStrip.SystemMenuItem) { + if ((parent_menu.Items[i] as MdiWidgetStrip.SystemMenuItem).MdiForm == form) + parent_menu.Items.RemoveAt (i); + } else if (parent_menu.Items[i] is MdiWidgetStrip.WidgetBoxMenuItem) { + if ((parent_menu.Items[i] as MdiWidgetStrip.WidgetBoxMenuItem).MdiForm == form) + parent_menu.Items.RemoveAt (i); + } + } + + parent_menu.ResumeLayout (); + } + } + + internal void SetWindowState (Form form, FormWindowState old_window_state, FormWindowState new_window_state, bool is_activating_child) + { + bool mdiclient_layout; + + MdiWindowManager wm = (MdiWindowManager) form.window_manager; + + if (!is_activating_child && new_window_state == FormWindowState.Maximized && !wm.IsActive) { + ActivateChild (form); + return; + } + + if (old_window_state == FormWindowState.Normal) + wm.NormalBounds = form.Bounds; + + if (SetWindowStates (wm)) + return; + + if (old_window_state == new_window_state) + return; + + mdiclient_layout = old_window_state == FormWindowState.Maximized || new_window_state == FormWindowState.Maximized; + + switch (new_window_state) { + case FormWindowState.Minimized: + ArrangeIconicWindows (false); + break; + case FormWindowState.Maximized: + form.Bounds = wm.MaximizedBounds; + break; + case FormWindowState.Normal: + form.Bounds = wm.NormalBounds; + break; + } + + wm.UpdateWindowDecorations (new_window_state); + + form.ResetCursor (); + + if (mdiclient_layout) + Parent.PerformLayout (); + + XplatUI.RequestNCRecalc (Parent.Handle); + XplatUI.RequestNCRecalc (form.Handle); + if (!setting_windowstates) + SizeScrollBars (); + } + internal int ChildrenCreated { + get { return mdi_created; } + set { mdi_created = value; } + } + + internal Form ActiveMdiChild { + get { + if (ParentForm != null && !ParentForm.Visible) + return null; + + if (Widgets.Count < 1) + return null; + + if (!ParentForm.IsHandleCreated) + return null; + + if (!ParentForm.has_been_visible) + return null; + + if (!ParentForm.Visible) + return active_child; + + active_child = null; + for (int i = 0; i < Widgets.Count; i++) { + if (Widgets [i].Visible) { + active_child = (Form) Widgets [i]; + break; + } + } + return active_child; + } + set { + ActivateChild (value); + } + } + + internal void ActivateActiveMdiChild () + { + if (ParentForm.is_changing_visible_state > 0) + return; + + for (int i = 0; i < Widgets.Count; i++) { + if (Widgets [i].Visible) { + ActivateChild ((Form) Widgets [i]); + return; + } + } + } + } +} + diff --git a/source/ShiftUI/Internal/MdiControlStrip.cs b/source/ShiftUI/Internal/MdiControlStrip.cs new file mode 100644 index 0000000..a04e02a --- /dev/null +++ b/source/ShiftUI/Internal/MdiControlStrip.cs @@ -0,0 +1,207 @@ +// +// MdiWidgetstrip.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Runtime.InteropServices; +using System.ComponentModel; +using System.Drawing; +using ShiftUI.Layout; +using System.Collections.Generic; +using System.ComponentModel.Design.Serialization; + +namespace ShiftUI +{ + internal class MdiWidgetStrip + { + public class SystemMenuItem : ToolStripMenuItem + { + private Form form; + + public SystemMenuItem (Form ownerForm) + { + form = ownerForm; + + base.AutoSize = false; + base.Size = new Size (20, 20); + base.Image = ownerForm.Icon.ToBitmap (); + base.MergeIndex = int.MinValue; + base.DisplayStyle = ToolStripItemDisplayStyle.Image; + + DropDownItems.Add ("&Restore", null, RestoreItemHandler); + ToolStripMenuItem tsiMove = (ToolStripMenuItem)DropDownItems.Add ("&Move"); + tsiMove.Enabled = false; + ToolStripMenuItem tsiSize = (ToolStripMenuItem)DropDownItems.Add ("&Size"); + tsiSize.Enabled = false; + DropDownItems.Add ("Mi&nimize", null, MinimizeItemHandler); + ToolStripMenuItem tsiMaximize = (ToolStripMenuItem)DropDownItems.Add ("Ma&ximize"); + tsiMaximize.Enabled = false; + DropDownItems.Add ("-"); + ToolStripMenuItem tsiClose = (ToolStripMenuItem)DropDownItems.Add ("&Close", null, CloseItemHandler); + tsiClose.ShortcutKeys = Keys.Widget | Keys.F4; + DropDownItems.Add ("-"); + ToolStripMenuItem tsiNext = (ToolStripMenuItem)DropDownItems.Add ("Nex&t", null, NextItemHandler); + tsiNext.ShortcutKeys = Keys.Widget | Keys.F6; + } + + protected override void OnPaint (PaintEventArgs e) + { + // Can't render without an owner + if (this.Owner == null) + return; + + // If DropDown.ShowImageMargin is false, we don't display the image + Image draw_image = this.Image; + + // Figure out where our text and image go + Rectangle text_layout_rect; + Rectangle image_layout_rect; + + this.CalculateTextAndImageRectangles (out text_layout_rect, out image_layout_rect); + + if (image_layout_rect != Rectangle.Empty) + this.Owner.Renderer.DrawItemImage (new ToolStripItemImageRenderEventArgs (e.Graphics, this, draw_image, image_layout_rect)); + + return; + } + + public Form MdiForm { + get { return form; } + set { form = value; } + } + + private void RestoreItemHandler (object sender, EventArgs e) + { + form.WindowState = FormWindowState.Normal; + } + + private void MinimizeItemHandler (object sender, EventArgs e) + { + form.WindowState = FormWindowState.Minimized; + } + + private void CloseItemHandler (object sender, EventArgs e) + { + form.Close (); + } + + private void NextItemHandler (object sender, EventArgs e) + { + form.MdiParent.MdiContainer.ActivateNextChild (); + } + } + + public class WidgetBoxMenuItem : ToolStripMenuItem + { + private Form form; + private ControlBoxType type; + + public WidgetBoxMenuItem (Form ownerForm, ControlBoxType type) + { + form = ownerForm; + this.type = type; + + base.AutoSize = false; + base.Alignment = ToolStripItemAlignment.Right; + base.Size = new Size (20, 20); + base.MergeIndex = int.MaxValue; + base.DisplayStyle = ToolStripItemDisplayStyle.None; + + switch (type) { + case ControlBoxType.Close: + this.Click += new EventHandler(CloseItemHandler); + break; + case ControlBoxType.Min: + this.Click += new EventHandler (MinimizeItemHandler); + break; + case ControlBoxType.Max: + this.Click += new EventHandler (RestoreItemHandler); + break; + } + } + + protected override void OnPaint (PaintEventArgs e) + { + base.OnPaint (e); + Graphics g = e.Graphics; + + switch (type) { + case ControlBoxType.Close: + g.FillRectangle (Brushes.Black, 8, 8, 4, 4); + g.FillRectangle (Brushes.Black, 6, 6, 2, 2); + g.FillRectangle (Brushes.Black, 6, 12, 2, 2); + g.FillRectangle (Brushes.Black, 12, 6, 2, 2); + g.FillRectangle (Brushes.Black, 12, 12, 2, 2); + g.DrawLine (Pens.Black, 8, 7, 8, 12); + g.DrawLine (Pens.Black, 7, 8, 12, 8); + g.DrawLine (Pens.Black, 11, 7, 11, 12); + g.DrawLine (Pens.Black, 7, 11, 12, 11); + break; + case ControlBoxType.Min: + g.DrawLine (Pens.Black, 6, 12, 11, 12); + g.DrawLine (Pens.Black, 6, 13, 11, 13); + break; + case ControlBoxType.Max: + g.DrawLines (Pens.Black, new Point[] {new Point (7, 8), new Point (7, 5), new Point (13, 5), new Point (13, 10), new Point (11, 10)}); + g.DrawLine (Pens.Black, 7, 6, 12, 6); + + g.DrawRectangle (Pens.Black, new Rectangle (5, 8, 6, 5)); + g.DrawLine (Pens.Black, 5, 9, 11, 9); + + break; + } + } + + public Form MdiForm { + get { return form; } + set { form = value; } + } + + private void RestoreItemHandler (object sender, EventArgs e) + { + form.WindowState = FormWindowState.Normal; + } + + private void MinimizeItemHandler (object sender, EventArgs e) + { + form.WindowState = FormWindowState.Minimized; + } + + private void CloseItemHandler (object sender, EventArgs e) + { + form.Close (); + } + } + + public enum ControlBoxType + { + Close, + Min, + Max + } + } +} diff --git a/source/ShiftUI/Internal/MdiLayout.cs b/source/ShiftUI/Internal/MdiLayout.cs new file mode 100644 index 0000000..8c610a4 --- /dev/null +++ b/source/ShiftUI/Internal/MdiLayout.cs @@ -0,0 +1,36 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +namespace ShiftUI { + public enum MdiLayout { + Cascade = 0, + TileHorizontal = 1, + TileVertical = 2, + ArrangeIcons = 3 + } +} diff --git a/source/ShiftUI/Internal/MdiWindowManager.cs b/source/ShiftUI/Internal/MdiWindowManager.cs new file mode 100644 index 0000000..0344f2c --- /dev/null +++ b/source/ShiftUI/Internal/MdiWindowManager.cs @@ -0,0 +1,624 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// +// + + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Runtime.InteropServices; + +namespace ShiftUI { + + internal class MdiWindowManager : InternalWindowManager { + + private MainMenu merged_menu; + private MainMenu maximized_menu; + private MenuItem icon_menu; + internal bool was_minimized; + + private PaintEventHandler draw_maximized_buttons; + internal EventHandler form_closed_handler; + + private MdiClient mdi_container; + private Rectangle prev_virtual_position; + + private Point icon_clicked; + private DateTime icon_clicked_time; + private bool icon_dont_show_popup; + + private TitleButtons maximized_title_buttons; + private bool is_visible_pending; + private byte last_activation_event; // 0 = none, 1 = activated, 2 = deactivated. + + public void RaiseActivated () + { + if (last_activation_event == 1) + return; + + last_activation_event = 1; + form.OnActivatedInternal (); + form.SelectActiveWidget (); + } + + public void RaiseDeactivate () + { + if (last_activation_event != 1) + return; + last_activation_event = 2; + form.OnDeactivateInternal (); + } + + public override int MenuHeight { + get { + // Mdi children don't get menus on the form, they're shown on the main form. + return 0; + } + } + + internal bool IsVisiblePending { + get { + return is_visible_pending; + } + set { + is_visible_pending = value; + } + } + + private TitleButtons MaximizedTitleButtons { + get { + if (maximized_title_buttons == null) { + maximized_title_buttons = new TitleButtons (this.Form); + maximized_title_buttons.CloseButton.Visible = true; + maximized_title_buttons.RestoreButton.Visible = true; + maximized_title_buttons.MinimizeButton.Visible = true; + } + return maximized_title_buttons; + } + } + + internal override Rectangle MaximizedBounds { + get { + Rectangle pb = mdi_container.ClientRectangle; + int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this); + int tw = TitleBarHeight; + + Rectangle new_bounds = new Rectangle (pb.Left - bw, + pb.Top - tw - bw, + pb.Width + bw * 2, + pb.Height + tw + bw * 2); + return new_bounds; + } + } + + + + public MdiWindowManager (Form form, MdiClient mdi_container) : base (form) + { + this.mdi_container = mdi_container; + if (form.WindowState == FormWindowState.Normal) { + NormalBounds = form.Bounds; + } + form_closed_handler = new EventHandler (FormClosed); + form.Closed += form_closed_handler; + form.TextChanged += new EventHandler (FormTextChangedHandler); + form.SizeChanged += new EventHandler (FormSizeChangedHandler); + form.LocationChanged += new EventHandler (FormLocationChangedHandler); + form.VisibleChanged += new EventHandler (FormVisibleChangedHandler); + draw_maximized_buttons = new PaintEventHandler (DrawMaximizedButtons); + CreateIconMenus (); + } + + private void FormVisibleChangedHandler (object sender, EventArgs e) + { + if (mdi_container == null) + return; + + if (form.Visible) { + mdi_container.ActivateChild (form); + } else if (mdi_container.Widgets.Count > 1) { + mdi_container.ActivateActiveMdiChild (); + } + } + + private void FormTextChangedHandler (object sender, EventArgs e) + { + mdi_container.SetParentText (false); + + if (form.MdiParent.MainMenuStrip != null) + form.MdiParent.MainMenuStrip.RefreshMdiItems (); + } + + private void FormLocationChangedHandler (object sender, EventArgs e) + { + if (form.window_state == FormWindowState.Minimized) + IconicBounds = form.Bounds; + form.MdiParent.MdiContainer.SizeScrollBars (); + } + + private void FormSizeChangedHandler (object sender, EventArgs e) + { + if (form.window_state == FormWindowState.Maximized && form.Bounds != MaximizedBounds) + form.Bounds = MaximizedBounds; + + form.MdiParent.MdiContainer.SizeScrollBars (); + } + + public MainMenu MergedMenu { + get { + if (merged_menu == null) + merged_menu = CreateMergedMenu (); + return merged_menu; + } + } + + private MainMenu CreateMergedMenu () + { + Form parent = (Form) mdi_container.Parent; + MainMenu clone; + if (parent.Menu != null) + clone = (MainMenu) parent.Menu.CloneMenu (); + else + clone = new MainMenu (); + + if (form.WindowState == FormWindowState.Maximized) { + + } + clone.MergeMenu (form.Menu); + clone.MenuChanged += new EventHandler (MenuChangedHandler); + clone.SetForm (parent); + return clone; + } + + public MainMenu MaximizedMenu { + get { + if (maximized_menu == null) + maximized_menu = CreateMaximizedMenu (); + return maximized_menu; + } + } + + private MainMenu CreateMaximizedMenu () + { + Form parent = (Form) mdi_container.Parent; + + if (form.MainMenuStrip != null || parent.MainMenuStrip != null) + return null; + + MainMenu res = new MainMenu (); + + if (parent.Menu != null) { + MainMenu clone = (MainMenu) parent.Menu.CloneMenu (); + res.MergeMenu (clone); + } + + if (form.Menu != null) { + MainMenu clone = (MainMenu) form.Menu.CloneMenu (); + res.MergeMenu (clone); + } + + if (res.MenuItems.Count == 0) + res.MenuItems.Add (new MenuItem ()); // Dummy item to get the menu height correct + + res.MenuItems.Insert (0, icon_menu); + + res.SetForm (parent); + return res; + } + + private void CreateIconMenus () + { + //TODO: remove this unneeded crap + } + + private void ClickIconMenuItem(object sender, EventArgs e) + { + if ((DateTime.Now - icon_clicked_time).TotalMilliseconds <= SystemInformation.DoubleClickTime) { + form.Close (); + return; + } + icon_clicked_time = DateTime.Now; + Point pnt = Point.Empty; + pnt = form.MdiParent.PointToScreen (pnt); + pnt = form.PointToClient (pnt); + ShowPopup (pnt); + } + + internal void ShowPopup (Point pnt) + { + // If we are using MainMenuStrip, display that menu instead + if (form.WindowState == FormWindowState.Maximized && form.MdiParent.MainMenuStrip != null) + if (form.MdiParent.MainMenuStrip.Items.Count > 0) { + ToolStripItem tsi = form.MdiParent.MainMenuStrip.Items[0]; + + if (tsi is MdiWidgetStrip.SystemMenuItem) { + (tsi as MdiWidgetStrip.SystemMenuItem).ShowDropDown (); + return; + } + } + + } + + private void RestoreItemHandler (object sender, EventArgs e) + { + form.WindowState = FormWindowState.Normal; + } + + private void MoveItemHandler (object sender, EventArgs e) + { + int x = 0; + int y = 0; + + PointToScreen (ref x, ref y); + Cursor.Position = new Point (x, y); + form.Cursor = Cursors.Cross; + state = State.Moving; + form.Capture = true; + } + + private void SizeItemHandler (object sender, EventArgs e) + { + int x = 0; + int y = 0; + + PointToScreen (ref x, ref y); + Cursor.Position = new Point (x, y); + form.Cursor = Cursors.Cross; + state = State.Sizing; + form.Capture = true; + } + + private void MinimizeItemHandler (object sender, EventArgs e) + { + form.WindowState = FormWindowState.Minimized; + } + + private void MaximizeItemHandler (object sender, EventArgs e) + { + if (form.WindowState != FormWindowState.Maximized) + form.WindowState = FormWindowState.Maximized; + } + + private void CloseItemHandler (object sender, EventArgs e) + { + form.Close (); + } + + private void NextItemHandler (object sender, EventArgs e) + { + mdi_container.ActivateNextChild (); + } + + private void DrawIconMenuItem (object sender, DrawItemEventArgs de) + { + de.Graphics.DrawIcon (form.Icon, new Rectangle (de.Bounds.X + 2, de.Bounds.Y + 2, + de.Bounds.Height - 4, de.Bounds.Height - 4)); + } + + private void MeasureIconMenuItem (object sender, MeasureItemEventArgs me) + { + int size = SystemInformation.MenuHeight; + me.ItemHeight = size; + me.ItemWidth = size + 2; // some padding + } + + private void MenuChangedHandler (object sender, EventArgs e) + { + CreateMergedMenu (); + } + + public override void PointToClient (ref int x, ref int y) + { + XplatUI.ScreenToClient (mdi_container.Handle, ref x, ref y); + } + + public override void PointToScreen (ref int x, ref int y) + { + XplatUI.ClientToScreen (mdi_container.Handle, ref x, ref y); + } + + public override void UpdateWindowDecorations (FormWindowState window_state) + { + if (MaximizedMenu != null) { + switch (window_state) { + case FormWindowState.Minimized: + case FormWindowState.Normal: + MaximizedMenu.Paint -= draw_maximized_buttons; + MaximizedTitleButtons.Visible = false; + TitleButtons.Visible = true; + break; + case FormWindowState.Maximized: + MaximizedMenu.Paint += draw_maximized_buttons; + MaximizedTitleButtons.Visible = true; + TitleButtons.Visible = false; + break; + } + } + + base.UpdateWindowDecorations (window_state); + } + + public override void SetWindowState (FormWindowState old_state, FormWindowState window_state) + { + mdi_container.SetWindowState (form, old_state, window_state, false); + } + + private void FormClosed (object sender, EventArgs e) + { + mdi_container.ChildFormClosed (form); + + if (form.MdiParent.MainMenuStrip != null) + form.MdiParent.MainMenuStrip.RefreshMdiItems (); + + mdi_container.RemoveControlMenuItems (this); + } + + public override void DrawMaximizedButtons (object sender, PaintEventArgs pe) + { + Size bs = ThemeEngine.Current.ManagedWindowGetMenuButtonSize (this); + Point pnt = XplatUI.GetMenuOrigin (mdi_container.ParentForm.Handle); + int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this); + TitleButtons buttons = MaximizedTitleButtons; + + buttons.Visible = true; + TitleButtons.Visible = false; + + buttons.CloseButton.Rectangle = new Rectangle (mdi_container.ParentForm.Size.Width - 1 - bw - bs.Width - 2, + pnt.Y + 2, bs.Width, bs.Height); + + buttons.RestoreButton.Rectangle = new Rectangle (buttons.CloseButton.Rectangle.Left - 2 - bs.Width, + pnt.Y + 2, bs.Width, bs.Height); + + buttons.MinimizeButton.Rectangle = new Rectangle (buttons.RestoreButton.Rectangle.Left - bs.Width, + pnt.Y + 2, bs.Width, bs.Height); + + DrawTitleButton (pe.Graphics, buttons.MinimizeButton, pe.ClipRectangle); + DrawTitleButton (pe.Graphics, buttons.RestoreButton, pe.ClipRectangle); + DrawTitleButton (pe.Graphics, buttons.CloseButton, pe.ClipRectangle); + + buttons.MinimizeButton.Rectangle.Y -= pnt.Y; + buttons.RestoreButton.Rectangle.Y -= pnt.Y; + buttons.CloseButton.Rectangle.Y -= pnt.Y; + } + + public bool HandleMenuMouseDown (MainMenu menu, int x, int y) + { + Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y)); + + HandleTitleBarDown (pt.X, pt.Y); + return TitleButtons.AnyPushedTitleButtons; + } + + public void HandleMenuMouseUp (MainMenu menu, int x, int y) + { + Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y)); + + HandleTitleBarUp (pt.X, pt.Y); + } + + public void HandleMenuMouseLeave (MainMenu menu, int x, int y) + { + Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y)); + HandleTitleBarLeave (pt.X, pt.Y); + + } + + public void HandleMenuMouseMove (MainMenu menu, int x, int y) + { + Point pt = MenuTracker.ScreenToMenu (menu, new Point (x, y)); + + HandleTitleBarMouseMove (pt.X, pt.Y); + + } + + protected override void HandleTitleBarLeave (int x, int y) + { + base.HandleTitleBarLeave (x, y); + + if (maximized_title_buttons != null) { + maximized_title_buttons.MouseLeave (x, y); + } + + if (IsMaximized) + XplatUI.InvalidateNC (form.MdiParent.Handle); + } + + protected override void HandleTitleBarUp (int x, int y) + { + if (IconRectangleContains (x, y)) { + if (!icon_dont_show_popup) { + if (IsMaximized) + ClickIconMenuItem (null, null); + else + ShowPopup (Point.Empty); + } else { + icon_dont_show_popup = false; + } + return; + } + + bool was_maximized = IsMaximized; + base.HandleTitleBarUp (x, y); + if (maximized_title_buttons != null && was_maximized) { + maximized_title_buttons.MouseUp (x, y); + } + + if (IsMaximized) + XplatUI.InvalidateNC (mdi_container.Parent.Handle); + } + + protected override void HandleTitleBarDoubleClick (int x, int y) + { + if (IconRectangleContains (x, y)) { + form.Close (); + } else if (form.MaximizeBox == true) { + form.WindowState = FormWindowState.Maximized; + } + base.HandleTitleBarDoubleClick (x, y); + } + + protected override void HandleTitleBarDown (int x, int y) + { + if (IconRectangleContains (x, y)) { + if ((DateTime.Now - icon_clicked_time).TotalMilliseconds <= SystemInformation.DoubleClickTime && icon_clicked.X == x && icon_clicked.Y == y) { + form.Close (); + } else { + icon_clicked_time = DateTime.Now; + icon_clicked.X = x; + icon_clicked.Y = y; + } + + return; + } + + base.HandleTitleBarDown (x, y); + + if (maximized_title_buttons != null) { + maximized_title_buttons.MouseDown (x, y); + } + + if (IsMaximized) { + XplatUI.InvalidateNC (mdi_container.Parent.Handle); + } + } + + protected override void HandleTitleBarMouseMove (int x, int y) + { + base.HandleTitleBarMouseMove (x, y); + + if (maximized_title_buttons != null && maximized_title_buttons.MouseMove (x, y)) + XplatUI.InvalidateNC (form.MdiParent.Handle); + } + + protected override bool HandleLButtonDblClick (ref Message m) + { + + int x = Widget.LowOrder ((int)m.LParam.ToInt32 ()); + int y = Widget.HighOrder ((int)m.LParam.ToInt32 ()); + + // Correct since we are in NC land. + NCClientToNC (ref x, ref y); + + if (IconRectangleContains (x, y)) { + form.Close (); + return true; + } + + return base.HandleLButtonDblClick (ref m); + } + + protected override bool HandleLButtonDown (ref Message m) + { + + int x = Widget.LowOrder ((int)m.LParam.ToInt32 ()); + int y = Widget.HighOrder ((int)m.LParam.ToInt32 ()); + + // Correct y since we are in NC land. + NCClientToNC(ref x, ref y); + + if (IconRectangleContains (x, y)){ + if ((DateTime.Now - icon_clicked_time).TotalMilliseconds <= SystemInformation.DoubleClickTime) { + form.Close (); + return true; + } else if (form.Capture) { + icon_dont_show_popup = true; + } + } + return base.HandleLButtonDown (ref m); + } + + protected override bool ShouldRemoveWindowManager (FormBorderStyle style) + { + return false; + } + + protected override void HandleWindowMove (Message m) + { + Point pos = Cursor.Position; + Point move = MouseMove (pos); + + if (move.X == 0 && move.Y == 0) + return; + + int x = virtual_position.X + move.X; + int y = virtual_position.Y + move.Y; + + Rectangle client = mdi_container.ClientRectangle; + if (mdi_container.VerticalScrollbarVisible) + client.Width -= SystemInformation.VerticalScrollBarWidth; + if (mdi_container.HorizontalScrollbarVisible) + client.Height -= SystemInformation.HorizontalScrollBarHeight; + + UpdateVP (x, y, form.Width, form.Height); + + start = pos; + } + + protected override bool HandleNCMouseMove (ref Message m) + { + XplatUI.RequestAdditionalWM_NCMessages (form.Handle, true, true); + return base.HandleNCMouseMove (ref m); + } + + protected override void DrawVirtualPosition (Rectangle virtual_position) + { + ClearVirtualPosition (); + + if (form.Parent != null) + XplatUI.DrawReversibleRectangle (form.Parent.Handle, virtual_position, 2); + prev_virtual_position = virtual_position; + } + + protected override void ClearVirtualPosition () + { + if (prev_virtual_position != Rectangle.Empty && form.Parent != null) + XplatUI.DrawReversibleRectangle (form.Parent.Handle, + prev_virtual_position, 2); + prev_virtual_position = Rectangle.Empty; + } + + protected override void OnWindowFinishedMoving () + { + form.Refresh (); + } + + public override bool IsActive { + get { + if (mdi_container == null) + return false; + return mdi_container.ActiveMdiChild == form; + } + } + + protected override void Activate () + { + if (mdi_container.ActiveMdiChild != form) { + mdi_container.ActivateChild (form); + } + base.Activate (); + } + } +} + diff --git a/source/ShiftUI/Internal/Message.cs b/source/ShiftUI/Internal/Message.cs new file mode 100644 index 0000000..90881c3 --- /dev/null +++ b/source/ShiftUI/Internal/Message.cs @@ -0,0 +1,118 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com + + +// COMPLETE + +using System; +using System.Runtime.InteropServices; +using System.Text; +using System.Diagnostics; + +namespace ShiftUI { + public struct Message { + private int msg; + private IntPtr hwnd; + private IntPtr lParam; + private IntPtr wParam; + private IntPtr result; + + #region Public Instance Properties + public IntPtr HWnd { + get { return hwnd; } + set { hwnd=value; } + } + + public IntPtr LParam { + get { return lParam; } + set { lParam=value; } + } + + public int Msg { + get { return msg; } + set { msg=value; } + } + + public IntPtr Result { + get { return result; } + set { result=value; } + } + + public IntPtr WParam { + get { return wParam; } + set { wParam=value; } + } + #endregion // Public Instance Properties + + #region Public Static Methods + public static Message Create(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam) { + Message new_message = new Message(); + + new_message.msg=msg; + new_message.hwnd=hWnd; + new_message.wParam=wparam; + new_message.lParam=lparam; + return new_message; + } + + public static bool operator == (Message a, Message b) + { + return (a.hwnd == b.hwnd) && (a.lParam == b.lParam) && (a.msg == b.msg) && (a.result == b.result) && (a.wParam == b.wParam); + } + + public static bool operator != (Message a, Message b) + { + return !(a == b); + } + #endregion // Public Static Methods + + #region Public Instance Methods + public override bool Equals(object o) { + if (!(o is Message)) { + return false; + } + + return ((this.msg == ((Message)o).msg) && + (this.hwnd == ((Message)o).hwnd) && + (this.lParam == ((Message)o).lParam) && + (this.wParam == ((Message)o).wParam) && + (this.result == ((Message)o).result)); + } + + public override int GetHashCode() { + return base.GetHashCode(); + } + + public object GetLParam(Type cls) { + object o = Marshal.PtrToStructure(this.lParam, cls); + + return(o); + } + + public override string ToString() { + return String.Format ("msg=0x{0:x} ({1}) hwnd=0x{2:x} wparam=0x{3:x} lparam=0x{4:x} result=0x{5:x}", msg, ((Msg) msg).ToString (), hwnd.ToInt32 (), wParam.ToInt32 (), lParam.ToInt32 (), result.ToInt32 ()); + } + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Internal/MethodInvoker.cs b/source/ShiftUI/Internal/MethodInvoker.cs new file mode 100644 index 0000000..e0275f8 --- /dev/null +++ b/source/ShiftUI/Internal/MethodInvoker.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +namespace ShiftUI { + public delegate void MethodInvoker(); +} diff --git a/source/ShiftUI/Internal/MouseHandler.cs b/source/ShiftUI/Internal/MouseHandler.cs new file mode 100644 index 0000000..9eb86be --- /dev/null +++ b/source/ShiftUI/Internal/MouseHandler.cs @@ -0,0 +1,228 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Geoff Norton +// +// + +using System; +using System.Runtime.InteropServices; + +namespace ShiftUI.CarbonInternal { + internal class MouseHandler : EventHandlerBase, IEventHandler { + internal const uint kEventMouseDown = 1; + internal const uint kEventMouseUp = 2; + internal const uint kEventMouseMoved = 5; + internal const uint kEventMouseDragged = 6; + internal const uint kEventMouseEntered = 8; + internal const uint kEventMouseExited = 9; + internal const uint kEventMouseWheelMoved = 10; + internal const uint kEventMouseScroll = 11; + + internal const uint kEventParamMouseLocation = 1835822947; + internal const uint kEventParamMouseButton = 1835168878; + internal const uint kEventParamMouseWheelAxis = 1836540280; + internal const uint kEventParamMouseWheelDelta = 1836541036; + internal const uint typeLongInteger = 1819242087; + internal const uint typeMouseWheelAxis = 1836540280; + internal const uint typeMouseButton = 1835168878; + internal const uint typeQDPoint = 1363439732; + + internal const uint kEventMouseWheelAxisX = 0; + internal const uint kEventMouseWheelAxisY = 1; + + internal const uint DoubleClickInterval = 7500000; + internal static ClickStruct ClickPending; + + internal MouseHandler (XplatUICarbon driver) : base (driver) {} + + public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) { + QDPoint qdpoint = new QDPoint (); + CGPoint point = new CGPoint (); + Rect window_bounds = new Rect (); + IntPtr view_handle = IntPtr.Zero; + IntPtr window_handle = IntPtr.Zero; + bool client = true; + ushort button = 0; + Hwnd hwnd; + + GetEventParameter (eventref, kEventParamMouseLocation, typeQDPoint, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (QDPoint)), IntPtr.Zero, ref qdpoint); + GetEventParameter (eventref, kEventParamMouseButton, typeMouseButton, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (ushort)), IntPtr.Zero, ref button); + + if (button == 1 && ((Driver.ModifierKeys & Keys.Widget) != 0)) + button = 2; + + point.x = qdpoint.x; + point.y = qdpoint.y; + + if (FindWindow (qdpoint, ref window_handle) == 5) + return true; + + GetWindowBounds (handle, 33, ref window_bounds); + HIViewFindByID (HIViewGetRoot (handle), new HIViewID (EventHandler.kEventClassWindow, 1), ref window_handle); + + point.x -= window_bounds.left; + point.y -= window_bounds.top; + + HIViewGetSubviewHit (window_handle, ref point, true, ref view_handle); + HIViewConvertPoint (ref point, window_handle, view_handle); + + hwnd = Hwnd.ObjectFromHandle (view_handle); + + if (hwnd != null) + client = (hwnd.ClientWindow == view_handle ? true : false); + + if (XplatUICarbon.Grab.Hwnd != IntPtr.Zero) { + hwnd = Hwnd.ObjectFromHandle (XplatUICarbon.Grab.Hwnd); + client = true; + } + if (hwnd == null) + return true; + + if (client) { + qdpoint.x = (short) point.x; + qdpoint.y = (short) point.y; + + Driver.ScreenToClient (hwnd.Handle, ref qdpoint); + } else { + point.x = qdpoint.x; + point.y = qdpoint.y; + } + + msg.hwnd = hwnd.Handle; + msg.lParam = (IntPtr) ((ushort) point.y << 16 | (ushort) point.x); + + switch (kind) { + case kEventMouseDown: + UpdateMouseState (button, true); + msg.message = (client ? Msg.WM_MOUSEMOVE : Msg.WM_NCMOUSEMOVE) + ((button - 1) * 3) + 1; + msg.wParam = Driver.GetMousewParam (0); + if (ClickPending.Pending && (((DateTime.Now.Ticks - ClickPending.Time) < DoubleClickInterval) && (msg.hwnd == ClickPending.Hwnd) && (msg.wParam == ClickPending.wParam) && (msg.lParam == ClickPending.lParam) && (msg.message == ClickPending.Message))) { + msg.message = (client ? Msg.WM_MOUSEMOVE : Msg.WM_NCMOUSEMOVE) + ((button - 1) * 3) + 3; + ClickPending.Pending = false; + } else { + ClickPending.Pending = true; + ClickPending.Hwnd = msg.hwnd; + ClickPending.Message = msg.message; + ClickPending.wParam = msg.wParam; + ClickPending.lParam = msg.lParam; + ClickPending.Time = DateTime.Now.Ticks; + } + break; + case kEventMouseUp: + UpdateMouseState (button, false); + msg.message = (client ? Msg.WM_MOUSEMOVE : Msg.WM_NCMOUSEMOVE) + ((button - 1) * 3) + 2; + msg.wParam = Driver.GetMousewParam (0); + break; + case kEventMouseDragged: + case kEventMouseMoved: + if (XplatUICarbon.Grab.Hwnd == IntPtr.Zero) { + IntPtr ht = IntPtr.Zero; + if (client) { + ht = (IntPtr) HitTest.HTCLIENT; + NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT); + } else { + ht = (IntPtr) NativeWindow.WndProc (hwnd.client_window, Msg.WM_NCHITTEST, IntPtr.Zero, msg.lParam).ToInt32 (); + NativeWindow.WndProc(hwnd.client_window, Msg.WM_SETCURSOR, msg.hwnd, ht); + } + } + msg.message = (client ? Msg.WM_MOUSEMOVE : Msg.WM_NCMOUSEMOVE); + msg.wParam = Driver.GetMousewParam (0); + break; + case kEventMouseWheelMoved: + case kEventMouseScroll: + UInt16 axis = 0; + Int32 delta = 0; + + GetEventParameter (eventref, kEventParamMouseWheelAxis, typeMouseWheelAxis, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (UInt16)), IntPtr.Zero, ref axis); + GetEventParameter (eventref, kEventParamMouseWheelDelta, typeLongInteger, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (Int32)), IntPtr.Zero, ref delta); + + if (axis == kEventMouseWheelAxisY) { + msg.hwnd = XplatUICarbon.FocusWindow; + msg.message = Msg.WM_MOUSEWHEEL; + msg.wParam = Driver.GetMousewParam (delta*40); + return true; + } + break; + default: + return false; + } + Driver.mouse_position.X = (int) point.x; + Driver.mouse_position.Y = (int) point.y; + return true; + } + + internal bool TranslateMessage (ref MSG msg) { + if (msg.message == Msg.WM_MOUSEMOVE || msg.message == Msg.WM_NCMOUSEMOVE) { + Hwnd hwnd = Hwnd.ObjectFromHandle (msg.hwnd); + if (XplatUICarbon.MouseHwnd == null) { + Driver.PostMessage (hwnd.Handle, Msg.WM_MOUSE_ENTER, IntPtr.Zero, IntPtr.Zero); + Cursor.SetCursor (hwnd.Cursor); + } else if (XplatUICarbon.MouseHwnd.Handle != hwnd.Handle) { + Driver.PostMessage (XplatUICarbon.MouseHwnd.Handle, Msg.WM_MOUSELEAVE, IntPtr.Zero, IntPtr.Zero); + Driver.PostMessage (hwnd.Handle, Msg.WM_MOUSE_ENTER, IntPtr.Zero, IntPtr.Zero); + Cursor.SetCursor (hwnd.Cursor); + } + XplatUICarbon.MouseHwnd = hwnd; + } + + return false; + } + + private void UpdateMouseState (int button, bool down) { + switch (button) { + case 1: + if (down) XplatUICarbon.MouseState |= MouseButtons.Left; else XplatUICarbon.MouseState &= ~MouseButtons.Left; + break; + case 2: + if (down) XplatUICarbon.MouseState |= MouseButtons.Right; else XplatUICarbon.MouseState &= ~MouseButtons.Right; + break; + case 3: + if (down) XplatUICarbon.MouseState |= MouseButtons.Middle; else XplatUICarbon.MouseState &= ~MouseButtons.Middle; + break; + } + } + + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref QDPoint data); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref Int32 data); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref ushort data); + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal static extern short FindWindow (QDPoint point, ref IntPtr handle); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal static extern int GetWindowBounds (IntPtr handle, uint region, ref Rect bounds); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal static extern int HIViewConvertPoint (ref CGPoint point, IntPtr source_view, IntPtr target_view); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal static extern IntPtr HIViewGetRoot (IntPtr handle); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal static extern int HIViewGetSubviewHit (IntPtr content_view, ref CGPoint point, bool tval, ref IntPtr hit_view); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal static extern int HIViewFindByID (IntPtr root_window, HIViewID id, ref IntPtr view_handle); + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal static extern int GetCurrentEventButtonState (); + } +} diff --git a/source/ShiftUI/Internal/NativeWindow.cs b/source/ShiftUI/Internal/NativeWindow.cs new file mode 100644 index 0000000..4657276 --- /dev/null +++ b/source/ShiftUI/Internal/NativeWindow.cs @@ -0,0 +1,324 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2008 Novell, Inc. +// +// Authors: +// Peter Dennis Bartok pbartok@novell.com +// Ivan N. Zlatev +// + + +// COMPLETE + +#define ExternalExceptionHandler + +using System.Runtime.Remoting; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Collections; +using System.Diagnostics; +using System.Drawing; +using System; + +namespace ShiftUI +{ + public class NativeWindow : MarshalByRefObject, IWin32Window + { + IntPtr window_handle = IntPtr.Zero; + static Hashtable window_collection = new Hashtable(); + + [ThreadStatic] + static NativeWindow WindowCreating; + + #region Public Constructors + public NativeWindow() + { + window_handle=IntPtr.Zero; + } + #endregion // Public Constructors + + #region Public Instance Properties + public IntPtr Handle { + get { + return window_handle; + } + } + #endregion // Public Instance Properties + + #region Public Static Methods + public static NativeWindow FromHandle(IntPtr handle) + { + return FindFirstInTable (handle); + } + #endregion // Public Static Methods + + #region Private and Internal Methods + internal void InvalidateHandle() + { + RemoveFromTable (this); + window_handle = IntPtr.Zero; + } + #endregion + + #region Public Instance Methods + public void AssignHandle(IntPtr handle) + { + RemoveFromTable (this); + window_handle = handle; + AddToTable (this); + OnHandleChange(); + } + + private static void AddToTable (NativeWindow window) + { + IntPtr handle = window.Handle; + if (handle == IntPtr.Zero) + return; + + lock (window_collection) { + object current = window_collection[handle]; + if (current == null) { + window_collection.Add (handle, window); + } else { + NativeWindow currentWindow = current as NativeWindow; + if (currentWindow != null) { + if (currentWindow != window) { + ArrayList windows = new ArrayList (); + windows.Add (currentWindow); + windows.Add (window); + window_collection[handle] = windows; + } + } else { // list of windows + ArrayList windows = (ArrayList) window_collection[handle]; + if (!windows.Contains (window)) + windows.Add (window); + } + } + } + } + + private static void RemoveFromTable (NativeWindow window) + { + IntPtr handle = window.Handle; + if (handle == IntPtr.Zero) + return; + + lock (window_collection) { + object current = window_collection[handle]; + if (current != null) { + NativeWindow currentWindow = current as NativeWindow; + if (currentWindow != null) { + window_collection.Remove (handle); + } else { // list of windows + ArrayList windows = (ArrayList) window_collection[handle]; + windows.Remove (window); + if (windows.Count == 0) + window_collection.Remove (handle); + else if (windows.Count == 1) + window_collection[handle] = windows[0]; + } + } + } + } + + private static NativeWindow FindFirstInTable (IntPtr handle) + { + if (handle == IntPtr.Zero) + return null; + + NativeWindow window = null; + lock (window_collection) { + object current = window_collection[handle]; + if (current != null) { + window = current as NativeWindow; + if (window == null) { + ArrayList windows = (ArrayList) current; + if (windows.Count > 0) + window = (NativeWindow) windows[0]; + } + } + } + return window; + } + + public virtual void CreateHandle(CreateParams cp) + { + if (cp != null) { + WindowCreating = this; + window_handle=XplatUI.CreateWindow(cp); + WindowCreating = null; + + if (window_handle != IntPtr.Zero) + AddToTable (this); + } + + } + + public void DefWndProc(ref Message m) + { + m.Result=XplatUI.DefWndProc(ref m); + } + + public virtual void DestroyHandle() + { + if (window_handle != IntPtr.Zero) { + XplatUI.DestroyWindow(window_handle); + } + } + + public virtual void ReleaseHandle() + { + RemoveFromTable (this); + window_handle=IntPtr.Zero; + OnHandleChange(); + } + + #endregion // Public Instance Methods + + #region Protected Instance Methods + ~NativeWindow() + { + } + + protected virtual void OnHandleChange() + { + } + + protected virtual void OnThreadException(Exception e) + { + Application.OnThreadException(e); + } + + protected virtual void WndProc(ref Message m) + { + DefWndProc(ref m); + } + + internal static IntPtr WndProc(IntPtr hWnd, Msg msg, IntPtr wParam, IntPtr lParam) + { + IntPtr result = IntPtr.Zero; + Message m = new Message(); + m.HWnd = hWnd; + m.Msg = (int)msg; + m.WParam = wParam; + m.LParam = lParam; + m.Result = IntPtr.Zero; + +#if debug + Console.WriteLine("NativeWindow.cs ({0}, {1}, {2}, {3}): result {4}", hWnd, msg, wParam, lParam, m.Result); +#endif + NativeWindow window = null; + + try { + object current = null; + lock (window_collection) { + current = window_collection[hWnd]; + } + + window = current as NativeWindow; + if (current == null) + window = EnsureCreated (window, hWnd); + + if (window != null) { + window.WndProc (ref m); + result = m.Result; + } else if (current is ArrayList) { + ArrayList windows = (ArrayList) current; + lock (windows) { + if (windows.Count > 0) { + window = EnsureCreated ((NativeWindow)windows[0], hWnd); + window.WndProc (ref m); + // the first one is the Widget's one. all others are synthetic, + // so we want only the result from the Widget + result = m.Result; + for (int i=1; i < windows.Count; i++) + ((NativeWindow)windows[i]).WndProc (ref m); + } + } + } else { + result = XplatUI.DefWndProc (ref m); + } + } + catch (Exception ex) { +#if !ExternalExceptionHandler + if (window != null) { + if (msg == Msg.WM_PAINT && window is Widget.WidgetNativeWindow) { + // Replace Widget with a red cross + var Widget = ((Widget.WidgetNativeWindow)window).Owner; + Widget.Hide (); + var redCross = new Widget (Widget.Parent, string.Empty); + redCross.BackColor = Color.White; + redCross.ForeColor = Color.Red; + redCross.Bounds = Widget.Bounds; + redCross.Paint += HandleRedCrossPaint; + } + window.OnThreadException (ex); + } +#else + throw ex; +#endif + } + #if debug + Console.WriteLine("NativeWindow.cs: Message {0}, result {1}", msg, m.Result); + #endif + + return result; + } + + private static void HandleRedCrossPaint (object sender, PaintEventArgs e) + { + var Widget = sender as Widget; + using (var pen = new Pen (Widget.ForeColor, 2)) { + var paintRect = Widget.DisplayRectangle; + e.Graphics.DrawRectangle (pen, paintRect.Left + 1, + paintRect.Top + 1, paintRect.Width - 1, paintRect.Height - 1); + // NOTE: .NET's drawing of the red cross seems to have a bug + // that draws the bottom and right of the rectangle only 1 pixel + // wide. We would get a nicer rectangle using the following code, + // but that runs into a problem with libgdiplus. + //var paintRect = Widget.DisplayRectangle; + //paintRect.Inflate (-1, -1); + //e.Graphics.DrawRectangle (pen, paintRect); + e.Graphics.DrawLine (pen, paintRect.Location, + paintRect.Location + paintRect.Size); + e.Graphics.DrawLine (pen, new Point (paintRect.Left, paintRect.Bottom), + new Point (paintRect.Right, paintRect.Top)); + } + } + + private static NativeWindow EnsureCreated (NativeWindow window, IntPtr hWnd) + { + // we need to do this AssignHandle here instead of relying on + // Widget.WndProc to do it, because subclasses can override + // WndProc, install their own WM_CREATE block, and look at + // this.Handle, and it needs to be set. Otherwise, we end up + // recursively creating windows and emitting WM_CREATE. + if (window == null && WindowCreating != null) { + window = WindowCreating; + WindowCreating = null; + if (window.Handle == IntPtr.Zero) + window.AssignHandle (hWnd); + } + return window; + } + #endregion // Protected Instance Methods + } +} diff --git a/source/ShiftUI/Internal/OpacityConverter.cs b/source/ShiftUI/Internal/OpacityConverter.cs new file mode 100644 index 0000000..89fcc63 --- /dev/null +++ b/source/ShiftUI/Internal/OpacityConverter.cs @@ -0,0 +1,74 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +using System; +using System.Collections; +using System.ComponentModel; +using System.Globalization; +using System.Text; + +namespace ShiftUI { + public class OpacityConverter : TypeConverter { + #region Public Constructors + public OpacityConverter() { + } + #endregion // Public Constructors + + #region Public Instance Methods + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { + if (sourceType == typeof(string)) { + return true; + } + return false; + } + + public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) { + if (value is string) { + string s; + + s = (string)value; + if (s.EndsWith("%")) { + s = ((string)value).Substring(0, ((string)value).Length - 1); + } + return Double.Parse(s, NumberStyles.Any, culture) / 100; + } + return base.ConvertFrom (context, culture, value); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) { + if (destinationType == typeof(string)) { + double v; + + v = ((double)value) * 100; + return v.ToString() + "%"; + } + return base.ConvertTo (context, culture, value, destinationType); + } + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Internal/OpenTreeNodeEnumerator.cs b/source/ShiftUI/Internal/OpenTreeNodeEnumerator.cs new file mode 100644 index 0000000..f2d9453 --- /dev/null +++ b/source/ShiftUI/Internal/OpenTreeNodeEnumerator.cs @@ -0,0 +1,112 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +using System; +using System.Collections; + +namespace ShiftUI { + + internal class OpenTreeNodeEnumerator : IEnumerator { + + private TreeNode start; + private TreeNode current; + private bool started; + + public OpenTreeNodeEnumerator (TreeNode start) + { + this.start = start; + } + + public object Current { + get { return current; } + } + + public TreeNode CurrentNode { + get { return current; } + } + + public bool MoveNext () + { + if (!started) { + started = true; + current = start; + return (current != null); + } + + if (current.is_expanded && current.Nodes.Count > 0) { + current = current.Nodes [0]; + return true; + } + + TreeNode prev = current; + TreeNode next = current.NextNode; + while (next == null) { + // The next node is null so we need to move back up the tree until we hit the top + if (prev.parent == null) + return false; + prev = prev.parent; + if (prev.parent != null) + next = prev.NextNode; + } + current = next; + return true; + } + + public bool MovePrevious () + { + if (!started) { + started = true; + current = start; + return (current != null); + } + + if (current.PrevNode != null) { + // Drill down as far as possible + TreeNode prev = current.PrevNode; + TreeNode walk = prev; + while (walk != null) { + prev = walk; + if (!walk.is_expanded) + break; + walk = walk.LastNode; + } + current = prev; + return true; + } + + if (current.Parent == null) + return false; + + current = current.Parent; + return true; + } + + public void Reset () + { + started = false; + } + } +} + diff --git a/source/ShiftUI/Internal/OwnerDrawPropertyBag.cs b/source/ShiftUI/Internal/OwnerDrawPropertyBag.cs new file mode 100644 index 0000000..c9f8e6f --- /dev/null +++ b/source/ShiftUI/Internal/OwnerDrawPropertyBag.cs @@ -0,0 +1,101 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + +using System; +using System.Drawing; +using System.Runtime.Serialization; + +namespace ShiftUI { + + [Serializable] + public class OwnerDrawPropertyBag : MarshalByRefObject, ISerializable { + + private Color fore_color; + private Color back_color; + private Font font; + + internal OwnerDrawPropertyBag () + { + fore_color = back_color = Color.Empty; + } + + private OwnerDrawPropertyBag (Color fore_color, Color back_color, Font font) + { + this.fore_color = fore_color; + this.back_color = back_color; + this.font = font; + } + + protected OwnerDrawPropertyBag(SerializationInfo info, StreamingContext context) { + SerializationInfoEnumerator en; + SerializationEntry e; + + en = info.GetEnumerator(); + + while (en.MoveNext()) { + e = en.Current; + switch(e.Name) { + case "Font": font = (Font)e.Value; break; + case "ForeColor": fore_color = (Color)e.Value; break; + case "BackColor": back_color = (Color)e.Value; break; + } + } + } + + + public Color ForeColor { + get { return fore_color; } + set { fore_color = value; } + } + + public Color BackColor { + get { return back_color; } + set { back_color = value; } + } + + public Font Font { + get { return font; } + set { font = value; } + } + + public virtual bool IsEmpty () + { + return (font == null && fore_color.IsEmpty && back_color.IsEmpty); + } + + void ISerializable.GetObjectData (SerializationInfo si, StreamingContext context) + { + si.AddValue ("BackColor", BackColor); + si.AddValue ("ForeColor", ForeColor); + si.AddValue ("Font", Font); + } + + public static OwnerDrawPropertyBag Copy (OwnerDrawPropertyBag value) + { + return new OwnerDrawPropertyBag (value.ForeColor, value.BackColor, value.Font); + } + } +} + + diff --git a/source/ShiftUI/Internal/Padding.cs b/source/ShiftUI/Internal/Padding.cs new file mode 100644 index 0000000..63bdc64 --- /dev/null +++ b/source/ShiftUI/Internal/Padding.cs @@ -0,0 +1,170 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005,2006 Novell, Inc. (http://www.novell.com) +// +// Author: +// Pedro Martínez Juliá +// Daniel Nauck (dna(at)mono-project(dot)de) +// + +using System; +using System.ComponentModel; +using System.Drawing; + +namespace ShiftUI { + + [Serializable] + [TypeConverter(typeof(PaddingConverter))] + public struct Padding { + + //NOTE: "_var" field name is required by serialization. + private int _bottom; + private int _left; + private int _right; + private int _top; + private bool _all; + + public Padding (int all) { + _left = all; + _right = all; + _top = all; + _bottom = all; + _all = true; + } + + public Padding (int left, int top, int right, int bottom) { + _left = left; + _right = right; + _top = top; + _bottom = bottom; + _all = (_left == _top) && (_left == _right) && (_left == _bottom); + } + + public static readonly Padding Empty = new Padding(0); + + [RefreshProperties(RefreshProperties.All)] + public int All { + get { + if(!_all) + return -1; + else + return _top; + } + set { + _all = true; + _left = _top = _right = _bottom = value; + } + } + + [RefreshProperties(RefreshProperties.All)] + public int Bottom { + get { return _bottom; } + set { + _bottom = value; + _all = false; + } + } + + [Browsable(false)] + public int Horizontal { + get { return _left + _right; } + } + + [RefreshProperties(RefreshProperties.All)] + public int Left { + get { return _left; } + set { + _left = value; + _all = false; + } + } + + [RefreshProperties(RefreshProperties.All)] + public int Right { + get { return _right; } + set { + _right = value; + _all = false; + } + } + + [Browsable(false)] + public Size Size { + get { return new Size(Horizontal, Vertical); } + } + + [RefreshProperties(RefreshProperties.All)] + public int Top { + get { return _top; } + set { + _top = value; + _all = false; + } + } + + [Browsable(false)] + public int Vertical { + get { return _top + _bottom; } + } + + public static Padding Add (Padding p1, Padding p2) { + return p1 + p2; + } + + public override bool Equals (object other) { + if (other is Padding) { + Padding other_aux = (Padding) other; + return _left == other_aux.Left && + _top == other_aux.Top && + _right == other_aux.Right && + _bottom == other_aux.Bottom; + } + return false; + } + + public override int GetHashCode () { + return _top ^ _bottom ^ _left ^ _right; + } + + public static Padding operator+ (Padding p1, Padding p2) { + return new Padding(p1.Left + p2.Left, p1.Top + p2.Top, p1.Right + p2.Right, p1.Bottom + p2.Bottom); + } + + public static bool operator== (Padding p1, Padding p2) { + return p1.Equals(p2); + } + + public static bool operator!= (Padding p1, Padding p2) { + return !(p1.Equals(p2)); + } + + public static Padding operator- (Padding p1, Padding p2) { + return new Padding(p1.Left - p2.Left, p1.Top - p2.Top, p1.Right - p2.Right, p1.Bottom - p2.Bottom); + } + + public static Padding Subtract (Padding p1, Padding p2) { + return p1 - p2; + } + + public override string ToString () { + return "{Left=" + Left + ",Top="+ Top + ",Right=" + Right + ",Bottom=" + Bottom + "}"; + } + } +} \ No newline at end of file diff --git a/source/ShiftUI/Internal/PaddingConverter.cs b/source/ShiftUI/Internal/PaddingConverter.cs new file mode 100644 index 0000000..447f65d --- /dev/null +++ b/source/ShiftUI/Internal/PaddingConverter.cs @@ -0,0 +1,125 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// + +using System.ComponentModel; +using System.Collections; +using System.Reflection; +using System.Globalization; +using System.ComponentModel.Design.Serialization; // e.g. InstanceDescriptor +using System; + +namespace ShiftUI +{ + public class PaddingConverter : TypeConverter + { + public PaddingConverter () + { + } + + #region Public Instance Methods + public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof (string)) + return true; + + return false; + } + + public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof (string)) + return true; + else if (destinationType == typeof(InstanceDescriptor)) + return true; + + return false; + } + + public override object ConvertFrom (ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + { + if ((value == null) || !(value is String)) + return base.ConvertFrom (context, culture, value); + + if (culture == null) + culture = CultureInfo.CurrentCulture; + + string[] parts = ((string)value).Split (culture.TextInfo.ListSeparator.ToCharArray ()); + + return new Padding (int.Parse (parts[0].Trim ()), int.Parse (parts[1].Trim ()), int.Parse (parts[2].Trim ()), int.Parse (parts[3].Trim ())); + } + + public override object ConvertTo (ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (value is Padding) { + Padding p = (Padding)value; + if (destinationType == typeof (string)) { + if (culture == null) + culture = CultureInfo.CurrentCulture; + return string.Format ("{0}{4} {1}{4} {2}{4} {3}", p.Left, p.Top, p.Right, p.Bottom, culture.TextInfo.ListSeparator); + } else if (destinationType == typeof (InstanceDescriptor)) { + Type[] types; + Object[] values; + if (p.All != -1) { + types = new Type[] { typeof(int) }; + values = new Object[] { p.All }; + } else { + types = new Type[] { typeof(int), typeof(int), typeof(int), typeof(int) }; + values = new Object[] { p.Left, p.Top, p.Right, p.Bottom }; + } + ConstructorInfo ci = typeof(Padding).GetConstructor (types); + return new InstanceDescriptor (ci, values); + } + } + return base.ConvertTo (context, culture, value, destinationType); + } + + public override object CreateInstance (ITypeDescriptorContext context, IDictionary propertyValues) + { + if (propertyValues == null) + throw new ArgumentNullException ("propertyValues"); + if (context == null) + throw new ArgumentNullException ("context"); + + Padding old = (Padding)context.PropertyDescriptor.GetValue (context.Instance); + if (old.All == (int)propertyValues["All"]) + return new Padding ((int)propertyValues["Left"], (int)propertyValues["Top"], (int)propertyValues["Right"], (int)propertyValues["Bottom"]); + else + return new Padding ((int)propertyValues["All"]); + } + + public override bool GetCreateInstanceSupported (ITypeDescriptorContext context) + { + return true; + } + + public override PropertyDescriptorCollection GetProperties (ITypeDescriptorContext context, object value, Attribute[] attributes) + { + return TypeDescriptor.GetProperties (typeof (Padding), attributes); + } + + public override bool GetPropertiesSupported (ITypeDescriptorContext context) + { + return true; + } + #endregion + } +} diff --git a/source/ShiftUI/Internal/PaintEventArgs.cs b/source/ShiftUI/Internal/PaintEventArgs.cs new file mode 100644 index 0000000..0f05b84 --- /dev/null +++ b/source/ShiftUI/Internal/PaintEventArgs.cs @@ -0,0 +1,98 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +using System.Drawing; +using System; + +namespace ShiftUI { + public class PaintEventArgs : EventArgs, IDisposable { + private Graphics graphics; + private Rectangle clip_rectangle; + internal bool Handled; + private bool disposed; + + #region Public Constructors + public PaintEventArgs (Graphics graphics, Rectangle clipRect) + { + if (graphics == null) + throw new ArgumentNullException ("graphics"); + + this.graphics=graphics; + this.clip_rectangle=clipRect; + } + #endregion // Public Constructors + + #region Public Instance Properties + public Rectangle ClipRectangle { + get { + return this.clip_rectangle; + } + } + + public Graphics Graphics { + get { + return this.graphics; + } + } + #endregion // Public Instance Properties + + #region Public Instance Methods + public void Dispose() { + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion // Public Instance Methods + + // Returns the previous graphics + internal Graphics SetGraphics (Graphics g) + { + Graphics res = graphics; + graphics = g; + + return res; + } + + internal void SetClip (Rectangle clip) + { + clip_rectangle = clip; + } + + #region Protected Instance Methods + ~PaintEventArgs() { + Dispose(false); + } + + protected virtual void Dispose (bool disposing) + { + if (!disposed) { + disposed = true; + } + } + #endregion // Protected Instance Methods + } +} diff --git a/source/ShiftUI/Internal/PaintEventHandler.cs b/source/ShiftUI/Internal/PaintEventHandler.cs new file mode 100644 index 0000000..9e074ee --- /dev/null +++ b/source/ShiftUI/Internal/PaintEventHandler.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +namespace ShiftUI +{ + public delegate void PaintEventHandler (object sender, PaintEventArgs e); +} diff --git a/source/ShiftUI/Internal/Pasteboard.cs b/source/ShiftUI/Internal/Pasteboard.cs new file mode 100644 index 0000000..57a75b4 --- /dev/null +++ b/source/ShiftUI/Internal/Pasteboard.cs @@ -0,0 +1,106 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Geoff Norton (gnorton@novell.com) +// +// + + +using System; +using System.Runtime.InteropServices; +using ShiftUI; + +namespace ShiftUI.CarbonInternal { + internal class Pasteboard { + private static IntPtr primary_pbref; + private static IntPtr app_pbref; + + private static IntPtr internal_format; + + static Pasteboard () { + PasteboardCreate (XplatUICarbon.__CFStringMakeConstantString("com.apple.pasteboard.clipboard"), ref primary_pbref); + PasteboardCreate (IntPtr.Zero, ref app_pbref); + internal_format = XplatUICarbon.__CFStringMakeConstantString ("com.novell.mono.mwf.pasteboard"); + } + + internal static object Retrieve (IntPtr pbref, int key) { + UInt32 count = 0; + + key = (int)internal_format; + + PasteboardGetItemCount (pbref, ref count); + for (int i = 1; i <= count; i++) { + UInt32 itemid = 0; + + PasteboardGetItemIdentifier (pbref, (UInt32)i, ref itemid); + //FIXME: We should get all the flavors and enumerate but we're cheating for now + if (itemid == 0xFACE) { + IntPtr pbdata = IntPtr.Zero; + + PasteboardCopyItemFlavorData (pbref, (UInt32)0xFACE, (UInt32)key, ref pbdata); + if (pbdata != IntPtr.Zero) { + GCHandle handle = (GCHandle) Marshal.ReadIntPtr (CFDataGetBytePtr (pbdata)); + + return handle.Target; + } + } + } + return null; + } + + internal static void Store (IntPtr pbref, object data, int key) { + IntPtr gcdata = (IntPtr) GCHandle.Alloc (data); + IntPtr pbdata = CFDataCreate (IntPtr.Zero, ref gcdata, Marshal.SizeOf (typeof (IntPtr))); + + key = (int)internal_format; + + PasteboardClear (pbref); + PasteboardPutItemFlavor (pbref, (UInt32)0xFACE, (UInt32)key, pbdata, 0); + } + + internal static IntPtr Primary { + get { return primary_pbref; } + } + + internal static IntPtr Application { + get { return app_pbref; } + } + + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern IntPtr CFDataCreate (IntPtr allocator, ref IntPtr buf, Int32 length); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern IntPtr CFDataGetBytePtr (IntPtr data); + + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int PasteboardClear (IntPtr pbref); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int PasteboardCreate (IntPtr str, ref IntPtr pbref); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int PasteboardCopyItemFlavorData (IntPtr pbref, UInt32 itemid, UInt32 key, ref IntPtr data); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int PasteboardGetItemCount (IntPtr pbref, ref UInt32 count); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int PasteboardGetItemIdentifier (IntPtr pbref, UInt32 itemindex, ref UInt32 itemid); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int PasteboardPutItemFlavor (IntPtr pbref, UInt32 itemid, UInt32 key, IntPtr data, UInt32 flags); + } +} diff --git a/source/ShiftUI/Internal/PopupEventArgs.cs b/source/ShiftUI/Internal/PopupEventArgs.cs new file mode 100644 index 0000000..b11b837 --- /dev/null +++ b/source/ShiftUI/Internal/PopupEventArgs.cs @@ -0,0 +1,71 @@ +// +// PopupEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +using System.ComponentModel; +using System.Drawing; + +namespace ShiftUI +{ + public class PopupEventArgs : CancelEventArgs + { + private Widget associated_control; + private IWin32Window associated_window; + private bool is_balloon; + private Size tool_tip_size; + + #region Public Constructors + public PopupEventArgs (IWin32Window associatedWindow, Widget associatedControl, bool isBalloon, Size size) : base () + { + this.associated_window = associatedWindow; + this.associated_control = associatedControl; + this.is_balloon = isBalloon; + this.tool_tip_size = size; + } + #endregion // Public Constructors + + #region Public Instance Properties + public Widget AssociatedControl { + get { return this.associated_control; } + } + + public IWin32Window AssociatedWindow { + get { return this.associated_window; } + } + + public bool IsBalloon { + get { return this.is_balloon; } + } + + public Size ToolTipSize { + get { return this.tool_tip_size; } + set { this.tool_tip_size = value; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Internal/PopupEventHandler.cs b/source/ShiftUI/Internal/PopupEventHandler.cs new file mode 100644 index 0000000..ba87315 --- /dev/null +++ b/source/ShiftUI/Internal/PopupEventHandler.cs @@ -0,0 +1,32 @@ +// +// PopupEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void PopupEventHandler (object sender, PopupEventArgs e); +} diff --git a/source/ShiftUI/Internal/PreProcessControlState.cs b/source/ShiftUI/Internal/PreProcessControlState.cs new file mode 100644 index 0000000..bd573a5 --- /dev/null +++ b/source/ShiftUI/Internal/PreProcessControlState.cs @@ -0,0 +1,38 @@ +// +// PreProcessWidgetstate.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum PreProcessWidgetstate + { + MessageProcessed = 0, + MessageNeeded = 1, + MessageNotNeeded = 2 + } +} \ No newline at end of file diff --git a/source/ShiftUI/Internal/ProfessionalColorTable.cs b/source/ShiftUI/Internal/ProfessionalColorTable.cs new file mode 100644 index 0000000..ff42d37 --- /dev/null +++ b/source/ShiftUI/Internal/ProfessionalColorTable.cs @@ -0,0 +1,654 @@ +// +// ProfessionalColorTable.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using ShiftUI.VisualStyles; + +namespace ShiftUI +{ + public class ProfessionalColorTable + { + #region Private Variables + private bool use_system_colors = false; + + private Color button_checked_gradient_begin; + private Color button_checked_gradient_end; + private Color button_checked_gradient_middle; + private Color button_checked_highlight; + private Color button_checked_highlight_border; + private Color button_pressed_border; + private Color button_pressed_gradient_begin; + private Color button_pressed_gradient_end; + private Color button_pressed_gradient_middle; + private Color button_pressed_highlight; + private Color button_pressed_highlight_border; + private Color button_selected_border; + private Color button_selected_gradient_begin; + private Color button_selected_gradient_end; + private Color button_selected_gradient_middle; + private Color button_selected_highlight; + private Color button_selected_highlight_border; + private Color check_background; + private Color check_pressed_background; + private Color check_selected_background; + private Color grip_dark; + private Color grip_light; + private Color image_margin_gradient_begin; + private Color image_margin_gradient_end; + private Color image_margin_gradient_middle; + private Color image_margin_revealed_gradient_begin; + private Color image_margin_revealed_gradient_end; + private Color image_margin_revealed_gradient_middle; + private Color menu_border; + private Color menu_item_border; + private Color menu_item_pressed_gradient_begin; + private Color menu_item_pressed_gradient_end; + private Color menu_item_pressed_gradient_middle; + private Color menu_item_selected; + private Color menu_item_selected_gradient_begin; + private Color menu_item_selected_gradient_end; + private Color menu_strip_gradient_begin; + private Color menu_strip_gradient_end; + private Color overflow_button_gradient_begin; + private Color overflow_button_gradient_end; + private Color overflow_button_gradient_middle; + private Color rafting_container_gradient_begin; + private Color rafting_container_gradient_end; + private Color separator_dark; + private Color separator_light; + private Color status_strip_gradient_begin; + private Color status_strip_gradient_end; + private Color tool_strip_border; + private Color tool_strip_content_panel_gradient_begin; + private Color tool_strip_content_panel_gradient_end; + private Color tool_strip_drop_down_background; + private Color tool_strip_gradient_begin; + private Color tool_strip_gradient_end; + private Color tool_strip_gradient_middle; + private Color tool_strip_panel_gradient_begin; + private Color tool_strip_panel_gradient_end; + #endregion + + #region Public Constructor + public ProfessionalColorTable () + { + CalculateColors (); + } + #endregion + + #region Public Properties + public virtual Color ButtonCheckedGradientBegin { get { return this.button_checked_gradient_begin; } } + public virtual Color ButtonCheckedGradientEnd { get { return this.button_checked_gradient_end; } } + public virtual Color ButtonCheckedGradientMiddle { get { return this.button_checked_gradient_middle; } } + public virtual Color ButtonCheckedHighlight { get { return this.button_checked_highlight; } } + public virtual Color ButtonCheckedHighlightBorder { get { return this.button_checked_highlight_border; } } + public virtual Color ButtonPressedBorder { get { return this.button_pressed_border; } } + public virtual Color ButtonPressedGradientBegin { get { return this.button_pressed_gradient_begin; } } + public virtual Color ButtonPressedGradientEnd { get { return this.button_pressed_gradient_end; } } + public virtual Color ButtonPressedGradientMiddle { get { return this.button_pressed_gradient_middle; } } + public virtual Color ButtonPressedHighlight { get { return this.button_pressed_highlight; } } + public virtual Color ButtonPressedHighlightBorder { get { return this.button_pressed_highlight_border; } } + public virtual Color ButtonSelectedBorder { get { return this.button_selected_border; } } + public virtual Color ButtonSelectedGradientBegin { get { return this.button_selected_gradient_begin; } } + public virtual Color ButtonSelectedGradientEnd { get { return this.button_selected_gradient_end; } } + public virtual Color ButtonSelectedGradientMiddle { get { return this.button_selected_gradient_middle; } } + public virtual Color ButtonSelectedHighlight { get { return this.button_selected_highlight; } } + public virtual Color ButtonSelectedHighlightBorder { get { return this.button_selected_highlight_border; } } + public virtual Color CheckBackground { get { return this.check_background; } } + public virtual Color CheckPressedBackground { get { return this.check_pressed_background; } } + public virtual Color CheckSelectedBackground { get { return this.check_selected_background; } } + public virtual Color GripDark { get { return this.grip_dark; } } + public virtual Color GripLight { get { return this.grip_light; } } + public virtual Color ImageMarginGradientBegin { get { return this.image_margin_gradient_begin; } } + public virtual Color ImageMarginGradientEnd { get { return this.image_margin_gradient_end; } } + public virtual Color ImageMarginGradientMiddle { get { return this.image_margin_gradient_middle; } } + public virtual Color ImageMarginRevealedGradientBegin { get { return this.image_margin_revealed_gradient_begin; } } + public virtual Color ImageMarginRevealedGradientEnd { get { return this.image_margin_revealed_gradient_end; } } + public virtual Color ImageMarginRevealedGradientMiddle { get { return this.image_margin_revealed_gradient_middle; } } + public virtual Color MenuBorder { get { return this.menu_border; } } + public virtual Color MenuItemBorder { get { return this.menu_item_border; } } + public virtual Color MenuItemPressedGradientBegin { get { return this.menu_item_pressed_gradient_begin; } } + public virtual Color MenuItemPressedGradientEnd { get { return this.menu_item_pressed_gradient_end; } } + public virtual Color MenuItemPressedGradientMiddle { get { return this.menu_item_pressed_gradient_middle; } } + public virtual Color MenuItemSelected { get { return this.menu_item_selected; } } + public virtual Color MenuItemSelectedGradientBegin { get { return this.menu_item_selected_gradient_begin; } } + public virtual Color MenuItemSelectedGradientEnd { get { return this.menu_item_selected_gradient_end; } } + public virtual Color MenuStripGradientBegin { get { return this.menu_strip_gradient_begin; } } + public virtual Color MenuStripGradientEnd { get { return this.menu_strip_gradient_end; } } + public virtual Color OverflowButtonGradientBegin { get { return this.overflow_button_gradient_begin; } } + public virtual Color OverflowButtonGradientEnd { get { return this.overflow_button_gradient_end; } } + public virtual Color OverflowButtonGradientMiddle { get { return this.overflow_button_gradient_middle; } } + public virtual Color RaftingContainerGradientBegin { get { return this.rafting_container_gradient_begin; } } + public virtual Color RaftingContainerGradientEnd { get { return this.rafting_container_gradient_end; } } + public virtual Color SeparatorDark { get { return this.separator_dark; } } + public virtual Color SeparatorLight { get { return this.separator_light; } } + public virtual Color StatusStripGradientBegin { get { return this.status_strip_gradient_begin; } } + public virtual Color StatusStripGradientEnd { get { return this.status_strip_gradient_end; } } + public virtual Color ToolStripBorder { get { return this.tool_strip_border; } } + public virtual Color ToolStripContentPanelGradientBegin { get { return this.tool_strip_content_panel_gradient_begin; } } + public virtual Color ToolStripContentPanelGradientEnd { get { return this.tool_strip_content_panel_gradient_end; } } + public virtual Color ToolStripDropDownBackground { get { return this.tool_strip_drop_down_background; } } + public virtual Color ToolStripGradientBegin { get { return this.tool_strip_gradient_begin; } } + public virtual Color ToolStripGradientEnd { get { return this.tool_strip_gradient_end; } } + public virtual Color ToolStripGradientMiddle { get { return this.tool_strip_gradient_middle; } } + public virtual Color ToolStripPanelGradientBegin { get { return this.tool_strip_panel_gradient_begin; } } + public virtual Color ToolStripPanelGradientEnd { get { return this.tool_strip_panel_gradient_end; } } + public bool UseSystemColors { + get { return use_system_colors; } + set { + if (value != use_system_colors) { + use_system_colors = value; CalculateColors (); + } + } + } + #endregion + + #region Private Methods + private void CalculateColors () + { + switch (GetCurrentStyle ()) { + case ColorSchemes.Classic: + button_checked_gradient_begin = Color.Empty; + button_checked_gradient_end = Color.Empty; + button_checked_gradient_middle = Color.Empty; + button_checked_highlight = Color.FromArgb (184, 191, 211); + button_checked_highlight_border = Color.FromKnownColor (KnownColor.Highlight); + + button_pressed_border = Color.FromKnownColor (KnownColor.Highlight); + button_pressed_gradient_begin = Color.FromArgb (133, 146, 181); + button_pressed_gradient_end = Color.FromArgb (133, 146, 181); + button_pressed_gradient_middle = Color.FromArgb (133, 146, 181); + button_pressed_highlight = Color.FromArgb (131, 144, 179); + button_pressed_highlight_border = Color.FromKnownColor (KnownColor.Highlight); + + button_selected_border = Color.FromKnownColor (KnownColor.Highlight); + button_selected_gradient_begin = Color.FromArgb (182, 189, 210); + button_selected_gradient_end = Color.FromArgb (182, 189, 210); + button_selected_gradient_middle = Color.FromArgb (182, 189, 210); + button_selected_highlight = Color.FromArgb (184, 191, 211); + button_selected_highlight_border = Color.FromKnownColor (KnownColor.Highlight); + + check_background = Color.FromKnownColor (KnownColor.Highlight); + check_pressed_background = Color.FromArgb (133, 146, 181); + check_selected_background = Color.FromArgb (133, 146, 181); + + grip_dark = Color.FromArgb (160, 160, 160); + grip_light = SystemColors.Window; + + image_margin_gradient_begin = Color.FromArgb (245, 244, 242); + image_margin_gradient_end = SystemColors.Control; + image_margin_gradient_middle = Color.FromArgb (234, 232, 228); + image_margin_revealed_gradient_begin = Color.FromArgb (238, 236, 233); + image_margin_revealed_gradient_end = Color.FromArgb (216, 213, 206); + image_margin_revealed_gradient_middle = Color.FromArgb (225, 222, 217); + + menu_border = Color.FromArgb (102, 102, 102); + menu_item_border = SystemColors.Highlight; + + menu_item_pressed_gradient_begin = Color.FromArgb (245, 244, 242); + menu_item_pressed_gradient_end = Color.FromArgb (234, 232, 228); + menu_item_pressed_gradient_middle = Color.FromArgb (225, 222, 217); + menu_item_selected = SystemColors.Window; + menu_item_selected_gradient_begin = Color.FromArgb (182, 189, 210); + menu_item_selected_gradient_end = Color.FromArgb (182, 189, 210); + + menu_strip_gradient_begin = SystemColors.ButtonFace; + menu_strip_gradient_end = Color.FromArgb (246, 245, 244); + + overflow_button_gradient_begin = Color.FromArgb (225, 222, 217); + overflow_button_gradient_end = SystemColors.ButtonShadow; + overflow_button_gradient_middle = Color.FromArgb (216, 213, 206); + + rafting_container_gradient_begin = SystemColors.ButtonFace; + rafting_container_gradient_end = Color.FromArgb (246, 245, 244); + + separator_dark = Color.FromArgb (166, 166, 166); + separator_light = SystemColors.ButtonHighlight; + + status_strip_gradient_begin = SystemColors.ButtonFace; + status_strip_gradient_end = Color.FromArgb (246, 245, 244); + + tool_strip_border = Color.FromArgb (219, 216, 209); + tool_strip_content_panel_gradient_begin = SystemColors.ButtonFace; + tool_strip_content_panel_gradient_end = Color.FromArgb (246, 245, 244); + tool_strip_drop_down_background = SystemColors.Window; + + tool_strip_gradient_begin = Color.FromArgb (245, 244, 242); + tool_strip_gradient_end = SystemColors.ButtonFace; + tool_strip_gradient_middle = Color.FromArgb (234, 232, 228); + + tool_strip_panel_gradient_begin = SystemColors.ButtonFace; + tool_strip_panel_gradient_end = Color.FromArgb (246, 245, 244); + break; + case ColorSchemes.NormalColor: + button_checked_gradient_begin = use_system_colors ? Color.Empty : Color.FromArgb (255, 223, 154); + button_checked_gradient_end = use_system_colors ? Color.Empty : Color.FromArgb (255, 166, 76); + button_checked_gradient_middle = use_system_colors ? Color.Empty : Color.FromArgb (255, 195, 116); + button_checked_highlight = Color.FromArgb (195, 211, 237); + button_checked_highlight_border = Color.FromKnownColor (KnownColor.Highlight); + button_pressed_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (0, 0, 128); + button_pressed_gradient_begin = use_system_colors ? Color.FromArgb (152, 181, 226) : Color.FromArgb (254, 128, 62); + button_pressed_gradient_end = use_system_colors ? Color.FromArgb (152, 181, 226) : Color.FromArgb (255, 223, 154); + button_pressed_gradient_middle = use_system_colors ? Color.FromArgb (152, 181, 226) : Color.FromArgb (255, 177, 109); + button_pressed_highlight = use_system_colors ? Color.FromArgb (150, 179, 225) : Color.FromArgb (150, 179, 225); + button_pressed_highlight_border = Color.FromKnownColor (KnownColor.Highlight); + button_selected_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (0, 0, 128); + button_selected_gradient_begin = use_system_colors ? Color.FromArgb (193, 210, 238) : Color.FromArgb (255, 255, 222); + button_selected_gradient_end = use_system_colors ? Color.FromArgb (193, 210, 238) : Color.FromArgb (255, 203, 136); + button_selected_gradient_middle = use_system_colors ? Color.FromArgb (193, 210, 238) : Color.FromArgb (255, 225, 172); + button_selected_highlight = use_system_colors ? Color.FromArgb (195, 211, 237) : Color.FromArgb (195, 211, 237); + button_selected_highlight_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (0, 0, 128); + + check_background = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (255, 192, 111); + check_pressed_background = use_system_colors ? Color.FromArgb (152, 181, 226) : Color.FromArgb (254, 128, 62); + check_selected_background = use_system_colors ? Color.FromArgb (152, 181, 226) : Color.FromArgb (254, 128, 62); + + grip_dark = use_system_colors ? Color.FromArgb (193, 190, 179) : Color.FromArgb (39, 65, 118); + grip_light = use_system_colors ? SystemColors.Window : Color.FromArgb (255, 255, 255); + + image_margin_gradient_begin = use_system_colors ? Color.FromArgb (251, 250, 246) : Color.FromArgb (227, 239, 255); + image_margin_gradient_end = use_system_colors ? SystemColors.Control : Color.FromArgb (123, 164, 224); + image_margin_gradient_middle = use_system_colors ? Color.FromArgb (246, 244, 236) : Color.FromArgb (203, 225, 252); + image_margin_revealed_gradient_begin = use_system_colors ? Color.FromArgb (247, 246, 239) : Color.FromArgb (203, 221, 246); + image_margin_revealed_gradient_end = use_system_colors ? Color.FromArgb (238, 235, 220) : Color.FromArgb (114, 155, 215); + image_margin_revealed_gradient_middle = use_system_colors ? Color.FromArgb (242, 240, 228) : Color.FromArgb (161, 197, 249); + + menu_border = use_system_colors ? Color.FromArgb (138, 134, 122) : Color.FromArgb (0, 45, 150); + menu_item_border = use_system_colors ? SystemColors.Highlight : Color.FromArgb (0, 0, 128); + + menu_item_pressed_gradient_begin = use_system_colors ? Color.FromArgb (251, 250, 246) : Color.FromArgb (227, 239, 255); + menu_item_pressed_gradient_end = use_system_colors ? Color.FromArgb (246, 244, 236) : Color.FromArgb (123, 164, 224); + menu_item_pressed_gradient_middle = use_system_colors ? Color.FromArgb (242, 240, 228) : Color.FromArgb (161, 197, 249); + menu_item_selected = use_system_colors ? SystemColors.Window : Color.FromArgb (255, 238, 194); + menu_item_selected_gradient_begin = use_system_colors ? Color.FromArgb (193, 210, 238) : Color.FromArgb (255, 255, 222); + menu_item_selected_gradient_end = use_system_colors ? Color.FromArgb (193, 210, 238) : Color.FromArgb (255, 203, 136); + + menu_strip_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (158, 190, 245); + menu_strip_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (196, 218, 250); + + overflow_button_gradient_begin = use_system_colors ? Color.FromArgb (242, 240, 228) : Color.FromArgb (127, 177, 250); + overflow_button_gradient_end = use_system_colors ? SystemColors.ButtonShadow : Color.FromArgb (0, 53, 145); + overflow_button_gradient_middle = use_system_colors ? Color.FromArgb (238, 235, 220) : Color.FromArgb (82, 127, 208); + + rafting_container_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (158, 190, 245); + rafting_container_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (196, 218, 250); + + separator_dark = use_system_colors ? Color.FromArgb (197, 194, 184) : Color.FromArgb (106, 140, 203); + separator_light = use_system_colors ? SystemColors.ButtonHighlight : Color.FromArgb (241, 249, 255); + + status_strip_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (158, 190, 245); + status_strip_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (196, 218, 250); + + tool_strip_border = use_system_colors ? Color.FromArgb (239, 237, 222) : Color.FromArgb (59, 97, 156); + tool_strip_content_panel_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (158, 190, 245); + tool_strip_content_panel_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (196, 218, 250); + tool_strip_drop_down_background = use_system_colors ? Color.FromArgb (252, 252, 249) : Color.FromArgb (246, 246, 246); + + tool_strip_gradient_begin = use_system_colors ? Color.FromArgb (251, 250, 246) : Color.FromArgb (227, 239, 255); + tool_strip_gradient_end = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (123, 164, 224); + tool_strip_gradient_middle = use_system_colors ? Color.FromArgb (246, 244, 236) : Color.FromArgb (203, 225, 252); + + tool_strip_panel_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (158, 190, 245); + tool_strip_panel_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (196, 218, 250); + break; + case ColorSchemes.HomeStead: + button_checked_gradient_begin = use_system_colors ? Color.Empty : Color.FromArgb (255, 223, 154); + button_checked_gradient_end = use_system_colors ? Color.Empty : Color.FromArgb (255, 166, 76); + button_checked_gradient_middle = use_system_colors ? Color.Empty : Color.FromArgb (255, 195, 116); + button_checked_highlight = Color.FromArgb (223, 227, 213); + button_checked_highlight_border = Color.FromKnownColor (KnownColor.Highlight); + + button_pressed_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (63, 93, 56); + button_pressed_gradient_begin = use_system_colors ? Color.FromArgb (201, 208, 184) : Color.FromArgb (254, 128, 62); + button_pressed_gradient_end = use_system_colors ? Color.FromArgb (201, 208, 184) : Color.FromArgb (255, 223, 154); + button_pressed_gradient_middle = use_system_colors ? Color.FromArgb (201, 208, 184) : Color.FromArgb (255, 177, 109); + button_pressed_highlight = use_system_colors ? Color.FromArgb (200, 206, 182) : Color.FromArgb (200, 206, 182); + button_pressed_highlight_border = Color.FromKnownColor (KnownColor.Highlight); + + button_selected_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (63, 93, 56); + button_selected_gradient_begin = use_system_colors ? Color.FromArgb (223, 227, 212) : Color.FromArgb (255, 255, 222); + button_selected_gradient_end = use_system_colors ? Color.FromArgb (223, 227, 212) : Color.FromArgb (255, 203, 136); + button_selected_gradient_middle = use_system_colors ? Color.FromArgb (223, 227, 212) : Color.FromArgb (255, 225, 172); + button_selected_highlight = use_system_colors ? Color.FromArgb (223, 227, 213) : Color.FromArgb (223, 227, 213); + button_selected_highlight_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (63, 93, 56); + + check_background = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (255, 192, 111); + check_pressed_background = use_system_colors ? Color.FromArgb (201, 208, 184) : Color.FromArgb (254, 128, 62); + check_selected_background = use_system_colors ? Color.FromArgb (201, 208, 184) : Color.FromArgb (254, 128, 62); + + grip_dark = use_system_colors ? Color.FromArgb (193, 190, 179) : Color.FromArgb (81, 94, 51); + grip_light = use_system_colors ? SystemColors.Window : Color.FromArgb (255, 255, 255); + + image_margin_gradient_begin = use_system_colors ? Color.FromArgb (251, 250, 246) : Color.FromArgb (255, 255, 237); + image_margin_gradient_end = use_system_colors ? SystemColors.Control : Color.FromArgb (181, 196, 143); + image_margin_gradient_middle = use_system_colors ? Color.FromArgb (246, 244, 236) : Color.FromArgb (206, 220, 167); + image_margin_revealed_gradient_begin = use_system_colors ? Color.FromArgb (247, 246, 239) : Color.FromArgb (230, 230, 209); + image_margin_revealed_gradient_end = use_system_colors ? Color.FromArgb (238, 235, 220) : Color.FromArgb (160, 177, 116); + image_margin_revealed_gradient_middle = use_system_colors ? Color.FromArgb (242, 240, 228) : Color.FromArgb (186, 201, 143); + + menu_border = use_system_colors ? Color.FromArgb (138, 134, 122) : Color.FromArgb (117, 141, 94); + menu_item_border = use_system_colors ? SystemColors.Highlight : Color.FromArgb (63, 93, 56); + + menu_item_pressed_gradient_begin = use_system_colors ? Color.FromArgb (251, 250, 246) : Color.FromArgb (237, 240, 214); + menu_item_pressed_gradient_end = use_system_colors ? Color.FromArgb (246, 244, 236) : Color.FromArgb (181, 196, 143); + menu_item_pressed_gradient_middle = use_system_colors ? Color.FromArgb (242, 240, 228) : Color.FromArgb (186, 201, 143); + menu_item_selected = use_system_colors ? SystemColors.Window : Color.FromArgb (255, 238, 194); + menu_item_selected_gradient_begin = use_system_colors ? Color.FromArgb (223, 227, 212) : Color.FromArgb (255, 255, 222); + menu_item_selected_gradient_end = use_system_colors ? Color.FromArgb (223, 227, 212) : Color.FromArgb (255, 203, 136); + + menu_strip_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (217, 217, 167); + menu_strip_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (242, 241, 228); + + overflow_button_gradient_begin = use_system_colors ? Color.FromArgb (242, 240, 228) : Color.FromArgb (186, 204, 150); + overflow_button_gradient_end = use_system_colors ? SystemColors.ButtonShadow : Color.FromArgb (96, 119, 107); + overflow_button_gradient_middle = use_system_colors ? Color.FromArgb (238, 235, 220) : Color.FromArgb (141, 160, 107); + + rafting_container_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (217, 217, 167); + rafting_container_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (242, 241, 228); + + separator_dark = use_system_colors ? Color.FromArgb (197, 194, 184) : Color.FromArgb (96, 128, 88); + separator_light = use_system_colors ? SystemColors.ButtonHighlight : Color.FromArgb (244, 247, 222); + + status_strip_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (217, 217, 167); + status_strip_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (242, 241, 228); + + tool_strip_border = use_system_colors ? Color.FromArgb (239, 237, 222) : Color.FromArgb (96, 128, 88); + tool_strip_content_panel_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (217, 217, 167); + tool_strip_content_panel_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (242, 241, 228); + tool_strip_drop_down_background = use_system_colors ? Color.FromArgb (252, 252, 249) : Color.FromArgb (244, 244, 238); + + tool_strip_gradient_begin = use_system_colors ? Color.FromArgb (251, 250, 246) : Color.FromArgb (255, 255, 237); + tool_strip_gradient_end = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (181, 196, 143); + tool_strip_gradient_middle = use_system_colors ? Color.FromArgb (246, 244, 236) : Color.FromArgb (206, 220, 167); + + tool_strip_panel_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (217, 217, 167); + tool_strip_panel_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 247) : Color.FromArgb (242, 241, 228); + break; + case ColorSchemes.Metallic: + button_checked_gradient_begin = use_system_colors ? Color.Empty : Color.FromArgb (255, 223, 154); + button_checked_gradient_end = use_system_colors ? Color.Empty : Color.FromArgb (255, 166, 76); + button_checked_gradient_middle = use_system_colors ? Color.Empty : Color.FromArgb (255, 195, 116); + button_checked_highlight = Color.FromArgb (231, 232, 235); + button_checked_highlight_border = Color.FromKnownColor (KnownColor.Highlight); + + button_pressed_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (75, 75, 111); + button_pressed_gradient_begin = use_system_colors ? Color.FromArgb (217, 218, 223) : Color.FromArgb (254, 128, 62); + button_pressed_gradient_end = use_system_colors ? Color.FromArgb (217, 218, 223) : Color.FromArgb (255, 223, 154); + button_pressed_gradient_middle = use_system_colors ? Color.FromArgb (217, 218, 223) : Color.FromArgb (255, 177, 109); + button_pressed_highlight = use_system_colors ? Color.FromArgb (215, 216, 222) : Color.FromArgb (215, 216, 222); + button_pressed_highlight_border = Color.FromKnownColor (KnownColor.Highlight); + + button_selected_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (75, 75, 111); + button_selected_gradient_begin = use_system_colors ? Color.FromArgb (232, 233, 236) : Color.FromArgb (255, 255, 222); + button_selected_gradient_end = use_system_colors ? Color.FromArgb (232, 233, 236) : Color.FromArgb (255, 203, 136); + button_selected_gradient_middle = use_system_colors ? Color.FromArgb (232, 233, 236) : Color.FromArgb (255, 225, 172); + button_selected_highlight = use_system_colors ? Color.FromArgb (231, 232, 235) : Color.FromArgb (231, 232, 235); + button_selected_highlight_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (75, 75, 111); + + check_background = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (255, 192, 111); + check_pressed_background = use_system_colors ? Color.FromArgb (217, 218, 223) : Color.FromArgb (254, 128, 62); + check_selected_background = use_system_colors ? Color.FromArgb (217, 218, 223) : Color.FromArgb (254, 128, 62); + + grip_dark = use_system_colors ? Color.FromArgb (182, 182, 185) : Color.FromArgb (84, 84, 117); + grip_light = use_system_colors ? SystemColors.Window : Color.FromArgb (255, 255, 255); + + image_margin_gradient_begin = use_system_colors ? Color.FromArgb (248, 248, 249) : Color.FromArgb (249, 249, 255); + image_margin_gradient_end = use_system_colors ? SystemColors.Control : Color.FromArgb (147, 145, 176); + image_margin_gradient_middle = use_system_colors ? Color.FromArgb (240, 239, 241) : Color.FromArgb (225, 226, 236); + image_margin_revealed_gradient_begin = use_system_colors ? Color.FromArgb (243, 242, 244) : Color.FromArgb (215, 215, 226); + image_margin_revealed_gradient_end = use_system_colors ? Color.FromArgb (227, 226, 230) : Color.FromArgb (118, 116, 151); + image_margin_revealed_gradient_middle = use_system_colors ? Color.FromArgb (233, 233, 235) : Color.FromArgb (184, 185, 202); + + menu_border = use_system_colors ? Color.FromArgb (126, 126, 129) : Color.FromArgb (124, 124, 148); + menu_item_border = use_system_colors ? SystemColors.Highlight : Color.FromArgb (75, 75, 111); + + menu_item_pressed_gradient_begin = use_system_colors ? Color.FromArgb (248, 248, 249) : Color.FromArgb (232, 233, 242); + menu_item_pressed_gradient_end = use_system_colors ? Color.FromArgb (240, 239, 241) : Color.FromArgb (172, 170, 194); + menu_item_pressed_gradient_middle = use_system_colors ? Color.FromArgb (233, 233, 235) : Color.FromArgb (184, 185, 202); + menu_item_selected = use_system_colors ? SystemColors.Window : Color.FromArgb (255, 238, 194); + menu_item_selected_gradient_begin = use_system_colors ? Color.FromArgb (232, 233, 236) : Color.FromArgb (255, 255, 222); + menu_item_selected_gradient_end = use_system_colors ? Color.FromArgb (232, 233, 236) : Color.FromArgb (255, 203, 136); + + menu_strip_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (215, 215, 229); + menu_strip_gradient_end = use_system_colors ? Color.FromArgb (249, 248, 249) : Color.FromArgb (243, 243, 247); + + overflow_button_gradient_begin = use_system_colors ? Color.FromArgb (233, 233, 235) : Color.FromArgb (186, 185, 206); + overflow_button_gradient_end = use_system_colors ? SystemColors.ButtonShadow : Color.FromArgb (118, 116, 146); + overflow_button_gradient_middle = use_system_colors ? Color.FromArgb (227, 226, 230) : Color.FromArgb (156, 155, 180); + + rafting_container_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (215, 215, 229); + rafting_container_gradient_end = use_system_colors ? Color.FromArgb (249, 248, 249) : Color.FromArgb (243, 243, 247); + + separator_dark = use_system_colors ? Color.FromArgb (186, 186, 189) : Color.FromArgb (110, 109, 143); + separator_light = use_system_colors ? SystemColors.ButtonHighlight : Color.FromArgb (255, 255, 255); + + status_strip_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (215, 215, 229); + status_strip_gradient_end = use_system_colors ? Color.FromArgb (249, 248, 249) : Color.FromArgb (243, 243, 247); + + tool_strip_border = use_system_colors ? Color.FromArgb (229, 228, 232) : Color.FromArgb (124, 124, 148); + tool_strip_content_panel_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (215, 215, 229); + tool_strip_content_panel_gradient_end = use_system_colors ? Color.FromArgb (249, 248, 249) : Color.FromArgb (243, 243, 247); + tool_strip_drop_down_background = use_system_colors ? Color.FromArgb (251, 250, 251) : Color.FromArgb (253, 250, 255); + + tool_strip_gradient_begin = use_system_colors ? Color.FromArgb (248, 248, 249) : Color.FromArgb (249, 249, 255); + tool_strip_gradient_end = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (147, 145, 176); + tool_strip_gradient_middle = use_system_colors ? Color.FromArgb (240, 239, 241) : Color.FromArgb (225, 226, 236); + + tool_strip_panel_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (215, 215, 229); + tool_strip_panel_gradient_end = use_system_colors ? Color.FromArgb (249, 248, 249) : Color.FromArgb (243, 243, 247); + break; + case ColorSchemes.MediaCenter: + button_checked_gradient_begin = use_system_colors ? Color.Empty : Color.FromArgb (226, 229, 238); + button_checked_gradient_end = use_system_colors ? Color.Empty : Color.FromArgb (226, 229, 238); + button_checked_gradient_middle = use_system_colors ? Color.Empty : Color.FromArgb (226, 229, 238); + button_checked_highlight = Color.FromArgb (196, 208, 229); + button_checked_highlight_border = Color.FromKnownColor (KnownColor.Highlight); + + button_pressed_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (51, 94, 168); + button_pressed_gradient_begin = use_system_colors ? Color.FromArgb (153, 175, 212) : Color.FromArgb (153, 175, 212); + button_pressed_gradient_end = use_system_colors ? Color.FromArgb (153, 175, 212) : Color.FromArgb (153, 175, 212); + button_pressed_gradient_middle = use_system_colors ? Color.FromArgb (153, 175, 212) : Color.FromArgb (153, 175, 212); + button_pressed_highlight = use_system_colors ? Color.FromArgb (152, 173, 210) : Color.FromArgb (152, 173, 210); + button_pressed_highlight_border = Color.FromKnownColor (KnownColor.Highlight); + + button_selected_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (51, 94, 168); + button_selected_gradient_begin = use_system_colors ? Color.FromArgb (194, 207, 229) : Color.FromArgb (194, 207, 229); + button_selected_gradient_end = use_system_colors ? Color.FromArgb (194, 207, 229) : Color.FromArgb (194, 207, 229); + button_selected_gradient_middle = use_system_colors ? Color.FromArgb (194, 207, 229) : Color.FromArgb (194, 207, 229); + button_selected_highlight = use_system_colors ? Color.FromArgb (196, 208, 229) : Color.FromArgb (196, 208, 229); + button_selected_highlight_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (51, 94, 168); + + check_background = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (226, 229, 238); + check_pressed_background = use_system_colors ? Color.FromArgb (153, 175, 212) : Color.FromArgb (51, 94, 168); + check_selected_background = use_system_colors ? Color.FromArgb (153, 175, 212) : Color.FromArgb (51, 94, 168); + + grip_dark = use_system_colors ? Color.FromArgb (189, 188, 191) : Color.FromArgb (189, 188, 191); + grip_light = use_system_colors ? SystemColors.Window : Color.FromArgb (255, 255, 255); + + image_margin_gradient_begin = use_system_colors ? Color.FromArgb (250, 250, 251) : Color.FromArgb (252, 252, 252); + image_margin_gradient_end = use_system_colors ? SystemColors.Control : Color.FromArgb (235, 233, 237); + image_margin_gradient_middle = use_system_colors ? Color.FromArgb (245, 244, 246) : Color.FromArgb (245, 244, 246); + image_margin_revealed_gradient_begin = use_system_colors ? Color.FromArgb (247, 246, 248) : Color.FromArgb (247, 246, 248); + image_margin_revealed_gradient_end = use_system_colors ? Color.FromArgb (237, 235, 239) : Color.FromArgb (228, 226, 230); + image_margin_revealed_gradient_middle = use_system_colors ? Color.FromArgb (241, 240, 242) : Color.FromArgb (241, 240, 242); + + menu_border = use_system_colors ? Color.FromArgb (134, 133, 136) : Color.FromArgb (134, 133, 136); + menu_item_border = use_system_colors ? SystemColors.Highlight : Color.FromArgb (51, 94, 168); + + menu_item_pressed_gradient_begin = use_system_colors ? Color.FromArgb (250, 250, 251) : Color.FromArgb (252, 252, 252); + menu_item_pressed_gradient_end = use_system_colors ? Color.FromArgb (245, 244, 246) : Color.FromArgb (245, 244, 246); + menu_item_pressed_gradient_middle = use_system_colors ? Color.FromArgb (241, 240, 242) : Color.FromArgb (241, 240, 242); + menu_item_selected = use_system_colors ? SystemColors.Window : Color.FromArgb (194, 207, 229); + menu_item_selected_gradient_begin = use_system_colors ? Color.FromArgb (194, 207, 229) : Color.FromArgb (194, 207, 229); + menu_item_selected_gradient_end = use_system_colors ? Color.FromArgb (194, 207, 229) : Color.FromArgb (194, 207, 229); + + menu_strip_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (235, 233, 237); + menu_strip_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 251) : Color.FromArgb (251, 250, 251); + + overflow_button_gradient_begin = use_system_colors ? Color.FromArgb (241, 240, 242) : Color.FromArgb (242, 242, 242); + overflow_button_gradient_end = use_system_colors ? SystemColors.ButtonShadow : Color.FromArgb (167, 166, 170); + overflow_button_gradient_middle = use_system_colors ? Color.FromArgb (237, 235, 239) : Color.FromArgb (224, 224, 225); + + rafting_container_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (235, 233, 237); + rafting_container_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 251) : Color.FromArgb (251, 250, 251); + + separator_dark = use_system_colors ? Color.FromArgb (193, 193, 196) : Color.FromArgb (193, 193, 196); + separator_light = use_system_colors ? SystemColors.ButtonHighlight : Color.FromArgb (255, 255, 255); + + status_strip_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (235, 233, 237); + status_strip_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 251) : Color.FromArgb (251, 250, 251); + + tool_strip_border = use_system_colors ? Color.FromArgb (238, 237, 240) : Color.FromArgb (238, 237, 240); + tool_strip_content_panel_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (235, 233, 237); + tool_strip_content_panel_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 251) : Color.FromArgb (251, 250, 251); + tool_strip_drop_down_background = use_system_colors ? Color.FromArgb (252, 252, 252) : Color.FromArgb (252, 252, 252); + + tool_strip_gradient_begin = use_system_colors ? Color.FromArgb (250, 250, 251) : Color.FromArgb (252, 252, 252); + tool_strip_gradient_end = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (235, 233, 237); + tool_strip_gradient_middle = use_system_colors ? Color.FromArgb (245, 244, 246) : Color.FromArgb (245, 244, 246); + + tool_strip_panel_gradient_begin = use_system_colors ? SystemColors.ButtonFace : Color.FromArgb (235, 233, 237); + tool_strip_panel_gradient_end = use_system_colors ? Color.FromArgb (251, 250, 251) : Color.FromArgb (251, 250, 251); + break; + case ColorSchemes.Aero: + button_checked_gradient_begin = Color.Empty; + button_checked_gradient_end = Color.Empty; + button_checked_gradient_middle = Color.Empty; + button_checked_highlight = Color.FromArgb (196, 225, 255); + button_checked_highlight_border = Color.FromKnownColor (KnownColor.Highlight); + + button_pressed_border = Color.FromKnownColor (KnownColor.Highlight); + button_pressed_gradient_begin = Color.FromArgb (153, 204, 255); + button_pressed_gradient_end = Color.FromArgb (153, 204, 255); + button_pressed_gradient_middle = Color.FromArgb (153, 204, 255); + button_pressed_highlight = Color.FromArgb (152, 203, 255); + button_pressed_highlight_border = Color.FromKnownColor (KnownColor.Highlight); + + button_selected_border = use_system_colors ? Color.FromKnownColor (KnownColor.Highlight) : Color.FromArgb (51, 94, 168); + button_selected_gradient_begin = Color.FromArgb (194, 224, 255); + button_selected_gradient_end = Color.FromArgb (194, 224, 255); + button_selected_gradient_middle = Color.FromArgb (194, 224, 255); + button_selected_highlight = Color.FromArgb (196, 225, 255); + button_selected_highlight_border = Color.FromKnownColor (KnownColor.Highlight); + + check_background = Color.FromKnownColor (KnownColor.Highlight); + check_pressed_background = Color.FromArgb (153, 204, 255); + check_selected_background = Color.FromArgb (153, 204, 255); + + grip_dark = Color.FromArgb (184, 184, 184); + grip_light = SystemColors.Window; + + image_margin_gradient_begin = Color.FromArgb (252, 252, 252); + image_margin_gradient_end = SystemColors.Control; + image_margin_gradient_middle = Color.FromArgb (250, 250, 250); + image_margin_revealed_gradient_begin = Color.FromArgb (251, 251, 251); + image_margin_revealed_gradient_end = Color.FromArgb (245, 245, 245); + image_margin_revealed_gradient_middle = Color.FromArgb (247, 247, 247); + + menu_border = Color.FromArgb (128, 128, 128); + menu_item_border = SystemColors.Highlight; + + menu_item_pressed_gradient_begin = Color.FromArgb (252, 252, 252); + menu_item_pressed_gradient_end = Color.FromArgb (250, 250, 250); + menu_item_pressed_gradient_middle = Color.FromArgb (247, 247, 247); + menu_item_selected = SystemColors.Window; + menu_item_selected_gradient_begin = Color.FromArgb (194, 224, 255); + menu_item_selected_gradient_end = Color.FromArgb (194, 224, 255); + + menu_strip_gradient_begin = SystemColors.ButtonFace; + menu_strip_gradient_end = Color.FromArgb (253, 253, 253); + + overflow_button_gradient_begin = Color.FromArgb (247, 247, 247); + overflow_button_gradient_end = SystemColors.ButtonShadow; + overflow_button_gradient_middle = Color.FromArgb (245, 245, 245); + + rafting_container_gradient_begin = SystemColors.ButtonFace; + rafting_container_gradient_end = Color.FromArgb (253, 253, 253); + + separator_dark = Color.FromArgb (189, 189, 189); + separator_light = SystemColors.ButtonHighlight; + + status_strip_gradient_begin = SystemColors.ButtonFace; + status_strip_gradient_end = Color.FromArgb (253, 253, 253); + + tool_strip_border = Color.FromArgb (246, 246, 246); + tool_strip_content_panel_gradient_begin = SystemColors.ButtonFace; + tool_strip_content_panel_gradient_end = Color.FromArgb (253, 253, 253); + tool_strip_drop_down_background = Color.FromArgb (253, 253, 253); + + tool_strip_gradient_begin = Color.FromArgb (252, 252, 252); + tool_strip_gradient_end = SystemColors.ButtonFace; + tool_strip_gradient_middle = Color.FromArgb (250, 250, 250); + + tool_strip_panel_gradient_begin = SystemColors.ButtonFace; + tool_strip_panel_gradient_end = Color.FromArgb (253, 253, 253); + break; + } + } + + private ColorSchemes GetCurrentStyle () + { + if (!VisualStyleInformation.IsEnabledByUser || string.IsNullOrEmpty (VisualStylesEngine.Instance.VisualStyleInformationFileName)) + + + return ColorSchemes.Classic; + else { + switch (System.IO.Path.GetFileNameWithoutExtension (VisualStylesEngine.Instance.VisualStyleInformationFileName).ToLowerInvariant ()) { + case "aero": + return ColorSchemes.Aero; + case "royale": + return ColorSchemes.MediaCenter; + default: + switch (VisualStyleInformation.ColorScheme) { + case "NormalColor": + return ColorSchemes.NormalColor; + case "HomeStead": + return ColorSchemes.HomeStead; + case "Metallic": + return ColorSchemes.Metallic; + default: + return ColorSchemes.Classic; + } + } + } + } + #endregion + + #region Private Enums + private enum ColorSchemes + { + Classic, // Windows Classic (No theme) + NormalColor, // Luna Blue + HomeStead, // Luna Olive + Metallic, // Luna Silver + MediaCenter, // Media Center (Energy Blue) + Aero // Windows Vista + } + #endregion + } +} diff --git a/source/ShiftUI/Internal/PropertyManager.cs b/source/ShiftUI/Internal/PropertyManager.cs new file mode 100644 index 0000000..f31608f --- /dev/null +++ b/source/ShiftUI/Internal/PropertyManager.cs @@ -0,0 +1,166 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. +// +// Authors: +// Jackson Harper jackson@ximian.com + +using System; +using System.Collections; +using System.ComponentModel; + +namespace ShiftUI { + + public class PropertyManager : BindingManagerBase { + + internal string property_name; + private PropertyDescriptor prop_desc; + private object data_source; + private EventDescriptor changed_event; + private EventHandler property_value_changed_handler; + + public PropertyManager() { + } + + internal PropertyManager (object data_source) + { + SetDataSource (data_source); + } + + internal PropertyManager (object data_source, string property_name) + { + this.property_name = property_name; + + SetDataSource (data_source); + } + + internal void SetDataSource (object new_data_source) + { + if (changed_event != null) + changed_event.RemoveEventHandler (data_source, property_value_changed_handler); + + data_source = new_data_source; + + if (property_name != null) { + prop_desc = TypeDescriptor.GetProperties (data_source).Find (property_name, true); + + if (prop_desc == null) + return; + + changed_event = TypeDescriptor.GetEvents (data_source).Find (property_name + "Changed", false); + if (changed_event != null) { + property_value_changed_handler = new EventHandler (PropertyValueChanged); + changed_event.AddEventHandler (data_source, property_value_changed_handler); + } + } + } + + void PropertyValueChanged (object sender, EventArgs args) + { + OnCurrentChanged (args); + } + + public override object Current { + get { return prop_desc == null ? data_source : prop_desc.GetValue (data_source); } + } + + public override int Position { + get { return 0; } + set { /* Doesn't do anything on MS" */ } + } + + public override int Count { + get { return 1; } + } + + public override void AddNew () + { + throw new NotSupportedException ("AddNew is not supported for property to property binding"); + } + + public override void CancelCurrentEdit () + { + IEditableObject editable = data_source as IEditableObject; + if (editable == null) + return; + editable.CancelEdit (); + + PushData (); + } + + public override void EndCurrentEdit () + { + PullData (); + + IEditableObject editable = data_source as IEditableObject; + if (editable == null) + return; + editable.EndEdit (); + } + + // Hide this method from the 2.0 public API + internal override PropertyDescriptorCollection GetItemPropertiesInternal () + { + return TypeDescriptor.GetProperties (data_source); + } + + public override void RemoveAt (int index) + { + throw new NotSupportedException ("RemoveAt is not supported for property to property binding"); + } + + public override void ResumeBinding () + { + } + + public override void SuspendBinding () + { + } + + internal override bool IsSuspended { + get { return data_source == null; } + } + + protected internal override string GetListName (ArrayList listAccessors) + { + return String.Empty; + } + + [MonoTODO ("Stub, does nothing")] + protected override void UpdateIsBinding () + { + } + + protected internal override void OnCurrentChanged (EventArgs ea) + { + PushData (); + + if (onCurrentChangedHandler != null) { + onCurrentChangedHandler (this, ea); + } + } + + protected override void OnCurrentItemChanged (EventArgs ea) + { + throw new NotImplementedException (); + } + } +} + diff --git a/source/ShiftUI/Internal/PropertySort.cs b/source/ShiftUI/Internal/PropertySort.cs new file mode 100644 index 0000000..30a9fa6 --- /dev/null +++ b/source/ShiftUI/Internal/PropertySort.cs @@ -0,0 +1,40 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jonathan Chambers (jonathan.chambers@ansys.com) +// + +// COMPLETE + +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ComVisible(true)] + public enum PropertySort + { + NoSort = 0, + Alphabetical = 1, + Categorized = 2, + CategorizedAlphabetical = 3 + } +} diff --git a/source/ShiftUI/Internal/PropertyTabChangedEventArgs.cs b/source/ShiftUI/Internal/PropertyTabChangedEventArgs.cs new file mode 100644 index 0000000..3fee1c3 --- /dev/null +++ b/source/ShiftUI/Internal/PropertyTabChangedEventArgs.cs @@ -0,0 +1,66 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jonathan Chambers (jonathan.chambers@ansys.com) +// + +// COMPLETE + +using System; +using System.Runtime.InteropServices; +using ShiftUI.Design; + +namespace ShiftUI +{ + [ComVisible(true)] + public class PropertyTabChangedEventArgs : EventArgs + { + #region Local Variables + private PropertyTab old_tab; + private PropertyTab new_tab; + #endregion // Local Variables + + #region Constructor + public PropertyTabChangedEventArgs ( PropertyTab oldTab , PropertyTab newTab ) + { + old_tab = oldTab; + new_tab = newTab; + } + #endregion // Constructor + + #region Public Instance Properties + public PropertyTab NewTab + { + get { + return new_tab; + } + } + + public PropertyTab OldTab + { + get { + return old_tab; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Internal/PropertyTabChangedEventHandler.cs b/source/ShiftUI/Internal/PropertyTabChangedEventHandler.cs new file mode 100644 index 0000000..498776f --- /dev/null +++ b/source/ShiftUI/Internal/PropertyTabChangedEventHandler.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jonathan Chambers (jonathan.chambers@ansys.com) +// + +// COMPLETE + +namespace ShiftUI +{ + public delegate void PropertyTabChangedEventHandler(object s, PropertyTabChangedEventArgs e); +} + + diff --git a/source/ShiftUI/Internal/PropertyValueChangedEventArgs.cs b/source/ShiftUI/Internal/PropertyValueChangedEventArgs.cs new file mode 100644 index 0000000..ac308af --- /dev/null +++ b/source/ShiftUI/Internal/PropertyValueChangedEventArgs.cs @@ -0,0 +1,66 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jonathan Chambers (jonathan.chambers@ansys.com) +// + +// COMPLETE + +using System; +using System.Runtime.InteropServices; +using ShiftUI.Design; + +namespace ShiftUI +{ + [ComVisible(true)] + public class PropertyValueChangedEventArgs : EventArgs + { + #region Local Variables + private GridItem changed_item; + private object old_value; + #endregion // Local Variables + + #region Constructors + public PropertyValueChangedEventArgs ( GridItem changedItem , object oldValue ) + { + changed_item = changedItem; + old_value = oldValue; + } + #endregion + + #region Public Instance Properties + public GridItem ChangedItem + { + get { + return changed_item; + } + } + + public object OldValue + { + get { + return old_value; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Internal/PropertyValueChangedEventHandler.cs b/source/ShiftUI/Internal/PropertyValueChangedEventHandler.cs new file mode 100644 index 0000000..3e76a86 --- /dev/null +++ b/source/ShiftUI/Internal/PropertyValueChangedEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jonathan Chambers (jonathan.chambers@ansys.com) +// + +// COMPLETE + +namespace ShiftUI +{ + public delegate void PropertyValueChangedEventHandler(object s, PropertyValueChangedEventArgs e); +} diff --git a/source/ShiftUI/Internal/RadioButtonRenderer.cs b/source/ShiftUI/Internal/RadioButtonRenderer.cs new file mode 100644 index 0000000..c08eb4f --- /dev/null +++ b/source/ShiftUI/Internal/RadioButtonRenderer.cs @@ -0,0 +1,182 @@ +// +// RadioButtonRenderer.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using ShiftUI.VisualStyles; +using System; + +namespace ShiftUI +{ + public sealed class RadioButtonRenderer + { + private static bool always_use_visual_styles = false; + + #region Private Constructor + private RadioButtonRenderer () { } + #endregion + + #region Public Static Methods + public static void DrawRadioButton (Graphics g, Point glyphLocation, RadioButtonState state) + { + DrawRadioButton (g, glyphLocation, Rectangle.Empty, String.Empty, null, TextFormatFlags.HorizontalCenter, null, Rectangle.Empty, false, state); + } + + public static void DrawRadioButton (Graphics g, Point glyphLocation, Rectangle textBounds, string radioButtonText, Font font, bool focused, RadioButtonState state) + { + DrawRadioButton (g, glyphLocation, textBounds, radioButtonText, font, TextFormatFlags.HorizontalCenter, null, Rectangle.Empty, focused, state); + } + + public static void DrawRadioButton (Graphics g, Point glyphLocation, Rectangle textBounds, string radioButtonText, Font font, TextFormatFlags flags, bool focused, RadioButtonState state) + { + DrawRadioButton (g, glyphLocation, textBounds, radioButtonText, font, flags, null, Rectangle.Empty, focused, state); + } + + public static void DrawRadioButton (Graphics g, Point glyphLocation, Rectangle textBounds, string radioButtonText, Font font, Image image, Rectangle imageBounds, bool focused, RadioButtonState state) + { + DrawRadioButton (g, glyphLocation, textBounds, radioButtonText, font, TextFormatFlags.HorizontalCenter, image, imageBounds, focused, state); + } + + public static void DrawRadioButton (Graphics g, Point glyphLocation, Rectangle textBounds, string radioButtonText, Font font, TextFormatFlags flags, Image image, Rectangle imageBounds, bool focused, RadioButtonState state) + { + Rectangle bounds = new Rectangle (glyphLocation, GetGlyphSize (g, state)); + + if (Application.RenderWithVisualStyles || always_use_visual_styles == true) { + VisualStyleRenderer vsr = GetRadioButtonRenderer (state); + + vsr.DrawBackground (g, bounds); + + if (image != null) + vsr.DrawImage (g, imageBounds, image); + + if (focused) + WidgetPaint.DrawFocusRectangle (g, textBounds); + + if (radioButtonText != String.Empty) + if (state == RadioButtonState.CheckedDisabled || state == RadioButtonState.UncheckedDisabled) + TextRenderer.DrawText (g, radioButtonText, font, textBounds, SystemColors.GrayText, flags); + else + TextRenderer.DrawText (g, radioButtonText, font, textBounds, SystemColors.ControlText, flags); + } + else { + switch (state) { + case RadioButtonState.CheckedDisabled: + WidgetPaint.DrawRadioButton (g, bounds, ButtonState.Inactive | ButtonState.Checked); + break; + case RadioButtonState.CheckedHot: + case RadioButtonState.CheckedNormal: + WidgetPaint.DrawRadioButton (g, bounds, ButtonState.Checked); + break; + case RadioButtonState.CheckedPressed: + WidgetPaint.DrawRadioButton (g, bounds, ButtonState.Pushed | ButtonState.Checked); + break; + case RadioButtonState.UncheckedDisabled: + case RadioButtonState.UncheckedPressed: + WidgetPaint.DrawRadioButton (g, bounds, ButtonState.Inactive); + break; + case RadioButtonState.UncheckedHot: + case RadioButtonState.UncheckedNormal: + WidgetPaint.DrawRadioButton (g, bounds, ButtonState.Normal); + break; + } + + if (image != null) + g.DrawImage (image, imageBounds); + + if (focused) + WidgetPaint.DrawFocusRectangle (g, textBounds); + + if (radioButtonText != String.Empty) + TextRenderer.DrawText (g, radioButtonText, font, textBounds, SystemColors.ControlText, flags); + } + + } + + public static bool IsBackgroundPartiallyTransparent (RadioButtonState state) + { + if (!VisualStyleRenderer.IsSupported) + return false; + + VisualStyleRenderer vsr = GetRadioButtonRenderer (state); + + return vsr.IsBackgroundPartiallyTransparent (); + } + + public static void DrawParentBackground (Graphics g, Rectangle bounds, Widget childControl) + { + if (!VisualStyleRenderer.IsSupported) + return; + + VisualStyleRenderer vsr = new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.UncheckedNormal); + + vsr.DrawParentBackground (g, bounds, childControl); + } + + public static Size GetGlyphSize (Graphics g, RadioButtonState state) + { + if (!VisualStyleRenderer.IsSupported) + return new Size (13, 13); + + VisualStyleRenderer vsr = GetRadioButtonRenderer(state); + + return vsr.GetPartSize (g, ThemeSizeType.Draw); + } + #endregion + + #region Private Static Methods + private static VisualStyleRenderer GetRadioButtonRenderer (RadioButtonState state) + { + switch (state) { + case RadioButtonState.CheckedDisabled: + return new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.CheckedDisabled); + case RadioButtonState.CheckedHot: + return new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.CheckedHot); + case RadioButtonState.CheckedNormal: + return new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.CheckedNormal); + case RadioButtonState.CheckedPressed: + return new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.CheckedPressed); + case RadioButtonState.UncheckedDisabled: + return new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.UncheckedDisabled); + case RadioButtonState.UncheckedHot: + return new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.UncheckedHot); + case RadioButtonState.UncheckedNormal: + default: + return new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.UncheckedNormal); + case RadioButtonState.UncheckedPressed: + return new VisualStyleRenderer (VisualStyleElement.Button.RadioButton.UncheckedPressed); + } + } + #endregion + + #region Public Static Properties + public static bool RenderMatchingApplicationState { + get { return !always_use_visual_styles; } + set { always_use_visual_styles = !value; } + } + #endregion + } +} \ No newline at end of file diff --git a/source/ShiftUI/Internal/RelatedCurrencyManager.cs b/source/ShiftUI/Internal/RelatedCurrencyManager.cs new file mode 100644 index 0000000..2957db0 --- /dev/null +++ b/source/ShiftUI/Internal/RelatedCurrencyManager.cs @@ -0,0 +1,54 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Chris Toshok (toshok@ximian.com) +// + +using System; +using System.Data; +using System.Reflection; +using System.Collections; +using System.ComponentModel; + +namespace ShiftUI { + [DefaultMember("Item")] + internal class RelatedCurrencyManager : CurrencyManager { + + BindingManagerBase parent; + PropertyDescriptor prop_desc; + + public RelatedCurrencyManager (BindingManagerBase parent, PropertyDescriptor prop_desc) + : base (prop_desc.GetValue (parent.Current)) + { + this.parent = parent; + this.prop_desc = prop_desc; + + parent.PositionChanged += new EventHandler (parent_PositionChanged); + } + + private void parent_PositionChanged (object sender, EventArgs args) + { + SetDataSource (prop_desc.GetValue (parent.Current)); + } + } +} + diff --git a/source/ShiftUI/Internal/RelatedImageListAttribute.cs b/source/ShiftUI/Internal/RelatedImageListAttribute.cs new file mode 100644 index 0000000..4c3af82 --- /dev/null +++ b/source/ShiftUI/Internal/RelatedImageListAttribute.cs @@ -0,0 +1,48 @@ +// +// RelatedImageListAttribute.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Author: +// Jonathan Pobst (monkey@jpobst.com) + + +using System; +using ShiftUI; + +namespace ShiftUI +{ + [AttributeUsageAttribute (AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public sealed class RelatedImageListAttribute : Attribute + { + private string related_image_list; + + public RelatedImageListAttribute (string relatedImageList) + { + this.related_image_list = relatedImageList; + } + + public string RelatedImageList { + get { return this.related_image_list; } + } + } +} diff --git a/source/ShiftUI/Internal/RelatedPropertyManager.cs b/source/ShiftUI/Internal/RelatedPropertyManager.cs new file mode 100644 index 0000000..0ba4834 --- /dev/null +++ b/source/ShiftUI/Internal/RelatedPropertyManager.cs @@ -0,0 +1,67 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Chris Toshok + +using System; +using System.Collections; +using System.ComponentModel; + +namespace ShiftUI { + + internal class RelatedPropertyManager : PropertyManager { + + BindingManagerBase parent; + + public RelatedPropertyManager (BindingManagerBase parent, string property_name) + { + this.parent = parent; + this.property_name = property_name; + + if (parent.Position != -1) + SetDataSource (parent.Current); + parent.PositionChanged += new EventHandler (parent_PositionChanged); + } + + void parent_PositionChanged (object sender, EventArgs args) + { + if (parent.Position == -1) { + SetDataSource (null); + } + else { + SetDataSource (parent.Current); + } + + OnCurrentChanged (EventArgs.Empty); + } + + public override PropertyDescriptorCollection GetItemProperties () + { + PropertyDescriptor property = parent.GetItemProperties ().Find (property_name, true); + + // We can't just pass property.PropertyType, since the actual object could implement + // more elements and not only those described in the property type + return TypeDescriptor.GetProperties (property.GetValue (parent.Current)); + } + } +} + diff --git a/source/ShiftUI/Internal/RichTextBoxFinds.cs b/source/ShiftUI/Internal/RichTextBoxFinds.cs new file mode 100644 index 0000000..28cd616 --- /dev/null +++ b/source/ShiftUI/Internal/RichTextBoxFinds.cs @@ -0,0 +1,39 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok +// +// + +// COMPLETE +using System; + +namespace ShiftUI { + [Flags] + public enum RichTextBoxFinds { + None = 0x00000000, + WholeWord = 0x00000002, + MatchCase = 0x00000004, + NoHighlight = 0x00000008, + Reverse = 0x00000010, + } +} diff --git a/source/ShiftUI/Internal/RichTextBoxScrollBars.cs b/source/ShiftUI/Internal/RichTextBoxScrollBars.cs new file mode 100644 index 0000000..b155f53 --- /dev/null +++ b/source/ShiftUI/Internal/RichTextBoxScrollBars.cs @@ -0,0 +1,39 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok +// +// + +// COMPLETE + +namespace ShiftUI { + public enum RichTextBoxScrollBars { + None = 0, + Horizontal = 1, + Vertical = 2, + Both = 3, + ForcedHorizontal= 17, + ForcedVertical = 18, + ForcedBoth = 19 + } +} diff --git a/source/ShiftUI/Internal/SUI_NOTES.txt b/source/ShiftUI/Internal/SUI_NOTES.txt new file mode 100644 index 0000000..96350b0 --- /dev/null +++ b/source/ShiftUI/Internal/SUI_NOTES.txt @@ -0,0 +1,3 @@ +The code found in this folder is from the Mono project. + +The Mono project can be found on Github at http://github.com/mono/mono. diff --git a/source/ShiftUI/Internal/Screen.cs b/source/ShiftUI/Internal/Screen.cs new file mode 100644 index 0000000..7da251f --- /dev/null +++ b/source/ShiftUI/Internal/Screen.cs @@ -0,0 +1,221 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +using System; +using System.Drawing; + +namespace ShiftUI { + public class Screen { + #region Local Variables + private static Screen[] all_screens; + private bool primary; + private Rectangle bounds; + private Rectangle workarea; + private string name; + private int bits_per_pixel; + #endregion // Local Variables + + #region Constructors + static Screen () + { + try { + all_screens = XplatUI.AllScreens; + } + catch (Exception e) { + Console.WriteLine ("{0} trying to get all screens: {1}", e.GetType (), e.Message); + } + + if (all_screens == null || all_screens.Length == 0) { + // just use a default one + all_screens = new[] { new Screen(true, "Mono MWF Primary Display", + XplatUI.VirtualScreen, XplatUI.WorkingArea) }; + } + } + + internal Screen() { + this.primary = true; + this.bounds = XplatUI.WorkingArea; + } + + internal Screen(bool primary, string name, Rectangle bounds, Rectangle workarea) { + this.primary = primary; + this.name = name; + this.bounds = bounds; + this.workarea = workarea; + this.bits_per_pixel = 32; + } + #endregion // Constructors + + #region Public Static Properties + public static Screen[] AllScreens { + get { + return all_screens; + } + } + + public static Screen PrimaryScreen { + get { + return all_screens[0]; + } + } + #endregion // Public Static Properties + + #region Public Instance Properties + [MonoTODO ("Stub, always returns 32")] + public int BitsPerPixel { + get { return bits_per_pixel; } + } + + public Rectangle Bounds { + get { + return this.bounds; + } + } + + public string DeviceName { + get { + return this.name; + } + } + + public bool Primary { + get { + return this.primary; + } + } + + public Rectangle WorkingArea { + get { + return this.workarea; + } + } + #endregion // Public Instance Properties + + #region Public Static Methods + public static Screen FromControl(Widget control) { + var point = control.Parent != null ? control.Parent.PointToScreen(control.Location) : control.Location; + return Screen.FromPoint(point); + } + + public static Screen FromHandle(IntPtr hwnd) { + Widget control; + + control = Widget.FromHandle(hwnd); + if (control != null) { + var point = control.Parent != null ? control.Parent.PointToScreen(control.Location) : control.Location; + return Screen.FromPoint(point); + } + return Screen.PrimaryScreen; + } + + public static Screen FromPoint(Point point) { + for (int i = 0; i < all_screens.Length; i++) { + if (all_screens[i].Bounds.Contains(point)) { + return all_screens[i]; + } + } + return Screen.PrimaryScreen; + } + + public static Screen FromRectangle(Rectangle rect) { + Screen bestScrn = null; + int closest = Int32.MaxValue; + foreach (Screen scrn in Screen.AllScreens) { + Rectangle rcBounds = scrn.Bounds; + int distance = 0; + if (rect.Left > rcBounds.Right) + distance += rect.Left - rcBounds.Right; + else if (rcBounds.Left > rect.Left) + distance += rcBounds.Left - rect.Left; + if (rcBounds.Left > rect.Right) + distance += rcBounds.Left - rect.Right; + else if (rect.Right > rcBounds.Right) + distance += rect.Right - rcBounds.Right; + if (rect.Top > rcBounds.Bottom) + distance += rect.Top - rcBounds.Bottom; + else if (rcBounds.Top > rect.Top) + distance += rcBounds.Top - rect.Top; + if (rcBounds.Top > rect.Bottom) + distance += rcBounds.Top - rect.Bottom; + else if (rect.Bottom > rcBounds.Bottom) + distance += rect.Bottom - rcBounds.Bottom; + if (distance < closest) { + bestScrn = scrn; + closest = distance; + } + } + return bestScrn; + } + + public static Rectangle GetBounds(Widget ctl) { + return Screen.FromControl(ctl).Bounds; + } + + public static Rectangle GetBounds(Point pt) { + return Screen.FromPoint(pt).Bounds; + } + + public static Rectangle GetBounds(Rectangle rect) { + return Screen.FromRectangle(rect).Bounds; + } + + public static Rectangle GetWorkingArea(Widget ctl) { + return Screen.FromControl(ctl).WorkingArea; + } + + public static Rectangle GetWorkingArea(Point pt) { + return Screen.FromPoint(pt).WorkingArea; + } + + public static Rectangle GetWorkingArea(Rectangle rect) { + return Screen.FromRectangle(rect).WorkingArea; + } + #endregion // Public Static Methods + + #region Public Instance Methods + public override bool Equals(object obj) { + if (obj is Screen) { + Screen s = (Screen)obj; + + if (name.Equals(s.name) && (primary == s.primary) && (bounds.Equals(s.Bounds)) && (workarea.Equals(s.workarea))) { + return true; + } + } + return false; + } + + public override int GetHashCode() { + return base.GetHashCode (); + } + + public override string ToString() { + return "Screen[Bounds={" + this.Bounds + "} WorkingArea={" + this.WorkingArea + "} Primary={" + this.Primary + "} DeviceName=" + this.DeviceName; + } + + + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Internal/ScrollProperties.cs b/source/ShiftUI/Internal/ScrollProperties.cs new file mode 100644 index 0000000..a5f59ee --- /dev/null +++ b/source/ShiftUI/Internal/ScrollProperties.cs @@ -0,0 +1,97 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Authors: +// Olivier Dufour olivier.duff@free.fr +// Jonathan Pobst monkey@jpobst.com +// + +using System.ComponentModel; + +namespace ShiftUI +{ + public abstract class ScrollProperties + { + #region Private Fields + private ScrollableWidget parentControl; + internal ScrollBar scroll_bar; + #endregion + + #region constructor + protected ScrollProperties (ScrollableWidget container) + { + parentControl = container; + } + #endregion + + #region Public Properties + [DefaultValue (true)] + public bool Enabled { + get { return scroll_bar.Enabled; } + set { scroll_bar.Enabled = value; } + } + + [DefaultValue (10)] + [RefreshProperties (RefreshProperties.Repaint)] + public int LargeChange { + get { return scroll_bar.LargeChange; } + set { scroll_bar.LargeChange = value; } + } + + [DefaultValue (100)] + [RefreshProperties (RefreshProperties.Repaint)] + public int Maximum { + get { return scroll_bar.Maximum; } + set { scroll_bar.Maximum = value; } + } + + [DefaultValue (0)] + [RefreshProperties (RefreshProperties.Repaint)] + public int Minimum { + get { return scroll_bar.Minimum; } + set { scroll_bar.Minimum = value; } + } + + [DefaultValue (1)] + public int SmallChange { + get { return scroll_bar.SmallChange; } + set { scroll_bar.SmallChange = value; } + } + + [DefaultValue (0)] + [BindableAttribute (true)] + public int Value { + get { return scroll_bar.Value; } + set { scroll_bar.Value = value; } + } + + [DefaultValue (false)] + public bool Visible { + get { return scroll_bar.Visible; } + set { scroll_bar.Visible = value; } + } + #endregion + + #region Protected Properties + protected ScrollableWidget ParentControl { + get { return parentControl; } + } + #endregion + } +} diff --git a/source/ShiftUI/Internal/SelectedGridItemChangedEventArgs.cs b/source/ShiftUI/Internal/SelectedGridItemChangedEventArgs.cs new file mode 100644 index 0000000..8a6149c --- /dev/null +++ b/source/ShiftUI/Internal/SelectedGridItemChangedEventArgs.cs @@ -0,0 +1,65 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jonathan Chambers (jonathan.chambers@ansys.com) +// + +// COMPLETE + +using System; +using ShiftUI.Design; + +namespace ShiftUI +{ + public class SelectedGridItemChangedEventArgs : EventArgs + { + #region Local Variables + private GridItem new_selection; + private GridItem old_selection; + #endregion + + #region Constructors + public SelectedGridItemChangedEventArgs ( GridItem oldSel , GridItem newSel ) + { + old_selection = oldSel; + new_selection = newSel; + } + #endregion // Constructors + + #region Public Instance Properties + public GridItem NewSelection + { + get { + return new_selection; + } + } + + public GridItem OldSelection + { + get { + return old_selection; + } + } + #endregion // Public Instance Properties + } +} + diff --git a/source/ShiftUI/Internal/SelectedGridItemChangedEventHandler.cs b/source/ShiftUI/Internal/SelectedGridItemChangedEventHandler.cs new file mode 100644 index 0000000..da69bf3 --- /dev/null +++ b/source/ShiftUI/Internal/SelectedGridItemChangedEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jonathan Chambers (jonathan.chambers@ansys.com) +// + +// COMPLETE + +namespace ShiftUI +{ + public delegate void SelectedGridItemChangedEventHandler(object sender, SelectedGridItemChangedEventArgs e); +} diff --git a/source/ShiftUI/Internal/SelectionRangeConverter.cs b/source/ShiftUI/Internal/SelectionRangeConverter.cs new file mode 100644 index 0000000..07f18ef --- /dev/null +++ b/source/ShiftUI/Internal/SelectionRangeConverter.cs @@ -0,0 +1,110 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +using System.ComponentModel; +using System.Globalization; +using System; + +namespace ShiftUI { + public class SelectionRangeConverter : TypeConverter { + #region Public Constructors + public SelectionRangeConverter() { + } + #endregion // Public Constructors + + #region Public Instance Methods + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { + if (sourceType == typeof(string)) { + return true; + } + return false; + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { + if (destinationType == typeof(string)) { + return true; + } + return false; + } + + public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) { + string[] parts; + DateTime start; + DateTime end; + + if ((value == null) || !(value is String)) { + return base.ConvertFrom (context, culture, value); + } + + if (culture == null) { + culture = CultureInfo.CurrentCulture; + } + + parts = ((string)value).Split(culture.TextInfo.ListSeparator.ToCharArray()); + + start = (DateTime)TypeDescriptor.GetConverter(typeof(DateTime)).ConvertFromString(context, culture, parts[0]); + end = (DateTime)TypeDescriptor.GetConverter(typeof(DateTime)).ConvertFromString(context, culture, parts[1]); + + return new SelectionRange(start, end); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) { + SelectionRange s; + + if ((value == null) || !(value is SelectionRange) || (destinationType != typeof(string))) { + return base.ConvertTo (context, culture, value, destinationType); + } + + if (culture == null) { + culture = CultureInfo.CurrentCulture; + } + + s = (SelectionRange)value; + + + return s.Start.ToShortDateString() + culture.TextInfo.ListSeparator + s.End.ToShortDateString(); + } + + public override object CreateInstance(ITypeDescriptorContext context, System.Collections.IDictionary propertyValues) { + return new SelectionRange((DateTime)propertyValues["Start"], (DateTime)propertyValues["End"]); + } + + public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) { + return true; + } + + public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) { + return TypeDescriptor.GetProperties(typeof(SelectionRange), attributes); + } + + public override bool GetPropertiesSupported(ITypeDescriptorContext context) { + return true; + } + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Internal/Splitter.cs b/source/ShiftUI/Internal/Splitter.cs new file mode 100644 index 0000000..761f6ee --- /dev/null +++ b/source/ShiftUI/Internal/Splitter.cs @@ -0,0 +1,707 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005-2008 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Dennis Bartok (pbartok@novell.com) +// Ivan N. Zlatev (contact i-nz.net) +// +// + +// COMPLETE + +#undef Debug + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace ShiftUI { + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [DefaultEvent("SplitterMoved")] + [Designer("ShiftUI.Design.SplitterDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [DefaultProperty("Dock")] + public class Splitter : Widget + { + #region Local Variables + static private Cursor splitter_ns; + static private Cursor splitter_we; + // XXX this "new" shouldn't be here. Widget shouldn't define border_style as internal. + new private BorderStyle border_style; + private int min_extra; + private int min_size; + private int max_size; + private int splitter_size; // Size (width or height) of our splitter control + private bool horizontal; // true if we've got a horizontal splitter + private Widget affected; // The control that the splitter resizes + private int split_requested; // If the user requests a position before we have ever laid out the doc + private int splitter_prev_move; + private Rectangle splitter_rectangle_moving; + private int moving_offset; + #endregion // Local Variables + + #region Constructors + static Splitter() { + splitter_ns = Cursors.HSplit; + splitter_we = Cursors.VSplit; + } + + public Splitter() { + + min_extra = 25; + min_size = 25; + split_requested = -1; + splitter_size = 3; + horizontal = false; + + SetStyle(Widgetstyles.Selectable, false); + Anchor = AnchorStyles.None; + Dock = DockStyle.Left; + + Layout += new LayoutEventHandler(LayoutSplitter); + this.ParentChanged += new EventHandler(ReparentSplitter); + Cursor = splitter_we; + } + #endregion // Constructors + + #region Public Instance Properties + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool AllowDrop { + get { + return base.AllowDrop; + } + + set { + base.AllowDrop = value; + } + } + + [Browsable(false)] + [DefaultValue(AnchorStyles.None)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override AnchorStyles Anchor { + get { + return AnchorStyles.None; + } + + set { + ; // MS doesn't set it + } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override Image BackgroundImage { + get { + return base.BackgroundImage; + } + + set { + base.BackgroundImage = value; + } + } + + [Browsable (false)] + [EditorBrowsable (EditorBrowsableState.Never)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + [DispId(-504)] + [DefaultValue (BorderStyle.None)] + [MWFDescription("Sets the border style for the splitter")] + [MWFCategory("Appearance")] + public BorderStyle BorderStyle { + get { + return border_style; + } + + set { + border_style = value; + + switch(value) { + case BorderStyle.FixedSingle: + splitter_size = 4; // We don't get motion events for 1px wide windows on X11. sigh. + break; + + case BorderStyle.Fixed3D: + value = BorderStyle.None; + splitter_size = 3; + break; + + case BorderStyle.None: + splitter_size = 3; + break; + + default: + throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for BorderStyle", value)); + } + + base.InternalBorderStyle = value; + } + } + + [DefaultValue(DockStyle.Left)] + [Localizable(true)] + public override DockStyle Dock { + get { + return base.Dock; + } + + set { + if (!Enum.IsDefined (typeof (DockStyle), value) || (value == DockStyle.None) || (value == DockStyle.Fill)) { + throw new ArgumentException("Splitter must be docked left, top, bottom or right"); + } + + if ((value == DockStyle.Top) || (value == DockStyle.Bottom)) { + horizontal = true; + Cursor = splitter_ns; + } else { + horizontal = false; + Cursor = splitter_we; + } + base.Dock = value; + } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override Font Font { + get { + return base.Font; + } + + set { + base.Font = value; + } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override Color ForeColor { + get { + return base.ForeColor; + } + + set { + base.ForeColor = value; + } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new ImeMode ImeMode { + get { + return base.ImeMode; + } + + set { + base.ImeMode = value; + } + } + + [DefaultValue(25)] + [Localizable(true)] + [MWFDescription("Sets minimum size of undocked window")] + [MWFCategory("Behaviour")] + public int MinExtra { + get { + return min_extra; + } + + set { + min_extra = value; + } + } + + [DefaultValue(25)] + [Localizable(true)] + [MWFDescription("Sets minimum size of the resized control")] + [MWFCategory("Behaviour")] + public int MinSize { + get { + return min_size; + } + + set { + min_size = value; + } + } + + internal int MaxSize { + get { + if (this.Parent == null) + return 0; + + if (affected == null) + affected = AffectedControl; + + int widths = 0; + int heights = 0; + int vert_offset = 0; + int horiz_offset = 0; + foreach (Widget c in this.Parent.Widgets) { + if (c != affected) { + switch (c.Dock) { + case DockStyle.Left: + case DockStyle.Right: + widths += c.Width; + + if (c.Location.X < this.Location.X) + vert_offset += c.Width; + break; + case DockStyle.Top: + case DockStyle.Bottom: + heights += c.Height; + + if (c.Location.Y < this.Location.Y) + horiz_offset += c.Height; + break; + } + } + } + + if (horizontal) { + moving_offset = horiz_offset; + + return Parent.ClientSize.Height - heights - MinExtra; + } else { + moving_offset = vert_offset; + + return Parent.ClientSize.Width - widths - MinExtra; + } + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [MWFDescription("Current splitter position")] + [MWFCategory("Layout")] + public int SplitPosition { + get { + affected = AffectedControl; + if (affected == null) { + return -1; + } + + if (Capture) { + return CalculateSplitPosition(); + } + + if (horizontal) { + return affected.Height; + } else { + return affected.Width; + } + } + + set { + if (value > MaxSize) + value = MaxSize; + if (value < MinSize) + value = MinSize; + + affected = AffectedControl; + if (affected == null) + split_requested = value; + else { + if (horizontal) + affected.Height = value; + else + affected.Width = value; + OnSplitterMoved (new SplitterEventArgs (Left, Top, value, value)); + } + } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new bool TabStop { + get { return base.TabStop; } + set { base.TabStop = value; } + } + + [Bindable(false)] + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override string Text { + get { + return base.Text; + } + + set { + base.Text = value; + } + } + + #endregion // Public Instance Properties + + #region Protected Instance Properties + protected override CreateParams CreateParams { + get { + return base.CreateParams; + } + } + + protected override Cursor DefaultCursor { + get { return base.DefaultCursor; } + } + + protected override ImeMode DefaultImeMode { + get { + return ImeMode.Disable; + } + } + + protected override Size DefaultSize { + get { + return new Size (3, 3); + } + } + #endregion // Protected Instance Properties + + #region Public Instance Methods + public override string ToString() { + return base.ToString () + String.Format(", MinExtra: {0}, MinSize: {1}", min_extra, min_size); + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + protected override void OnKeyDown(KeyEventArgs e) { + base.OnKeyDown (e); + if (Capture && (e.KeyCode == Keys.Escape)) { + Capture = false; + SplitterEndMove (Point.Empty, true); + } + } + + protected override void OnMouseDown(MouseEventArgs e) { + base.OnMouseDown (e); + + // Only allow if we are set up properly + if (affected == null) + affected = AffectedControl; + max_size = MaxSize; + + if (affected == null || e.Button != MouseButtons.Left) + return; + + Capture = true; + SplitterBeginMove (Parent.PointToClient (PointToScreen (new Point (e.X, e.Y)))); + } + + protected override void OnMouseMove (MouseEventArgs e) + { + base.OnMouseMove (e); + + if (!Capture || e.Button != MouseButtons.Left || affected == null) + return; + + // We need our mouse coordinates relative to our parent + SplitterMove (Parent.PointToClient (PointToScreen (e.Location))); + } + + protected override void OnMouseUp (MouseEventArgs e) + { + base.OnMouseUp (e); + if (!Capture || e.Button != MouseButtons.Left || affected == null) + return; + + SplitterEndMove (Parent.PointToClient (PointToScreen (e.Location)), false); + Capture = false; + } + + private void SplitterBeginMove (Point location) + { + splitter_rectangle_moving = new Rectangle (Bounds.X, Bounds.Y, + Width, Height); + splitter_prev_move = horizontal ? location.Y : location.X; + } + + private void SplitterMove (Point location) + { + int currentMove = horizontal ? location.Y : location.X; + int delta = currentMove - splitter_prev_move; + Rectangle prev_location = splitter_rectangle_moving; + bool moved = false; + int min = this.MinSize + moving_offset; + int max = max_size + moving_offset; + + if (horizontal) { + if (splitter_rectangle_moving.Y + delta > min && splitter_rectangle_moving.Y + delta < max) { + splitter_rectangle_moving.Y += delta; + moved = true; + } else { + // Ensure that the splitter is set to minimum or maximum position, + // even if the mouse "skips". + // + if (splitter_rectangle_moving.Y + delta <= min && splitter_rectangle_moving.Y != min) { + splitter_rectangle_moving.Y = min; + moved = true; + } else if (splitter_rectangle_moving.Y + delta >= max && splitter_rectangle_moving.Y != max) { + splitter_rectangle_moving.Y = max; + moved = true; + } + } + } else { + if (splitter_rectangle_moving.X + delta > min && splitter_rectangle_moving.X + delta < max) { + splitter_rectangle_moving.X += delta; + moved = true; + } else { + // Ensure that the splitter is set to minimum or maximum position, + // even if the mouse "skips". + // + if (splitter_rectangle_moving.X + delta <= min && splitter_rectangle_moving.X != min) { + splitter_rectangle_moving.X = min; + moved = true; + } else if (splitter_rectangle_moving.X + delta >= max && splitter_rectangle_moving.X != max) { + splitter_rectangle_moving.X = max; + moved = true; + } + } + } + + if (moved) { + splitter_prev_move = currentMove; + OnSplitterMoving (new SplitterEventArgs (location.X, location.Y, + splitter_rectangle_moving.X, + splitter_rectangle_moving.Y)); + XplatUI.DrawReversibleRectangle (this.Parent.Handle, prev_location, 1); + XplatUI.DrawReversibleRectangle (this.Parent.Handle, splitter_rectangle_moving, 1); + } + } + + private void SplitterEndMove (Point location, bool cancel) + { + if (!cancel) { + // Resize the affected window + if (horizontal) + affected.Height = CalculateSplitPosition(); + else + affected.Width = CalculateSplitPosition(); + } + + this.Parent.Refresh (); // to clean up the drag handle artifacts from all Widgets + SplitterEventArgs args = new SplitterEventArgs (location.X, location.Y, + splitter_rectangle_moving.X, + splitter_rectangle_moving.Y); + OnSplitterMoved (args); + } + + protected virtual void OnSplitterMoved(SplitterEventArgs sevent) { + SplitterEventHandler eh = (SplitterEventHandler)(Events [SplitterMovedEvent]); + if (eh != null) + eh (this, sevent); + } + + protected virtual void OnSplitterMoving(SplitterEventArgs sevent) { + SplitterEventHandler eh = (SplitterEventHandler)(Events [SplitterMovingEvent]); + if (eh != null) + eh (this, sevent); + } + + protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) { + // enforce our width / height + if (horizontal) { + splitter_size = height; + if (splitter_size < 1) { + splitter_size = 3; + } + base.SetBoundsCore (x, y, width, splitter_size, specified); + } else { + splitter_size = width; + if (splitter_size < 1) { + splitter_size = 3; + } + base.SetBoundsCore (x, y, splitter_size, height, specified); + } + } + #endregion // Protected Instance Methods + + #region Private Properties and Methods + private Widget AffectedControl { + get { + if (Parent == null) + return null; + + // Doc says the first control preceeding us in the zorder + for (int i = Parent.Widgets.GetChildIndex(this) + 1; i < Parent.Widgets.Count; i++) { + switch (Dock) { + case DockStyle.Top: + if (Top == Parent.Widgets[i].Bottom) + return Parent.Widgets[i]; + break; + case DockStyle.Bottom: + if (Bottom == Parent.Widgets[i].Top) + return Parent.Widgets[i]; + break; + case DockStyle.Left: + if (Left == Parent.Widgets[i].Right) + return Parent.Widgets[i]; + break; + case DockStyle.Right: + if (Right == Parent.Widgets[i].Left) + return Parent.Widgets[i]; + break; + } + } + return null; + } + } + + private int CalculateSplitPosition() { + if (horizontal) { + if (Dock == DockStyle.Top) + return splitter_rectangle_moving.Y - affected.Top; + else + return affected.Bottom - splitter_rectangle_moving.Y - splitter_size; + } else { + if (Dock == DockStyle.Left) + return splitter_rectangle_moving.X - affected.Left; + else + return affected.Right - splitter_rectangle_moving.X - splitter_size; + } + } + + internal override void OnPaintInternal (PaintEventArgs e) { + e.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(this.BackColor), e.ClipRectangle); + } + + private void LayoutSplitter(object sender, LayoutEventArgs e) { + affected = AffectedControl; + if (split_requested != -1) { + SplitPosition = split_requested; + split_requested = -1; + } + } + + private void ReparentSplitter(object sender, EventArgs e) { + affected = null; + } + + #endregion // Private Properties and Methods + + #region Events + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageChanged { + add { base.BackgroundImageChanged += value; } + remove { base.BackgroundImageChanged -= value; } + } + + [Browsable (false)] + [EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageLayoutChanged + { + add { base.BackgroundImageLayoutChanged += value; } + remove { base.BackgroundImageLayoutChanged -= value; } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler Enter { + add { base.Enter += value; } + remove { base.Enter -= value; } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler FontChanged { + add { base.FontChanged += value; } + remove { base.FontChanged -= value; } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler ForeColorChanged { + add { base.ForeColorChanged += value; } + remove { base.ForeColorChanged -= value; } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler ImeModeChanged { + add { base.ImeModeChanged += value; } + remove { base.ImeModeChanged -= value; } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event KeyEventHandler KeyDown { + add { base.KeyDown += value; } + remove { base.KeyDown -= value; } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event KeyPressEventHandler KeyPress { + add { base.KeyPress += value; } + remove { base.KeyPress -= value; } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event KeyEventHandler KeyUp { + add { base.KeyUp += value; } + remove { base.KeyUp -= value; } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler Leave { + add { base.Leave += value; } + remove { base.Leave -= value; } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler TabStopChanged { + add { base.TabStopChanged += value; } + remove { base.TabStopChanged -= value; } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + + static object SplitterMovedEvent = new object (); + static object SplitterMovingEvent = new object (); + + public event SplitterEventHandler SplitterMoved { + add { Events.AddHandler (SplitterMovedEvent, value); } + remove { Events.RemoveHandler (SplitterMovedEvent, value); } + } + + public event SplitterEventHandler SplitterMoving { + add { Events.AddHandler (SplitterMovingEvent, value); } + remove { Events.RemoveHandler (SplitterMovingEvent, value); } + } + #endregion // Events + } +} diff --git a/source/ShiftUI/Internal/Structs.cs b/source/ShiftUI/Internal/Structs.cs new file mode 100644 index 0000000..087964d --- /dev/null +++ b/source/ShiftUI/Internal/Structs.cs @@ -0,0 +1,157 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software",, to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Geoff Norton +// + +using System; + +namespace ShiftUI.CarbonInternal { + internal struct CGSize { + public float width; + public float height; + + public CGSize (int w, int h) { + this.width = (float)w; + this.height = (float)h; + } + } + + internal struct QDPoint { + public short y; + public short x; + + public QDPoint (short x, short y) { + this.x = x; + this.y = y; + } + } + + internal struct CGPoint { + public float x; + public float y; + + public CGPoint (int x, int y) { + this.x = (float)x; + this.y = (float)y; + } + } + + internal struct HIRect { + public CGPoint origin; + public CGSize size; + + public HIRect (int x, int y, int w, int h) { + this.origin = new CGPoint (x, y); + this.size = new CGSize (w, h); + } + } + + internal struct HIViewID { + public uint type; + public uint id; + + public HIViewID (uint type, uint id) { + this.type = type; + this.id = id; + } + } + + internal struct EventTypeSpec { + public UInt32 eventClass; + public UInt32 eventKind; + + public EventTypeSpec (UInt32 eventClass, UInt32 eventKind) + { + this.eventClass = eventClass; + this.eventKind = eventKind; + } + } + + internal struct CarbonEvent { + public IntPtr hWnd; + public IntPtr evt; + + public CarbonEvent (IntPtr hWnd, IntPtr evt) + { + this.hWnd = hWnd; + this.evt = evt; + } + } + + internal struct RGBColor { + public short red; + public short green; + public short blue; + } + + internal struct Rect { + public short top; + public short left; + public short bottom; + public short right; + } + + internal struct Caret { + internal Timer Timer; + internal IntPtr Hwnd; + internal int X; + internal int Y; + internal int Width; + internal int Height; + internal int Visible; + internal bool On; + internal bool Paused; + } + + internal struct Hover { + internal Timer Timer; + internal IntPtr Hwnd; + internal int X; + internal int Y; + internal int Interval; + } + + internal struct CGAffineTransform { + internal float a; + internal float b; + internal float c; + internal float d; + internal float tx; + internal float ty; + } + + internal struct MouseTrackingRegionID { + public uint signature; + public uint id; + + public MouseTrackingRegionID (uint signature, uint id) { + this.signature = signature; + this.id = id; + } + } + + internal struct ProcessSerialNumber { + public ulong highLongOfPSN; + public ulong lowLongOfPSN; + } +} diff --git a/source/ShiftUI/Internal/SystemInformation.cs b/source/ShiftUI/Internal/SystemInformation.cs new file mode 100644 index 0000000..a27f039 --- /dev/null +++ b/source/ShiftUI/Internal/SystemInformation.cs @@ -0,0 +1,611 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004,2006 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Miguel de Icaza (miguel@novell.com). +// Peter Bartok (pbartok@novell.com) +// + +// NOT COMPLETE + +using System; +using System.Drawing; +using System.ComponentModel; + +namespace ShiftUI +{ + public class SystemInformation + { + private SystemInformation () + { + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static int ActiveWindowTrackingDelay { get { return XplatUI.ActiveWindowTrackingDelay; } } + + public static ArrangeDirection ArrangeDirection { + get { + return ThemeEngine.Current.ArrangeDirection; + } + } + + public static ArrangeStartingPosition ArrangeStartingPosition { + get { + return ThemeEngine.Current.ArrangeStartingPosition; + } + } + + public static BootMode BootMode { + get { + return BootMode.Normal; + } + } + + public static Size Border3DSize { + get { + return ThemeEngine.Current.Border3DSize; + } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static int BorderMultiplierFactor { get { return ThemeEngine.Current.BorderMultiplierFactor; } } + + public static Size BorderSize { + get { + return ThemeEngine.Current.BorderSize; + } + } + + public static Size CaptionButtonSize { + get { + return ThemeEngine.Current.CaptionButtonSize; + } + } + + public static int CaptionHeight { + get { + return ThemeEngine.Current.CaptionHeight; + } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static int CaretBlinkTime { get { return XplatUI.CaretBlinkTime; } } + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static int CaretWidth { get { return XplatUI.CaretWidth; } } + + public static string ComputerName { + get { + return Environment.MachineName; + } + } + + public static Size CursorSize { + get { + return XplatUI.CursorSize; + } + } + + public static bool DbcsEnabled { + get { + return false; + } + } + + public static bool DebugOS { + get { + return false; + } + } + + public static Size DoubleClickSize { + get { + return ThemeEngine.Current.DoubleClickSize; + } + } + + public static int DoubleClickTime { + get { + return ThemeEngine.Current.DoubleClickTime; + } + } + + public static bool DragFullWindows { + get { + return XplatUI.DragFullWindows; + } + } + + public static Size DragSize { + get { + return XplatUI.DragSize; + } + } + + public static Size FixedFrameBorderSize { + get { + return ThemeEngine.Current.FixedFrameBorderSize; + } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static int FontSmoothingContrast { get { return XplatUI.FontSmoothingContrast; } } + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static int FontSmoothingType { get { return XplatUI.FontSmoothingType; } } + + public static Size FrameBorderSize { + get { + return ThemeEngine.Current.FrameBorderSize; + } + } + + public static bool HighContrast { + get { + return false; + } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static int HorizontalFocusThickness { get { return ThemeEngine.Current.HorizontalFocusThickness; } } + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static int HorizontalResizeBorderThickness { get { return XplatUI.HorizontalResizeBorderThickness; } } + + public static int HorizontalScrollBarArrowWidth { + get { + return ThemeEngine.Current.HorizontalScrollBarArrowWidth; + } + } + + public static int HorizontalScrollBarHeight { + get { + return ThemeEngine.Current.HorizontalScrollBarHeight; + } + } + + public static int HorizontalScrollBarThumbWidth { + get { + return ThemeEngine.Current.HorizontalScrollBarThumbWidth; + } + } + + public static Size IconSize { + get { + return XplatUI.IconSize; + } + } + + public static int IconHorizontalSpacing { + get { + return IconSpacingSize.Width; + } + } + + public static int IconVerticalSpacing { + get { + return IconSpacingSize.Height; + } + } + + public static Size IconSpacingSize { + get { + return ThemeEngine.Current.IconSpacingSize; + } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static bool IsActiveWindowTrackingEnabled { + get { return XplatUI.IsActiveWindowTrackingEnabled; } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static bool IsComboBoxAnimationEnabled { + get { return XplatUI.IsComboBoxAnimationEnabled; } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static bool IsDropShadowEnabled { + get { return XplatUI.IsDropShadowEnabled; } + } + + public static bool IsFlatMenuEnabled { + get { return false; } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static bool IsFontSmoothingEnabled { + get { return XplatUI.IsFontSmoothingEnabled; } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static bool IsHotTrackingEnabled { + get { return XplatUI.IsHotTrackingEnabled; } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static bool IsIconTitleWrappingEnabled { + get { return XplatUI.IsIconTitleWrappingEnabled; } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static bool IsKeyboardPreferred { + get { return XplatUI.IsKeyboardPreferred; } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static bool IsListBoxSmoothScrollingEnabled { + get { return XplatUI.IsListBoxSmoothScrollingEnabled; } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static bool IsMenuAnimationEnabled { + get { return XplatUI.IsMenuAnimationEnabled; } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static bool IsMenuFadeEnabled { + get { return XplatUI.IsMenuFadeEnabled; } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static bool IsMinimizeRestoreAnimationEnabled { + get { return XplatUI.IsMinimizeRestoreAnimationEnabled; } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static bool IsSelectionFadeEnabled { + get { return XplatUI.IsSelectionFadeEnabled; } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static bool IsSnapToDefaultEnabled { + get { return XplatUI.IsSnapToDefaultEnabled; } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static bool IsTitleBarGradientEnabled { + get { return XplatUI.IsTitleBarGradientEnabled; } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static bool IsToolTipAnimationEnabled { + get { return XplatUI.IsToolTipAnimationEnabled; } + } + + public static int KanjiWindowHeight { + get { + return 0; + } + } + + public static int KeyboardDelay { + get { + return XplatUI.KeyboardDelay; + } + } + + public static int KeyboardSpeed { + get { + return XplatUI.KeyboardSpeed; + } + } + + public static Size MaxWindowTrackSize { + get { + return XplatUI.MaxWindowTrackSize; + } + } + + public static bool MenuAccessKeysUnderlined { + get { + return ThemeEngine.Current.MenuAccessKeysUnderlined; + } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static Size MenuBarButtonSize { + get { return ThemeEngine.Current.MenuBarButtonSize; } + } + + public static Size MenuButtonSize { + get { + return ThemeEngine.Current.MenuButtonSize; + } + } + + public static Size MenuCheckSize { + get { + return ThemeEngine.Current.MenuCheckSize; + } + } + + public static Font MenuFont { + get { + // note: we MUST return a clone of the Font instance as anyone + // can dispose it. However we shouldn't expect the theme to do + // the cloning for performance reason + return (Font) ThemeEngine.Current.MenuFont.Clone (); + } + } + + public static int MenuHeight { + get { + return ThemeEngine.Current.MenuHeight; + } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static int MenuShowDelay { get { return XplatUI.MenuShowDelay; } } + + public static bool MidEastEnabled { + get { + return false; // ??? how do we decide? + } + } + + public static Size MinimizedWindowSize { + get { + return XplatUI.MinimizedWindowSize; + } + } + + public static Size MinimizedWindowSpacingSize { + get { + return XplatUI.MinimizedWindowSpacingSize; + } + } + + public static Size MinimumWindowSize { + get { + return XplatUI.MinimumWindowSize; + } + } + + public static Size MinWindowTrackSize { + get { + return XplatUI.MinWindowTrackSize; + } + } + + public static int MonitorCount { + get { + return Screen.AllScreens.Length; + } + } + + public static bool MonitorsSameDisplayFormat { + get { + return true; + } + } + + public static int MouseButtons { + get { + return XplatUI.MouseButtonCount; + } + } + + public static bool MouseButtonsSwapped { + get { + return XplatUI.MouseButtonsSwapped; + } + } + + public static Size MouseHoverSize { + get { + return XplatUI.MouseHoverSize; + } + } + + public static int MouseHoverTime { + get { + return XplatUI.MouseHoverTime; + } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static int MouseSpeed { + get { return XplatUI.MouseSpeed; } + } + + public static int MouseWheelScrollDelta { + get { + return XplatUI.MouseWheelScrollDelta; + } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public static bool MousePresent { + get { + return true; + } + } + + public static bool MouseWheelPresent { + get { + return XplatUI.MouseWheelPresent; + } + } + + public static int MouseWheelScrollLines { + get { + return ThemeEngine.Current.MouseWheelScrollLines; + } + } + + public static bool NativeMouseWheelSupport { + get { + return MouseWheelPresent; + } + } + + public static bool Network { + get { + return true; + } + } + + public static bool PenWindows { + get { + return false; + } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static LeftRightAlignment PopupMenuAlignment { + get { return XplatUI.PopupMenuAlignment; } + } + + [MonoTODO ("Only implemented for Win32.")] + public static PowerStatus PowerStatus { + get { return XplatUI.PowerStatus; } + } + + public static Size PrimaryMonitorMaximizedWindowSize { + get { + var workingArea = Screen.PrimaryScreen.WorkingArea; + return new Size (workingArea.Width, workingArea.Height); + } + } + + public static Size PrimaryMonitorSize { + get { + var bounds = Screen.PrimaryScreen.Bounds; + return new Size (bounds.Width, bounds.Height); + } + } + + public static bool RightAlignedMenus { + get { + return ThemeEngine.Current.RightAlignedMenus; + } + } + + public static ScreenOrientation ScreenOrientation { + get { return ScreenOrientation.Angle0; } + } + + public static bool Secure { + get { + return true; + } + } + + public static bool ShowSounds { + get { + return false; + } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static int SizingBorderWidth { + get { return XplatUI.SizingBorderWidth; } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static Size SmallCaptionButtonSize { + get { return XplatUI.SmallCaptionButtonSize; } + } + + public static Size SmallIconSize { + get { + return XplatUI.SmallIconSize; + } + } + + public static bool TerminalServerSession { + get { + return false; + } + } + + public static Size ToolWindowCaptionButtonSize { + get { + return ThemeEngine.Current.ToolWindowCaptionButtonSize; + } + } + + public static int ToolWindowCaptionHeight { + get { + return ThemeEngine.Current.ToolWindowCaptionHeight; + } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static bool UIEffectsEnabled { + get { return XplatUI.UIEffectsEnabled; } + } + + public static string UserDomainName { + get { + return Environment.UserDomainName; + } + } + + public static bool UserInteractive { + get { + return Environment.UserInteractive; + } + } + + public static string UserName { + get { + return Environment.UserName; + } + } + + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static int VerticalFocusThickness { get { return ThemeEngine.Current.VerticalFocusThickness; } } + [MonoInternalNote ("Determine if we need an X11 implementation or if defaults are good.")] + public static int VerticalResizeBorderThickness { get { return XplatUI.VerticalResizeBorderThickness; } } + + public static int VerticalScrollBarArrowHeight { + get { + return ThemeEngine.Current.VerticalScrollBarArrowHeight; + } + } + + public static int VerticalScrollBarThumbHeight { + get { + return ThemeEngine.Current.VerticalScrollBarThumbHeight; + } + } + + public static int VerticalScrollBarWidth { + get { + return ThemeEngine.Current.VerticalScrollBarWidth; + } + } + + public static Rectangle VirtualScreen { + get { + var rect = new Rectangle (); + foreach (var screen in Screen.AllScreens) + rect = Rectangle.Union (rect, screen.Bounds); + return rect; + } + } + + public static Rectangle WorkingArea { + get { + return Screen.PrimaryScreen.WorkingArea; + } + } + } +} diff --git a/source/ShiftUI/Internal/SystemParameter.cs b/source/ShiftUI/Internal/SystemParameter.cs new file mode 100644 index 0000000..fd4f7c1 --- /dev/null +++ b/source/ShiftUI/Internal/SystemParameter.cs @@ -0,0 +1,49 @@ +// +// SystemParameter.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ComVisible(true)] + public enum SystemParameter + { + DropShadow = 0, + FlatMenu = 1, + FontSmoothingContrastMetric = 2, + FontSmoothingTypeMetric = 3, + MenuFadeEnabled = 4, + SelectionFade = 5, + ToolTipAnimationMetric = 6, + UIEffects = 7, + CaretWidthMetric = 8, + VerticalFocusThicknessMetric = 9, + HorizontalFocusThicknessMetric = 10 + } +} diff --git a/source/ShiftUI/Internal/TableLayout.cs b/source/ShiftUI/Internal/TableLayout.cs new file mode 100644 index 0000000..f32ca96 --- /dev/null +++ b/source/ShiftUI/Internal/TableLayout.cs @@ -0,0 +1,603 @@ +// +// TableLayout.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +#undef TABLE_DEBUG + +using System; +using System.Drawing; + +namespace ShiftUI.Layout +{ + internal class TableLayout : LayoutEngine + { + private static Widget dummy_Widget = new Widget ("Dummy"); // Used as a placeholder for row/col spans + + public TableLayout () : base () + { + } + + public override void InitLayout (object child, BoundsSpecified specified) + { + base.InitLayout (child, specified); + } + + // There are 3 steps to doing a table layout: + // 1) Figure out which row/column each Widget goes into + // 2) Figure out the sizes of each row/column + // 3) Size and position each Widget + public override bool Layout (object container, LayoutEventArgs args) + { + TableLayoutPanel panel = container as TableLayoutPanel; + TableLayoutSettings settings = panel.LayoutSettings; + +#if TABLE_DEBUG + Console.WriteLine ("Beginning layout on panel: {0}, Widget count: {1}, col/row count: {2}x{3}", panel.Name, panel.Widgets.Count, settings.ColumnCount, settings.RowCount); +#endif + + // STEP 1: + // - Figure out which row/column each Widget goes into + // - Store data in the TableLayoutPanel.actual_positions + panel.actual_positions = CalculateWidgetPositions (panel, Math.Max (settings.ColumnCount, 1), Math.Max (settings.RowCount, 1)); + + // STEP 2: + // - Figure out the sizes of each row/column + // - Store data in the TableLayoutPanel.widths/heights + CalculateColumnRowSizes (panel, panel.actual_positions.GetLength (0), panel.actual_positions.GetLength (1)); + + // STEP 3: + // - Size and position each Widget + LayoutWidgets(panel); + +#if TABLE_DEBUG + Console.WriteLine ("-- CalculatedPositions:"); + OutputWidgetGrid (panel.actual_positions, panel); + + Console.WriteLine ("Finished layout on panel: {0}", panel.Name); + Console.WriteLine (); +#endif + + return false; + } + + internal Widget[,] CalculateWidgetPositions (TableLayoutPanel panel, int columns, int rows) + { + Widget[,] grid = new Widget[columns, rows]; + + TableLayoutSettings settings = panel.LayoutSettings; + + // First place all Widgets that have an explicit col/row + foreach (Widget c in panel.Widgets) { + int col = settings.GetColumn (c); + int row = settings.GetRow (c); + if (col >= 0 && row >= 0) { + if (col >= columns) + return CalculateWidgetPositions (panel, col + 1, rows); + if (row >= rows) + return CalculateWidgetPositions (panel, columns, row + 1); + + if (grid[col, row] == null) { + int col_span = Math.Min (settings.GetColumnSpan (c), columns); + int row_span = Math.Min (settings.GetRowSpan (c), rows); + + if (col + col_span > columns) { + if (row + 1 < rows) { + grid[col, row] = dummy_Widget; + row++; + col = 0; + } + else if (settings.GrowStyle == TableLayoutPanelGrowStyle.AddColumns) + return CalculateWidgetPositions (panel, columns + 1, rows); + else + throw new ArgumentException (); + } + + if (row + row_span > rows) { + if (settings.GrowStyle == TableLayoutPanelGrowStyle.AddRows) + return CalculateWidgetPositions (panel, columns, rows + 1); + else + throw new ArgumentException (); + } + + grid[col, row] = c; + + // Fill in the rest of this Widget's row/column extent with dummy + // Widgets, so that other Widgets don't get put there. + for (int i = 0; i < col_span; i++) + for (int j = 0; j < row_span; j++) + if (i != 0 || j != 0) + grid[col + i, row + j] = dummy_Widget; + } + } + } + + int x_pointer = 0; + int y_pointer = 0; + + // Fill in gaps with Widgets that do not have an explicit col/row + foreach (Widget c in panel.Widgets) { + int col = settings.GetColumn (c); + int row = settings.GetRow (c); + + if ((col >= 0 && col < columns) && (row >= 0 && row < rows) && (grid[col, row] == c || grid[col, row] == dummy_Widget)) + continue; + + for (int y = y_pointer; y < rows; y++) { + y_pointer = y; + x_pointer = 0; + + for (int x = x_pointer; x < columns; x++) { + x_pointer = x; + + if (grid[x, y] == null) { + int col_span = Math.Min (settings.GetColumnSpan (c), columns); + int row_span = Math.Min (settings.GetRowSpan (c), rows); + + if (x + col_span > columns) { + if (y + 1 < rows) + break; + else if (settings.GrowStyle == TableLayoutPanelGrowStyle.AddColumns) + return CalculateWidgetPositions (panel, columns + 1, rows); + else + throw new ArgumentException (); + } + + if (y + row_span > rows) { + if (x + 1 < columns) + break; + else if (settings.GrowStyle == TableLayoutPanelGrowStyle.AddRows) + return CalculateWidgetPositions (panel, columns, rows + 1); + else + throw new ArgumentException (); + } + + grid[x, y] = c; + + // Fill in the rest of this Widget's row/column extent with dummy + // Widgets, so that other Widgets don't get put there. + for (int i = 0; i < col_span; i++) + for (int j = 0; j < row_span; j++) + if (i != 0 || j != 0) + grid[x + i, y + j] = dummy_Widget; + + // I know someone will kill me for using a goto, but + // sometimes they really are the easiest way... + goto Found; + } else { + // MS adds the Widgets only to the first row if + // GrowStyle is AddColumns and RowCount is 0, + // so interrupt the search for a free horizontal cell + // beyond the first one in the given vertical + if (settings.GrowStyle == TableLayoutPanelGrowStyle.AddColumns && + settings.RowCount == 0) + break; + } + } + } + + // MS adds rows instead of columns even when GrowStyle is AddColumns, + // but RowCount is 0. + TableLayoutPanelGrowStyle adjustedGrowStyle = settings.GrowStyle; + if (settings.GrowStyle == TableLayoutPanelGrowStyle.AddColumns) { + if (settings.RowCount == 0) + adjustedGrowStyle = TableLayoutPanelGrowStyle.AddRows; + } + + switch (adjustedGrowStyle) { + case TableLayoutPanelGrowStyle.AddColumns: + return CalculateWidgetPositions (panel, columns + 1, rows); + case TableLayoutPanelGrowStyle.AddRows: + default: + return CalculateWidgetPositions (panel, columns, rows + 1); + case TableLayoutPanelGrowStyle.FixedSize: + throw new ArgumentException (); + } + + Found: ; + } + + return grid; + } + + private void CalculateColumnRowSizes (TableLayoutPanel panel, int columns, int rows) + { + TableLayoutSettings settings = panel.LayoutSettings; + + panel.column_widths = new int[panel.actual_positions.GetLength (0)]; + panel.row_heights = new int[panel.actual_positions.GetLength (1)]; + + int border_width = TableLayoutPanel.GetCellBorderWidth (panel.CellBorderStyle); + + Rectangle parentDisplayRectangle = panel.DisplayRectangle; + + TableLayoutColumnStyleCollection col_styles = new TableLayoutColumnStyleCollection (panel); + + foreach (ColumnStyle cs in settings.ColumnStyles) + col_styles.Add( new ColumnStyle(cs.SizeType, cs.Width)); + + TableLayoutRowStyleCollection row_styles = new TableLayoutRowStyleCollection (panel); + + foreach (RowStyle rs in settings.RowStyles) + row_styles.Add (new RowStyle (rs.SizeType, rs.Height)); + + // If we have more columns than columnstyles, temporarily add enough columnstyles + if (columns > col_styles.Count) + { + for (int i = col_styles.Count; i < columns; i++) + col_styles.Add(new ColumnStyle()); + } + + // Same for rows.. + if (rows > row_styles.Count) + { + for (int i = row_styles.Count; i < rows; i++) + row_styles.Add (new RowStyle ()); + } + + while (row_styles.Count > rows) + row_styles.RemoveAt (row_styles.Count - 1); + while (col_styles.Count > columns) + col_styles.RemoveAt (col_styles.Count - 1); + + // Find the largest column-span/row-span values. + int max_colspan = 0, max_rowspan = 0; + foreach (Widget c in panel.Widgets) { + max_colspan = Math.Max (max_colspan, settings.GetColumnSpan (c)); + max_rowspan = Math.Max (max_rowspan, settings.GetRowSpan (c)); + } + + // Figure up all the column widths + int total_width = parentDisplayRectangle.Width - (border_width * (columns + 1)); + int index = 0; + + // First assign all the Absolute sized columns.. + foreach (ColumnStyle cs in col_styles) { + if (cs.SizeType == SizeType.Absolute) { + panel.column_widths[index] = (int)cs.Width; + total_width -= (int)cs.Width; + } + + index++; + } + + // Next, assign all the AutoSize columns to the width of their widest + // Widget. If the table-layout is auto-sized, then make sure that + // no column with Percent styling clips its contents. + // (per http://msdn.microsoft.com/en-us/library/ms171690.aspx) + for (int colspan = 0; colspan < max_colspan; ++colspan) + { + for (index = colspan; index < col_styles.Count - colspan; ++index) + { + ColumnStyle cs = col_styles[index]; + if (cs.SizeType == SizeType.AutoSize + || (panel.AutoSize && cs.SizeType == SizeType.Percent)) + { + int max_width = panel.column_widths[index]; + + // Find the widest Widget in the column + for (int i = 0; i < rows; i ++) + { + Widget c = panel.actual_positions[index - colspan, i]; + + if (c != null && c != dummy_Widget && c.VisibleInternal) + { + // Skip any Widgets not being sized in this pass. + if (settings.GetColumnSpan (c) != colspan + 1) + continue; + + // Calculate the maximum Widget width. + if (c.AutoSize) + max_width = Math.Max (max_width, c.PreferredSize.Width + c.Margin.Horizontal); + else + max_width = Math.Max (max_width, c.ExplicitBounds.Width + c.Margin.Horizontal); + max_width = Math.Max (max_width, c.Width + c.Margin.Left + c.Margin.Right); + } + } + + // Subtract the width of prior columns, if any. + for (int i = Math.Max (index - colspan, 0); i < index; ++i) + max_width -= panel.column_widths[i]; + + // If necessary, increase this column's width. + if (max_width > panel.column_widths[index]) + { + max_width -= panel.column_widths[index]; + panel.column_widths[index] += max_width; + total_width -= max_width; + } + } + } + } + + index = 0; + float total_percent = 0; + + // Finally, assign the remaining space to Percent columns, if any. + if (total_width > 0) + { + int percent_width = total_width; + + // Find the total percent (not always 100%) + foreach (ColumnStyle cs in col_styles) + { + if (cs.SizeType == SizeType.Percent) + total_percent += cs.Width; + } + + // Divvy up the space.. + foreach (ColumnStyle cs in col_styles) + { + if (cs.SizeType == SizeType.Percent) + { + int width_change = (int)(((cs.Width / total_percent) * percent_width) + - panel.column_widths[index]); + if (width_change > 0) + { + panel.column_widths[index] += width_change; + total_width -= width_change; + } + } + + index++; + } + } + + if (total_width > 0) + { + // Find the last column that isn't an Absolute SizeType, and give it + // all this free space. (Absolute sized columns need to retain their + // absolute width if at all possible!) + int col = col_styles.Count - 1; + for (; col >= 0; --col) + { + if (col_styles[col].SizeType != SizeType.Absolute) + break; + } + if (col < 0) + col = col_styles.Count - 1; + panel.column_widths[col] += total_width; + } + + // Figure up all the row heights + int total_height = parentDisplayRectangle.Height - (border_width * (rows + 1)); + index = 0; + + // First assign all the Absolute sized rows.. + foreach (RowStyle rs in row_styles) { + if (rs.SizeType == SizeType.Absolute) { + panel.row_heights[index] = (int)rs.Height; + total_height -= (int)rs.Height; + } + + index++; + } + + index = 0; + + // Next, assign all the AutoSize rows to the height of their tallest + // Widget. If the table-layout is auto-sized, then make sure that + // no row with Percent styling clips its contents. + // (per http://msdn.microsoft.com/en-us/library/ms171690.aspx) + for (int rowspan = 0; rowspan < max_rowspan; ++rowspan) + { + for (index = rowspan; index < row_styles.Count - rowspan; ++index) + { + RowStyle rs = row_styles[index]; + if (rs.SizeType == SizeType.AutoSize + || (panel.AutoSize && rs.SizeType == SizeType.Percent)) + { + int max_height = panel.row_heights[index]; + + // Find the tallest Widget in the row + for (int i = 0; i < columns; i++) { + Widget c = panel.actual_positions[i, index - rowspan]; + + if (c != null && c != dummy_Widget && c.VisibleInternal) + { + // Skip any Widgets not being sized in this pass. + if (settings.GetRowSpan (c) != rowspan + 1) + continue; + + // Calculate the maximum Widget height. + if (c.AutoSize) + max_height = Math.Max (max_height, c.PreferredSize.Height + c.Margin.Vertical); + else + max_height = Math.Max (max_height, c.ExplicitBounds.Height + c.Margin.Vertical); + max_height = Math.Max (max_height, c.Height + c.Margin.Top + c.Margin.Bottom); + } + } + + // Subtract the height of prior rows, if any. + for (int i = Math.Max (index - rowspan, 0); i < index; ++i) + max_height -= panel.row_heights[i]; + + // If necessary, increase this row's height. + if (max_height > panel.row_heights[index]) + { + max_height -= panel.row_heights[index]; + panel.row_heights[index] += max_height; + total_height -= max_height; + } + } + } + } + + index = 0; + total_percent = 0; + + // Finally, assign the remaining space to Percent rows, if any. + if (total_height > 0) { + int percent_height = total_height; + + // Find the total percent (not always 100%) + foreach (RowStyle rs in row_styles) { + if (rs.SizeType == SizeType.Percent) + total_percent += rs.Height; + } + + // Divvy up the space.. + foreach (RowStyle rs in row_styles) { + if (rs.SizeType == SizeType.Percent) { + int height_change = (int)(((rs.Height / total_percent) * percent_height) + - panel.row_heights[index]); + if (height_change > 0) + { + panel.row_heights[index] += height_change; + total_height -= height_change; + } + } + + index++; + } + } + + if (total_height > 0) + { + // Find the last row that isn't an Absolute SizeType, and give it + // all this free space. (Absolute sized rows need to retain their + // absolute height if at all possible!) + int row = row_styles.Count - 1; + for (; row >= 0; --row) + { + if (row_styles[row].SizeType != SizeType.Absolute) + break; + } + if (row < 0) + row = row_styles.Count - 1; + panel.row_heights[row] += total_height; + } + } + + private void LayoutWidgets (TableLayoutPanel panel) + { + TableLayoutSettings settings = panel.LayoutSettings; + + int border_width = TableLayoutPanel.GetCellBorderWidth (panel.CellBorderStyle); + + int columns = panel.actual_positions.GetLength(0); + int rows = panel.actual_positions.GetLength(1); + + Point current_pos = new Point (panel.DisplayRectangle.Left + border_width, panel.DisplayRectangle.Top + border_width); + + for (int y = 0; y < rows; y++) + { + for (int x = 0; x < columns; x++) + { + Widget c = panel.actual_positions[x,y]; + + if(c != null && c != dummy_Widget) { + Size preferred; + + if (c.AutoSize) + preferred = c.PreferredSize; + else + preferred = c.ExplicitBounds.Size; + + int new_x = 0; + int new_y = 0; + int new_width = 0; + int new_height = 0; + + // Figure out the width of the Widget + int column_width = panel.column_widths[x]; + + for (int i = 1; i < Math.Min (settings.GetColumnSpan(c), panel.column_widths.Length); i++) + column_width += panel.column_widths[x + i]; + + if (c.Dock == DockStyle.Fill || c.Dock == DockStyle.Top || c.Dock == DockStyle.Bottom || ((c.Anchor & AnchorStyles.Left) == AnchorStyles.Left && (c.Anchor & AnchorStyles.Right) == AnchorStyles.Right)) + new_width = column_width - c.Margin.Left - c.Margin.Right; + else + new_width = Math.Min (preferred.Width, column_width - c.Margin.Left - c.Margin.Right); + + // Figure out the height of the Widget + int column_height = panel.row_heights[y]; + + for (int i = 1; i < Math.Min (settings.GetRowSpan (c), panel.row_heights.Length); i++) + column_height += panel.row_heights[y + i]; + + if (c.Dock == DockStyle.Fill || c.Dock == DockStyle.Left || c.Dock == DockStyle.Right || ((c.Anchor & AnchorStyles.Top) == AnchorStyles.Top && (c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom)) + new_height = column_height - c.Margin.Top - c.Margin.Bottom; + else + new_height = Math.Min (preferred.Height, column_height - c.Margin.Top - c.Margin.Bottom); + + // Figure out the left location of the Widget + if (c.Dock == DockStyle.Left || c.Dock == DockStyle.Fill || (c.Anchor & AnchorStyles.Left) == AnchorStyles.Left) + new_x = current_pos.X + c.Margin.Left; + else if (c.Dock == DockStyle.Right || (c.Anchor & AnchorStyles.Right) == AnchorStyles.Right) + new_x = (current_pos.X + column_width) - new_width - c.Margin.Right; + else // (center Widget) + new_x = (current_pos.X + (column_width - c.Margin.Left - c.Margin.Right) / 2) + c.Margin.Left - (new_width / 2); + + // Figure out the top location of the Widget + if (c.Dock == DockStyle.Top || c.Dock == DockStyle.Fill || (c.Anchor & AnchorStyles.Top) == AnchorStyles.Top) + new_y = current_pos.Y + c.Margin.Top; + else if (c.Dock == DockStyle.Bottom || (c.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom) + new_y = (current_pos.Y + column_height) - new_height - c.Margin.Bottom; + else // (center Widget) + new_y = (current_pos.Y + (column_height - c.Margin.Top - c.Margin.Bottom) / 2) + c.Margin.Top - (new_height / 2); + + c.SetBoundsInternal (new_x, new_y, new_width, new_height, BoundsSpecified.None); + } + + current_pos.Offset (panel.column_widths[x] + border_width, 0); + } + + current_pos.Offset ((-1 * current_pos.X) + border_width + panel.DisplayRectangle.Left, panel.row_heights[y] + border_width); + } + } + +#if TABLE_DEBUG + private void OutputWidgetGrid (Widget[,] grid, TableLayoutPanel panel) + { + Console.WriteLine (" Size: {0}x{1}", grid.GetLength (0), grid.GetLength (1)); + + Console.Write (" "); + + foreach (int i in panel.column_widths) + Console.Write (" {0}px ", i.ToString ().PadLeft (3)); + + Console.WriteLine (); + + for (int y = 0; y < grid.GetLength (1); y++) { + Console.Write (" {0}px |", panel.row_heights[y].ToString ().PadLeft (3)); + + for (int x = 0; x < grid.GetLength (0); x++) { + if (grid[x, y] == null) + Console.Write (" --- |"); + else if (string.IsNullOrEmpty (grid[x, y].Name)) + Console.Write (" ??? |"); + else + Console.Write (" {0} |", grid[x, y].Name.PadRight (5).Substring (0, 5)); + } + + Console.WriteLine (); + } + } +#endif + } +} diff --git a/source/ShiftUI/Internal/TableLayoutSettings.cs b/source/ShiftUI/Internal/TableLayoutSettings.cs new file mode 100644 index 0000000..786a98b --- /dev/null +++ b/source/ShiftUI/Internal/TableLayoutSettings.cs @@ -0,0 +1,362 @@ +// +// TableLayoutSettings.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.ComponentModel; +using System.Collections.Generic; +using ShiftUI.Layout; +using System.Runtime.Serialization; + +namespace ShiftUI +{ + [Serializable] + [TypeConverter (typeof (TableLayoutSettingsTypeConverter))] + public sealed class TableLayoutSettings : LayoutSettings, ISerializable + { + private TableLayoutColumnStyleCollection column_styles; + private TableLayoutRowStyleCollection row_styles; + private TableLayoutPanelGrowStyle grow_style; + private int column_count; + private int row_count; + private Dictionary columns; + private Dictionary column_spans; + private Dictionary rows; + private Dictionary row_spans; + internal TableLayoutPanel panel; + internal bool isSerialized; + + #region Internal Constructor + internal TableLayoutSettings (TableLayoutPanel panel) + { + this.column_styles = new TableLayoutColumnStyleCollection (panel); + this.row_styles = new TableLayoutRowStyleCollection (panel); + this.grow_style = TableLayoutPanelGrowStyle.AddRows; + this.column_count = 0; + this.row_count = 0; + this.columns = new Dictionary (); + this.column_spans = new Dictionary (); + this.rows = new Dictionary (); + this.row_spans = new Dictionary (); + this.panel = panel; + } + + private TableLayoutSettings (SerializationInfo serializationInfo, StreamingContext context) + { + TypeConverter converter = TypeDescriptor.GetConverter (this); + string text = serializationInfo.GetString ("SerializedString"); + if (!string.IsNullOrEmpty (text) && (converter != null)) { + TableLayoutSettings settings = converter.ConvertFromInvariantString (text) as TableLayoutSettings; + this.column_styles = settings.column_styles; + this.row_styles = settings.row_styles; + this.grow_style = settings.grow_style; + this.column_count = settings.column_count; + this.row_count = settings.row_count; + this.columns = settings.columns; + this.column_spans = settings.column_spans; + this.rows = settings.rows; + this.row_spans = settings.row_spans; + this.panel = settings.panel; + this.isSerialized = true; + } + } + #endregion + + #region Public Properties + [DefaultValue (0)] + public int ColumnCount { + get { return this.column_count; } + set { + if (value < 0) + throw new ArgumentOutOfRangeException(); + + if (column_count != value) { + column_count = value; + if (panel != null) + panel.PerformLayout (panel, "ColumnCount"); + } + } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + public TableLayoutColumnStyleCollection ColumnStyles { + get { return this.column_styles; } + } + + [DefaultValue (TableLayoutPanelGrowStyle.AddRows)] + public TableLayoutPanelGrowStyle GrowStyle { + get { return this.grow_style; } + set { + if (!Enum.IsDefined (typeof(TableLayoutPanelGrowStyle), value)) + throw new ArgumentException(); + + if (grow_style != value) { + grow_style = value; + if (panel != null) + panel.PerformLayout (panel, "GrowStyle"); + } + } + } + + public override LayoutEngine LayoutEngine { + get { + if (panel != null) + return panel.LayoutEngine; + return base.LayoutEngine; + } + } + + [DefaultValue (0)] + public int RowCount { + get { return this.row_count; } + set { + if (value < 0) + throw new ArgumentOutOfRangeException (); + + if (row_count != value) { + row_count = value; + + if (panel != null) + panel.PerformLayout (); + } + } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + public TableLayoutRowStyleCollection RowStyles { + get { return row_styles; } + } + #endregion + + #region Public Methods + [DefaultValue (-1)] + public TableLayoutPanelCellPosition GetCellPosition (Object control) + { + if (control == null) + throw new ArgumentNullException (); + + int column; + int row; + + if (!columns.TryGetValue (control, out column)) + { + if (!(control is Widget) || !columns.TryGetValue ((control as Widget).Name, out column)) + column = -1; + } + if (!rows.TryGetValue (control, out row)) + { + if (!(control is Widget) || !rows.TryGetValue ((control as Widget), out row)) + row = -1; + } + + return new TableLayoutPanelCellPosition (column, row); + } + + [DefaultValue (-1)] + public int GetColumn (Object control) + { + if (control == null) + throw new ArgumentNullException (); + + int retval; + + if (columns.TryGetValue (control, out retval)) + return retval; + if ((control is Widget) && columns.TryGetValue ((control as Widget).Name, out retval)) + return retval; + + return -1; + } + + public int GetColumnSpan (Object control) + { + if (control == null) + throw new ArgumentNullException (); + + int retval; + + if (column_spans.TryGetValue (control, out retval)) + return retval; + if ((control is Widget) && column_spans.TryGetValue ((control as Widget).Name, out retval)) + return retval; + + return 1; + } + + [DefaultValue (-1)] + public int GetRow (Object control) + { + if (control == null) + throw new ArgumentNullException (); + + int retval; + + if (rows.TryGetValue (control, out retval)) + return retval; + if ((control is Widget) && rows.TryGetValue ((control as Widget).Name, out retval)) + return retval; + + return -1; + } + + public int GetRowSpan (Object control) + { + if (control == null) + throw new ArgumentNullException (); + + int retval; + + if (row_spans.TryGetValue (control, out retval)) + return retval; + if ((control is Widget) && row_spans.TryGetValue ((control as Widget).Name, out retval)) + return retval; + + return 1; + } + + [DefaultValue (-1)] + public void SetCellPosition (Object control, TableLayoutPanelCellPosition cellPosition) + { + if (control == null) + throw new ArgumentNullException (); + + columns[control] = cellPosition.Column; + rows[control] = cellPosition.Row; + + if (panel != null) + panel.PerformLayout (); + } + + public void SetColumn (Object control, int column) + { + if (control == null) + throw new ArgumentNullException (); + if (column < -1) + throw new ArgumentException (); + + columns[control] = column; + + if (panel != null) + panel.PerformLayout (); + } + + public void SetColumnSpan (Object control, int value) + { + if (control == null) + throw new ArgumentNullException (); + if (value < -1) + throw new ArgumentException (); + + column_spans[control] = value; + + if (panel != null) + panel.PerformLayout (); + } + + public void SetRow (Object control, int row) + { + if (control == null) + throw new ArgumentNullException (); + if (row < -1) + throw new ArgumentException (); + + rows[control] = row; + + if (panel != null) + panel.PerformLayout (); + } + + public void SetRowSpan (Object control, int value) + { + if (control == null) + throw new ArgumentNullException (); + if (value < -1) + throw new ArgumentException (); + + row_spans[control] = value; + + if (panel != null) + panel.PerformLayout (); + } + #endregion + + #region Internal Methods + internal List GetWidgets () + { + List list = new List(); + foreach (KeyValuePair control in columns) { + WidgetInfo info = new WidgetInfo(); + info.Widget = control.Key; + info.Col = GetColumn(control.Key); + info.ColSpan = GetColumnSpan (control.Key); + info.Row = GetRow (control.Key); + info.RowSpan = GetRowSpan (control.Key); + list.Add (info); + } + return list; + } + + #endregion + + #region ISerializable Members + void ISerializable.GetObjectData (SerializationInfo si, StreamingContext context) + { + TableLayoutSettingsTypeConverter conv = new TableLayoutSettingsTypeConverter (); + string text = conv.ConvertToInvariantString (this); + si.AddValue ("SerializedString", text); + } + #endregion + + internal class StyleConverter : TypeConverter + { + public override object ConvertFrom (ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + { + if ((value == null) || !(value is String)) + return base.ConvertFrom (context, culture, value); + + return Enum.Parse (typeof (StyleConverter), (string)value, true); + } + + public override object ConvertTo (ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if ((value == null) || !(value is StyleConverter) || (destinationType != typeof (string))) + return base.ConvertTo (context, culture, value, destinationType); + + return ((StyleConverter)value).ToString (); + } + } + } + + internal struct WidgetInfo + { + public object Widget; + public int Row; + public int RowSpan; + public int Col; + public int ColSpan; + } +} diff --git a/source/ShiftUI/Internal/TableLayoutSettingsTypeConverter.cs b/source/ShiftUI/Internal/TableLayoutSettingsTypeConverter.cs new file mode 100644 index 0000000..d9396b9 --- /dev/null +++ b/source/ShiftUI/Internal/TableLayoutSettingsTypeConverter.cs @@ -0,0 +1,233 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// + + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Globalization; +using System.Xml; +using System.IO; +using System.Collections.Generic; + +namespace ShiftUI.Layout +{ + public class TableLayoutSettingsTypeConverter : TypeConverter + { + public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof (string)) + return true; + + return base.CanConvertTo (context, destinationType); + } + + public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + return true; + + return base.CanConvertFrom (context, sourceType); + } + + + + public override object ConvertTo (ITypeDescriptorContext context, + CultureInfo culture, + object value, + Type destinationType) + { + if (!(value is TableLayoutSettings) || destinationType != typeof (string)) + return base.ConvertTo (context, culture, value, destinationType); + + TableLayoutSettings settings = value as TableLayoutSettings; + StringWriter sw = new StringWriter (); + XmlTextWriter xw = new XmlTextWriter (sw); + xw.WriteStartDocument (); + List list = settings.GetWidgets (); + xw.WriteStartElement ("TableLayoutSettings"); + xw.WriteStartElement ("Widgets"); + + foreach (WidgetInfo info in list) { + xw.WriteStartElement ("Widget"); + xw.WriteAttributeString ("Name", info.Widget.ToString ()); + xw.WriteAttributeString ("Row", info.Row.ToString ()); + xw.WriteAttributeString ("RowSpan", info.RowSpan.ToString ()); + xw.WriteAttributeString ("Column", info.Col.ToString ()); + xw.WriteAttributeString ("ColumnSpan", info.ColSpan.ToString ()); + xw.WriteEndElement (); + } + xw.WriteEndElement (); + + + List styles = new List (); + + foreach (ColumnStyle style in settings.ColumnStyles) { + styles.Add (style.SizeType.ToString ()); + styles.Add (style.Width.ToString (CultureInfo.InvariantCulture)); + } + + + xw.WriteStartElement ("Columns"); + xw.WriteAttributeString ("Styles", String.Join (",", styles.ToArray ())); + xw.WriteEndElement (); + + styles.Clear(); + foreach (RowStyle style in settings.RowStyles) { + styles.Add (style.SizeType.ToString ()); + styles.Add (style.Height.ToString (CultureInfo.InvariantCulture)); + } + + xw.WriteStartElement ("Rows"); + xw.WriteAttributeString ("Styles", String.Join (",", styles.ToArray ())); + xw.WriteEndElement (); + + xw.WriteEndElement (); + xw.WriteEndDocument (); + xw.Close (); + + return sw.ToString (); + + } + + public override object ConvertFrom (ITypeDescriptorContext context, + CultureInfo culture, + object value) + { + if (!(value is string)) + return base.ConvertFrom(context, culture, value); + + XmlDocument xmldoc = new XmlDocument(); + xmldoc.LoadXml (value as string); + TableLayoutSettings settings = new TableLayoutSettings(new TableLayoutPanel()); + int count = ParseWidget (xmldoc, settings); + ParseColumnStyle (xmldoc, settings); + ParseRowStyle (xmldoc, settings); + settings.RowCount = count; + + + return settings; + } + + + private int ParseWidget (XmlDocument xmldoc, TableLayoutSettings settings) + { + int count = 0; + foreach (XmlNode node in xmldoc.GetElementsByTagName ("Widget")) { + if (node.Attributes["Name"] == null || string.IsNullOrEmpty(node.Attributes["Name"].Value)) + continue; + if (node.Attributes["Row"] != null) { + settings.SetRow (node.Attributes["Name"].Value, GetValue (node.Attributes["Row"].Value)); + count++; + } + if (node.Attributes["RowSpan"] != null) { + settings.SetRowSpan (node.Attributes["Name"].Value, GetValue (node.Attributes["RowSpan"].Value)); + } + if (node.Attributes["Column"] != null) + settings.SetColumn (node.Attributes["Name"].Value, GetValue (node.Attributes["Column"].Value)); + if (node.Attributes["ColumnSpan"] != null) + settings.SetColumnSpan (node.Attributes["Name"].Value, GetValue (node.Attributes["ColumnSpan"].Value)); + } + return count; + } + + private void ParseColumnStyle (XmlDocument xmldoc, TableLayoutSettings settings) + { + foreach (XmlNode node in xmldoc.GetElementsByTagName ("Columns")) { + if (node.Attributes["Styles"] == null) + continue; + string styles = node.Attributes["Styles"].Value; + if (string.IsNullOrEmpty (styles)) + continue; + string[] list = BuggySplit (styles); + for (int i = 0; i < list.Length; i+=2) { + float width = 0f; + SizeType type = (SizeType) Enum.Parse (typeof (SizeType), list[i]); + float.TryParse (list[i+1], NumberStyles.Float, CultureInfo.InvariantCulture, out width); + settings.ColumnStyles.Add (new ColumnStyle (type, width)); + } + } + } + + private void ParseRowStyle (XmlDocument xmldoc, TableLayoutSettings settings) + { + foreach (XmlNode node in xmldoc.GetElementsByTagName ("Rows")) { + if (node.Attributes["Styles"] == null) + continue; + string styles = node.Attributes["Styles"].Value; + if (string.IsNullOrEmpty(styles)) + continue; + string[] list = BuggySplit (styles); + for (int i = 0; i < list.Length; i += 2) { + float height = 0f; + SizeType type = (SizeType) Enum.Parse (typeof (SizeType), list[i]); + float.TryParse (list[i + 1], NumberStyles.Float, CultureInfo.InvariantCulture, out height); + settings.RowStyles.Add (new RowStyle (type, height)); + } + } + } + + private int GetValue (string attValue) + { + int val = -1; + if (!string.IsNullOrEmpty (attValue)) { + int.TryParse (attValue, out val); + } + return val; + } + + // .Net accidently uses the local culture separator, so + // Percent,50.0,Percent,50.0 can be + // Percent,50,0,Percent,50,0 + // Make sure we can handle this + private string[] BuggySplit (string s) + { + List l = new List (); + + string[] split = s.Split (','); + + for (int i = 0; i < split.Length; i++) { + switch (split[i].ToLowerInvariant ()) { + case "autosize": + case "absolute": + case "percent": + l.Add (split[i]); + break; + default: + if (i + 1 < split.Length) { + float test; + + if (float.TryParse (split[i + 1], out test)) { + l.Add (string.Format ("{0}.{1}", split[i], split[i + 1])); + i++; + } else + l.Add (split[i]); + } else + l.Add (split[i]); + break; + } + } + + return l.ToArray (); + } + } +} diff --git a/source/ShiftUI/Internal/TextBoxTextRenderer.cs b/source/ShiftUI/Internal/TextBoxTextRenderer.cs new file mode 100644 index 0000000..3e908f3 --- /dev/null +++ b/source/ShiftUI/Internal/TextBoxTextRenderer.cs @@ -0,0 +1,131 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Jonathan Pobst monkey@jpobst.com +// +// + +using System; +using System.Drawing; +using System.Drawing.Text; +using System.Text; +using System.Collections; + +namespace ShiftUI +{ + internal class TextBoxTextRenderer + { + private static Size max_size; + private static bool use_textrenderer; + private static StringFormat sf_nonprinting; + private static StringFormat sf_printing; + private static Hashtable measure_cache; + + static TextBoxTextRenderer () + { + // On Windows, we want to use TextRenderer (GDI) + // On Linux, we want to use DrawString (GDI+) + // TextRenderer provides translation from TextRenderer to + // DrawString, but I doubt it's exact enough. + // Another option would be to put Pango here for Linux. + int platform = (int)Environment.OSVersion.Platform; + + if (platform == 4 || platform == 128 || platform == 6) + use_textrenderer = false; + else + use_textrenderer = true; + + // windows 2000 doesn't draw with gdi if bounds are In32.MaxValue + max_size = new Size (Int16.MaxValue, Int16.MaxValue); + + sf_nonprinting = new StringFormat (StringFormat.GenericTypographic); + sf_nonprinting.Trimming = StringTrimming.None; + sf_nonprinting.FormatFlags = StringFormatFlags.DisplayFormatControl; + sf_nonprinting.HotkeyPrefix = HotkeyPrefix.None; + + sf_printing = StringFormat.GenericTypographic; + sf_printing.HotkeyPrefix = HotkeyPrefix.None; + + measure_cache = new Hashtable (); + } + + public static void DrawText (Graphics g, string text, Font font, Color color, float x, float y, bool showNonPrint) + { + if (!use_textrenderer) { + if (showNonPrint) + g.DrawString (text, font, ThemeEngine.Current.ResPool.GetSolidBrush (color), x, y, sf_nonprinting); + else + g.DrawString (text, font, ThemeEngine.Current.ResPool.GetSolidBrush (color), x, y, sf_printing); + } else { + if (showNonPrint) + TextRenderer.DrawTextInternal (g, text, font, new Rectangle (new Point ((int)x, (int)y), max_size), color, TextFormatFlags.NoPadding | TextFormatFlags.NoPrefix, false); + else + TextRenderer.DrawTextInternal (g, text, font, new Rectangle (new Point ((int)x, (int)y), max_size), color, TextFormatFlags.NoPadding | TextFormatFlags.NoPrefix, false); + } + } + + public static SizeF MeasureText (Graphics g, string text, Font font) + { + // Due to the way the TextBox currently works, it measures each + // character one at a time. And it does this alot. So here we + // are implementing a cache for each font/character combination + // measurement. Since the number of fonts and number of characters + // used tends to be small, this is a good performance gain for + // not too much memory. + if (text.Length == 1) { + // If g.VisibleClipBounds is {X=0, Y=0, Width=1, Height=1}, then some characters + // (in some fonts for some point sizes) return a different width then when the + // VisibleClipBounds has a different (usually but not always more reasonable) value. + // This state of the Graphics object can occur during initialization of text boxes + // with preset Text values. See https://bugzilla.xamarin.com/show_bug.cgi?id=26258 + // for more details. + string sep; + var bounds = g.VisibleClipBounds; + if (bounds.Width == 1 && bounds.Height == 1 && bounds.X == 0 && bounds.Y == 0) + sep = "-1x1|"; + else + sep = "|"; + string key = font.GetHashCode ().ToString () + sep + text; + + if (measure_cache.ContainsKey (key)) { + return (SizeF)measure_cache[key]; + } else { + SizeF size; + + if (!use_textrenderer) + size = g.MeasureString (text, font, 10000, sf_nonprinting); + else + size = TextRenderer.MeasureTextInternal (g, text, font, Size.Empty, TextFormatFlags.NoPadding | TextFormatFlags.NoPrefix, false); + + measure_cache[key] = size; + + return size; + } + } + + if (!use_textrenderer) + return g.MeasureString (text, font, 10000, sf_nonprinting); + else + return TextRenderer.MeasureTextInternal (g, text, font, Size.Empty, TextFormatFlags.NoPadding | TextFormatFlags.NoPrefix, false); + } + } +} diff --git a/source/ShiftUI/Internal/TextControl.cs b/source/ShiftUI/Internal/TextControl.cs new file mode 100644 index 0000000..65dd5c6 --- /dev/null +++ b/source/ShiftUI/Internal/TextControl.cs @@ -0,0 +1,4613 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +// NOT COMPLETE + +// There's still plenty of things missing, I've got most of it planned, just hadn't had +// the time to write it all yet. +// Stuff missing (in no particular order): +// - Align text after RecalculateLine +// - Implement tag types for hotlinks, etc. +// - Implement CaretPgUp/PgDown + +// NOTE: +// selection_start.pos and selection_end.pos are 0-based +// selection_start.pos = first selected char +// selection_end.pos = first NOT-selected char +// +// FormatText methods are 1-based (as are all tags, LineTag.Start is 1 for +// the first character on a line; the reason is that 0 is the position +// *before* the first character on a line + + +#undef Debug + +using System; +using System.Collections; +using System.Drawing; +using System.Drawing.Text; +using System.Text; +using RTF=ShiftUI.RTF; + +namespace ShiftUI { + internal enum LineColor { + Red = 0, + Black = 1 + } + + internal enum CaretSelection { + Position, // Selection=Caret + Word, // Selection=Word under caret + Line // Selection=Line under caret + } + + [Flags] + internal enum FormatSpecified { + None, + + BackColor = 2, + Font = 4, + Color = 8, + } + + internal enum CaretDirection { + CharForward, // Move a char to the right + CharBack, // Move a char to the left + LineUp, // Move a line up + LineDown, // Move a line down + Home, // Move to the beginning of the line + End, // Move to the end of the line + PgUp, // Move one page up + PgDn, // Move one page down + CtrlPgUp, // Move caret to the first visible char in the viewport + CtrlPgDn, // Move caret to the last visible char in the viewport + CtrlHome, // Move to the beginning of the document + CtrlEnd, // Move to the end of the document + WordBack, // Move to the beginning of the previous word (or beginning of line) + WordForward, // Move to the beginning of the next word (or end of line) + SelectionStart, // Move to the beginning of the current selection + SelectionEnd, // Move to the end of the current selection + CharForwardNoWrap, // Move a char forward, but don't wrap onto the next line + CharBackNoWrap // Move a char backward, but don't wrap onto the previous line + } + + internal enum LineEnding { + Wrap = 1, // line wraps to the next line + Limp = 2, // \r + Hard = 4, // \r\n + Soft = 8, // \r\r\n + Rich = 16, // \n + + None = 0 + } + + internal class Document : ICloneable, IEnumerable { + #region Structures + // FIXME - go through code and check for places where + // we do explicit comparisons instead of using the compare overloads + internal struct Marker { + internal Line line; + internal LineTag tag; + internal int pos; + internal int height; + + public static bool operator<(Marker lhs, Marker rhs) { + if (lhs.line.line_no < rhs.line.line_no) { + return true; + } + + if (lhs.line.line_no == rhs.line.line_no) { + if (lhs.pos < rhs.pos) { + return true; + } + } + return false; + } + + public static bool operator>(Marker lhs, Marker rhs) { + if (lhs.line.line_no > rhs.line.line_no) { + return true; + } + + if (lhs.line.line_no == rhs.line.line_no) { + if (lhs.pos > rhs.pos) { + return true; + } + } + return false; + } + + public static bool operator==(Marker lhs, Marker rhs) { + if ((lhs.line.line_no == rhs.line.line_no) && (lhs.pos == rhs.pos)) { + return true; + } + return false; + } + + public static bool operator!=(Marker lhs, Marker rhs) { + if ((lhs.line.line_no != rhs.line.line_no) || (lhs.pos != rhs.pos)) { + return true; + } + return false; + } + + public void Combine(Line move_to_line, int move_to_line_length) { + line = move_to_line; + pos += move_to_line_length; + tag = LineTag.FindTag(line, pos); + } + + // This is for future use, right now Document.Split does it by hand, with some added shortcut logic + public void Split(Line move_to_line, int split_at) { + line = move_to_line; + pos -= split_at; + tag = LineTag.FindTag(line, pos); + } + + public override bool Equals(object obj) { + return this==(Marker)obj; + } + + public override int GetHashCode() { + return base.GetHashCode (); + } + + public override string ToString() { + return "Marker Line " + line + ", Position " + pos; + } + + } + #endregion Structures + + #region Local Variables + private Line document; + private int lines; + private Line sentinel; + private int document_id; + private Random random = new Random(); + internal string password_char; + private StringBuilder password_cache; + private bool calc_pass; + private int char_count; + private bool enable_links; + + // For calculating widths/heights + public static readonly StringFormat string_format = new StringFormat (StringFormat.GenericTypographic); + + private int recalc_suspended; + private bool recalc_pending; + private int recalc_start = 1; // This starts at one, since lines are 1 based + private int recalc_end; + private bool recalc_optimize; + + private int update_suspended; + private bool update_pending; + private int update_start = 1; + + internal bool multiline; + internal HorizontalAlignment alignment; + internal bool wrap; + + internal UndoManager undo; + + internal Marker caret; + internal Marker selection_start; + internal Marker selection_end; + internal bool selection_visible; + internal Marker selection_anchor; + internal Marker selection_prev; + internal bool selection_end_anchor; + + internal int viewport_x; + internal int viewport_y; // The visible area of the document + internal int offset_x; + internal int offset_y; + internal int viewport_width; + internal int viewport_height; + + internal int document_x; // Width of the document + internal int document_y; // Height of the document + + internal int crlf_size; // 1 or 2, depending on whether we use \r\n or just \n + + internal TextBoxBase owner; // Who's owning us? + static internal int caret_width = 1; + static internal int caret_shift = 1; + + internal int left_margin = 2; // A left margin for all lines + internal int top_margin = 2; + internal int right_margin = 2; + #endregion // Local Variables + + #region Constructors + internal Document (TextBoxBase owner) + { + lines = 0; + + this.owner = owner; + + multiline = true; + password_char = ""; + calc_pass = false; + recalc_pending = false; + + // Tree related stuff + sentinel = new Line (this, LineEnding.None); + sentinel.color = LineColor.Black; + + document = sentinel; + + // We always have a blank line + owner.HandleCreated += new EventHandler(owner_HandleCreated); + owner.VisibleChanged += new EventHandler(owner_VisibleChanged); + + Add (1, String.Empty, owner.Font, owner.ForeColor, LineEnding.None); + + undo = new UndoManager (this); + + selection_visible = false; + selection_start.line = this.document; + selection_start.pos = 0; + selection_start.tag = selection_start.line.tags; + selection_end.line = this.document; + selection_end.pos = 0; + selection_end.tag = selection_end.line.tags; + selection_anchor.line = this.document; + selection_anchor.pos = 0; + selection_anchor.tag = selection_anchor.line.tags; + caret.line = this.document; + caret.pos = 0; + caret.tag = caret.line.tags; + + viewport_x = 0; + viewport_y = 0; + + offset_x = 0; + offset_y = 0; + + crlf_size = 2; + + // Default selection is empty + + document_id = random.Next(); + + string_format.Trimming = StringTrimming.None; + string_format.FormatFlags = StringFormatFlags.DisplayFormatControl; + + UpdateMargins (); + } + #endregion + + #region Internal Properties + internal Line Root { + get { + return document; + } + + set { + document = value; + } + } + + // UIA: Method used via reflection in TextRangeProvider + internal int Lines { + get { + return lines; + } + } + + internal Line CaretLine { + get { + return caret.line; + } + } + + internal int CaretPosition { + get { + return caret.pos; + } + } + + internal Point Caret { + get { + return new Point((int)caret.tag.Line.widths[caret.pos] + caret.line.X, caret.line.Y); + } + } + + internal LineTag CaretTag { + get { + return caret.tag; + } + + set { + caret.tag = value; + } + } + + internal int CRLFSize { + get { + return crlf_size; + } + + set { + crlf_size = value; + } + } + + /// + /// Whether text is scanned for links + /// + internal bool EnableLinks { + get { return enable_links; } + set { enable_links = value; } + } + + internal string PasswordChar { + get { + return password_char; + } + + set { + password_char = value; + PasswordCache.Length = 0; + if ((password_char.Length != 0) && (password_char[0] != '\0')) { + calc_pass = true; + } else { + calc_pass = false; + } + } + } + + private StringBuilder PasswordCache { + get { + if (password_cache == null) + password_cache = new StringBuilder(); + return password_cache; + } + } + + internal int ViewPortX { + get { + return viewport_x; + } + + set { + viewport_x = value; + } + } + + internal int Length { + get { + return char_count + lines - 1; // Add \n for each line but the last + } + } + + private int CharCount { + get { + return char_count; + } + + set { + char_count = value; + + if (LengthChanged != null) { + LengthChanged(this, EventArgs.Empty); + } + } + } + + internal int ViewPortY { + get { + return viewport_y; + } + + set { + viewport_y = value; + } + } + + internal int OffsetX + { + get + { + return offset_x; + } + + set + { + offset_x = value; + } + } + + internal int OffsetY + { + get + { + return offset_y; + } + + set + { + offset_y = value; + } + } + + internal int ViewPortWidth { + get { + return viewport_width; + } + + set { + viewport_width = value; + } + } + + internal int ViewPortHeight { + get { + return viewport_height; + } + + set { + viewport_height = value; + } + } + + + internal int Width { + get { + return this.document_x; + } + } + + internal int Height { + get { + return this.document_y; + } + } + + internal bool SelectionVisible { + get { + return selection_visible; + } + } + + internal bool Wrap { + get { + return wrap; + } + + set { + wrap = value; + } + } + + #endregion // Internal Properties + + #region Private Methods + + internal void UpdateMargins () + { + switch (owner.actual_border_style) { + case BorderStyle.None: + left_margin = 0; + top_margin = 0; + right_margin = 1; + break; + case BorderStyle.FixedSingle: + left_margin = 2; + top_margin = 2; + right_margin = 3; + break; + case BorderStyle.Fixed3D: + left_margin = 1; + top_margin = 1; + right_margin = 2; + break; + } + } + + internal void SuspendRecalc () + { + if (recalc_suspended == 0) { + recalc_start = int.MaxValue; + recalc_end = int.MinValue; + } + + recalc_suspended++; + } + + internal void ResumeRecalc (bool immediate_update) + { + if (recalc_suspended > 0) + recalc_suspended--; + + if (recalc_suspended == 0 && (immediate_update || recalc_pending) && !(recalc_start == int.MaxValue && recalc_end == int.MinValue)) { + RecalculateDocument (owner.CreateGraphicsInternal (), recalc_start, recalc_end, recalc_optimize); + recalc_pending = false; + } + } + + internal void SuspendUpdate () + { + update_suspended++; + } + + internal void ResumeUpdate (bool immediate_update) + { + if (update_suspended > 0) + update_suspended--; + + if (immediate_update && update_suspended == 0 && update_pending) { + UpdateView (GetLine (update_start), 0); + update_pending = false; + } + } + + // For debugging + internal int DumpTree(Line line, bool with_tags) { + int total; + + total = 1; + + Console.Write("Line {0} [# {1}], Y: {2}, ending style: {3}, Text: '{4}'", + line.line_no, line.GetHashCode(), line.Y, line.ending, + line.text != null ? line.text.ToString() : "undefined"); + + if (line.left == sentinel) { + Console.Write(", left = sentinel"); + } else if (line.left == null) { + Console.Write(", left = NULL"); + } + + if (line.right == sentinel) { + Console.Write(", right = sentinel"); + } else if (line.right == null) { + Console.Write(", right = NULL"); + } + + Console.WriteLine(""); + + if (with_tags) { + LineTag tag; + int count; + int length; + + tag = line.tags; + count = 1; + length = 0; + Console.Write(" Tags: "); + while (tag != null) { + Console.Write("{0} <{1}>-<{2}>", count++, tag.Start, tag.End + /*line.text.ToString (tag.start - 1, tag.length)*/); + length += tag.Length; + + if (tag.Line != line) { + Console.Write("BAD line link"); + throw new Exception("Bad line link in tree"); + } + tag = tag.Next; + if (tag != null) { + Console.Write(", "); + } + } + if (length > line.text.Length) { + throw new Exception(String.Format("Length of tags more than length of text on line (expected {0} calculated {1})", line.text.Length, length)); + } else if (length < line.text.Length) { + throw new Exception(String.Format("Length of tags less than length of text on line (expected {0} calculated {1})", line.text.Length, length)); + } + Console.WriteLine(""); + } + if (line.left != null) { + if (line.left != sentinel) { + total += DumpTree(line.left, with_tags); + } + } else { + if (line != sentinel) { + throw new Exception("Left should not be NULL"); + } + } + + if (line.right != null) { + if (line.right != sentinel) { + total += DumpTree(line.right, with_tags); + } + } else { + if (line != sentinel) { + throw new Exception("Right should not be NULL"); + } + } + + for (int i = 1; i <= this.lines; i++) { + if (GetLine(i) == null) { + throw new Exception(String.Format("Hole in line order, missing {0}", i)); + } + } + + if (line == this.Root) { + if (total < this.lines) { + throw new Exception(String.Format("Not enough nodes in tree, found {0}, expected {1}", total, this.lines)); + } else if (total > this.lines) { + throw new Exception(String.Format("Too many nodes in tree, found {0}, expected {1}", total, this.lines)); + } + } + + return total; + } + + private void SetSelectionVisible (bool value) + { + bool old_selection_visible = selection_visible; + selection_visible = value; + + // cursor and selection are enemies, we can't have both in the same room at the same time + if (owner.IsHandleCreated && !owner.show_caret_w_selection) + XplatUI.CaretVisible (owner.Handle, !selection_visible); + if (UIASelectionChanged != null && (selection_visible || old_selection_visible)) + UIASelectionChanged (this, EventArgs.Empty); + } + + private void DecrementLines(int line_no) { + int current; + + current = line_no; + while (current <= lines) { + GetLine(current).line_no--; + current++; + } + return; + } + + private void IncrementLines(int line_no) { + int current; + + current = this.lines; + while (current >= line_no) { + GetLine(current).line_no++; + current--; + } + return; + } + + private void RebalanceAfterAdd(Line line1) { + Line line2; + + while ((line1 != document) && (line1.parent.color == LineColor.Red)) { + if (line1.parent == line1.parent.parent.left) { + line2 = line1.parent.parent.right; + + if ((line2 != null) && (line2.color == LineColor.Red)) { + line1.parent.color = LineColor.Black; + line2.color = LineColor.Black; + line1.parent.parent.color = LineColor.Red; + line1 = line1.parent.parent; + } else { + if (line1 == line1.parent.right) { + line1 = line1.parent; + RotateLeft(line1); + } + + line1.parent.color = LineColor.Black; + line1.parent.parent.color = LineColor.Red; + + RotateRight(line1.parent.parent); + } + } else { + line2 = line1.parent.parent.left; + + if ((line2 != null) && (line2.color == LineColor.Red)) { + line1.parent.color = LineColor.Black; + line2.color = LineColor.Black; + line1.parent.parent.color = LineColor.Red; + line1 = line1.parent.parent; + } else { + if (line1 == line1.parent.left) { + line1 = line1.parent; + RotateRight(line1); + } + + line1.parent.color = LineColor.Black; + line1.parent.parent.color = LineColor.Red; + RotateLeft(line1.parent.parent); + } + } + } + document.color = LineColor.Black; + } + + private void RebalanceAfterDelete(Line line1) { + Line line2; + + while ((line1 != document) && (line1.color == LineColor.Black)) { + if (line1 == line1.parent.left) { + line2 = line1.parent.right; + if (line2.color == LineColor.Red) { + line2.color = LineColor.Black; + line1.parent.color = LineColor.Red; + RotateLeft(line1.parent); + line2 = line1.parent.right; + } + if ((line2.left.color == LineColor.Black) && (line2.right.color == LineColor.Black)) { + line2.color = LineColor.Red; + line1 = line1.parent; + } else { + if (line2.right.color == LineColor.Black) { + line2.left.color = LineColor.Black; + line2.color = LineColor.Red; + RotateRight(line2); + line2 = line1.parent.right; + } + line2.color = line1.parent.color; + line1.parent.color = LineColor.Black; + line2.right.color = LineColor.Black; + RotateLeft(line1.parent); + line1 = document; + } + } else { + line2 = line1.parent.left; + if (line2.color == LineColor.Red) { + line2.color = LineColor.Black; + line1.parent.color = LineColor.Red; + RotateRight(line1.parent); + line2 = line1.parent.left; + } + if ((line2.right.color == LineColor.Black) && (line2.left.color == LineColor.Black)) { + line2.color = LineColor.Red; + line1 = line1.parent; + } else { + if (line2.left.color == LineColor.Black) { + line2.right.color = LineColor.Black; + line2.color = LineColor.Red; + RotateLeft(line2); + line2 = line1.parent.left; + } + line2.color = line1.parent.color; + line1.parent.color = LineColor.Black; + line2.left.color = LineColor.Black; + RotateRight(line1.parent); + line1 = document; + } + } + } + line1.color = LineColor.Black; + } + + private void RotateLeft(Line line1) { + Line line2 = line1.right; + + line1.right = line2.left; + + if (line2.left != sentinel) { + line2.left.parent = line1; + } + + if (line2 != sentinel) { + line2.parent = line1.parent; + } + + if (line1.parent != null) { + if (line1 == line1.parent.left) { + line1.parent.left = line2; + } else { + line1.parent.right = line2; + } + } else { + document = line2; + } + + line2.left = line1; + if (line1 != sentinel) { + line1.parent = line2; + } + } + + private void RotateRight(Line line1) { + Line line2 = line1.left; + + line1.left = line2.right; + + if (line2.right != sentinel) { + line2.right.parent = line1; + } + + if (line2 != sentinel) { + line2.parent = line1.parent; + } + + if (line1.parent != null) { + if (line1 == line1.parent.right) { + line1.parent.right = line2; + } else { + line1.parent.left = line2; + } + } else { + document = line2; + } + + line2.right = line1; + if (line1 != sentinel) { + line1.parent = line2; + } + } + + + internal void UpdateView(Line line, int pos) { + if (!owner.IsHandleCreated) { + return; + } + + if (update_suspended > 0) { + update_start = Math.Min (update_start, line.line_no); + // update_end = Math.Max (update_end, line.line_no); + // recalc_optimize = true; + update_pending = true; + return; + } + + // Optimize invalidation based on Line alignment + if (RecalculateDocument(owner.CreateGraphicsInternal(), line.line_no, line.line_no, true)) { + // Lineheight changed, invalidate the rest of the document + if ((line.Y - viewport_y) >=0 ) { + // We formatted something that's in view, only draw parts of the screen + owner.Invalidate(new Rectangle( + offset_x, + line.Y - viewport_y + offset_y, + viewport_width, + owner.Height - (line.Y - viewport_y))); + } else { + // The tag was above the visible area, draw everything + owner.Invalidate(); + } + } else { + switch(line.alignment) { + case HorizontalAlignment.Left: { + owner.Invalidate(new Rectangle( + line.X + ((int)line.widths[pos] - viewport_x - 1) + offset_x, + line.Y - viewport_y + offset_y, + viewport_width, + line.height + 1)); + break; + } + + case HorizontalAlignment.Center: { + owner.Invalidate(new Rectangle( + line.X + offset_x, + line.Y - viewport_y + offset_y, + viewport_width, + line.height + 1)); + break; + } + + case HorizontalAlignment.Right: { + owner.Invalidate(new Rectangle( + line.X + offset_x, + line.Y - viewport_y + offset_y, + (int)line.widths[pos + 1] - viewport_x + line.X, + line.height + 1)); + break; + } + } + } + } + + + // Update display from line, down line_count lines; pos is unused, but required for the signature + internal void UpdateView(Line line, int line_count, int pos) { + if (!owner.IsHandleCreated) { + return; + } + + if (recalc_suspended > 0) { + recalc_start = Math.Min (recalc_start, line.line_no); + recalc_end = Math.Max (recalc_end, line.line_no + line_count); + recalc_optimize = true; + recalc_pending = true; + return; + } + + int start_line_top = line.Y; + + Line end_line = GetLine (line.line_no + line_count); + if (end_line == null) + end_line = GetLine (lines); + + if (end_line == null) + return; + + int end_line_bottom = end_line.Y + end_line.height; + + if (RecalculateDocument(owner.CreateGraphicsInternal(), line.line_no, line.line_no + line_count, true)) { + // Lineheight changed, invalidate the rest of the document + if ((line.Y - viewport_y) >=0 ) { + // We formatted something that's in view, only draw parts of the screen + owner.Invalidate(new Rectangle( + offset_x, + line.Y - viewport_y + offset_y, + viewport_width, + owner.Height - (line.Y - viewport_y))); + } else { + // The tag was above the visible area, draw everything + owner.Invalidate(); + } + } else { + int x = 0 - viewport_x + offset_x; + int w = viewport_width; + int y = Math.Min (start_line_top - viewport_y, line.Y - viewport_y) + offset_y; + int h = Math.Max (end_line_bottom - y, end_line.Y + end_line.height - y); + + owner.Invalidate (new Rectangle (x, y, w, h)); + } + } + + /// + /// Scans the next paragraph for http:/ ftp:/ www. https:/ etc and marks the tags + /// as links. + /// + /// The line to start on + /// marks as true if something is changed + private void ScanForLinks (Line start_line, ref bool link_changed) + { + Line current_line = start_line; + StringBuilder line_no_breaks = new StringBuilder (); + StringBuilder line_link_record = new StringBuilder (); + ArrayList cumulative_length_list = new ArrayList (); + bool update_caret_tag = false; + + cumulative_length_list.Add (0); + + while (current_line != null) { + line_no_breaks.Append (current_line.text); + + if (link_changed == false) + current_line.LinkRecord (line_link_record); + + current_line.ClearLinks (); + + cumulative_length_list.Add (line_no_breaks.Length); + + if (current_line.ending == LineEnding.Wrap) + current_line = GetLine (current_line.LineNo + 1); + else + break; + } + + // search for protocols.. make sure www. is first! + string [] search_terms = new string [] { "www.", "http:/", "ftp:/", "https:/" }; + int search_found = 0; + int index_found = 0; + string line_no_breaks_string = line_no_breaks.ToString (); + int line_no_breaks_index = 0; + int link_end = 0; + + while (true) { + if (line_no_breaks_index >= line_no_breaks_string.Length) + break; + + index_found = FirstIndexOfAny (line_no_breaks_string, search_terms, line_no_breaks_index, out search_found); + + //no links found on this line + if (index_found == -1) + break; + + if (search_found == 0) { + // if we are at the end of the line to analyse and the end of the line + // is "www." then there are no links here + if (line_no_breaks_string.Length == index_found + search_terms [0].Length) + break; + + // if after www. we don't have a letter a digit or a @ or - or / + // then it is not a web address, we should continue searching + if (char.IsLetterOrDigit (line_no_breaks_string [index_found + search_terms [0].Length]) == false && + "@/~".IndexOf (line_no_breaks_string [index_found + search_terms [0].Length].ToString ()) == -1) { + line_no_breaks_index = index_found + search_terms [0].Length; + continue; + } + } + + link_end = line_no_breaks_string.Length - 1; + line_no_breaks_index = line_no_breaks_string.Length; + + // we've found a link, we just need to find where it ends now + for (int i = index_found + search_terms [search_found].Length; i < line_no_breaks_string.Length; i++) { + if (line_no_breaks_string [i - 1] == '.') { + if (char.IsLetterOrDigit (line_no_breaks_string [i]) == false && + "@/~".IndexOf (line_no_breaks_string [i].ToString ()) == -1) { + link_end = i - 1; + line_no_breaks_index = i; + break; + } + } else { + if (char.IsLetterOrDigit (line_no_breaks_string [i]) == false && + "@-/:~.?=_&".IndexOf (line_no_breaks_string [i].ToString ()) == -1) { + link_end = i - 1; + line_no_breaks_index = i; + break; + } + } + } + + string link_text = line_no_breaks_string.Substring (index_found, link_end - index_found + 1); + int current_cumulative = 0; + + // we've found a link - index_found -> link_end + // now we just make all the tags as containing link and + // point them to the text for the whole link + + current_line = start_line; + + //find the line we start on + for (current_cumulative = 1; current_cumulative < cumulative_length_list.Count; current_cumulative++) + if ((int)cumulative_length_list [current_cumulative] > index_found) + break; + + current_line = GetLine (start_line.LineNo + current_cumulative - 1); + + // find the tag we start on + LineTag current_tag = current_line.FindTag (index_found - (int)cumulative_length_list [current_cumulative - 1] + 1); + + if (current_tag.Start != (index_found - (int)cumulative_length_list [current_cumulative - 1]) + 1) { + if (current_tag == CaretTag) + update_caret_tag = true; + + current_tag = current_tag.Break ((index_found - (int)cumulative_length_list [current_cumulative - 1]) + 1); + } + + // set the tag + current_tag.IsLink = true; + current_tag.LinkText = link_text; + + //go through each character + // find the tag we are in + // skip the number of characters in the tag + for (int i = 1; i < link_text.Length; i++) { + // on to a new word-wrapped line + if ((int)cumulative_length_list [current_cumulative] <= index_found + i) { + + current_line = GetLine (start_line.LineNo + current_cumulative++); + current_tag = current_line.FindTag (index_found + i - (int)cumulative_length_list [current_cumulative - 1] + 1); + + current_tag.IsLink = true; + current_tag.LinkText = link_text; + + continue; + } + + if (current_tag.End < index_found + 1 + i - (int)cumulative_length_list [current_cumulative - 1]) { + // skip empty tags in the middle of the URL + do { + current_tag = current_tag.Next; + } while (current_tag.Length == 0); + + current_tag.IsLink = true; + current_tag.LinkText = link_text; + } + } + + //if there are characters left in the tag after the link + // split the tag + // make the second part a non link + if (current_tag.End > (index_found + link_text.Length + 1) - (int)cumulative_length_list [current_cumulative - 1]) { + if (current_tag == CaretTag) + update_caret_tag = true; + + current_tag.Break ((index_found + link_text.Length + 1) - (int)cumulative_length_list [current_cumulative - 1]); + } + } + + if (update_caret_tag) { + CaretTag = LineTag.FindTag (CaretLine, CaretPosition); + link_changed = true; + } else { + if (link_changed == false) { + current_line = start_line; + StringBuilder new_link_record = new StringBuilder (); + + while (current_line != null) { + current_line.LinkRecord (new_link_record); + + if (current_line.ending == LineEnding.Wrap) + current_line = GetLine (current_line.LineNo + 1); + else + break; + } + + if (new_link_record.Equals (line_link_record) == false) + link_changed = true; + } + } + } + + private int FirstIndexOfAny (string haystack, string [] needles, int start_index, out int term_found) + { + term_found = -1; + int best_index = -1; + + for (int i = 0; i < needles.Length; i++) { + int index = haystack.IndexOf (needles [i], start_index, StringComparison.InvariantCultureIgnoreCase); + + if (index > -1) { + if (term_found > -1) { + if (index < best_index) { + best_index = index; + term_found = i; + } + } else { + best_index = index; + term_found = i; + } + } + } + + return best_index; + } + + + + private void InvalidateLinks (Rectangle clip) + { + for (int i = (owner.list_links.Count - 1); i >= 0; i--) { + TextBoxBase.LinkRectangle link = (TextBoxBase.LinkRectangle) owner.list_links [i]; + + if (clip.IntersectsWith (link.LinkAreaRectangle)) + owner.list_links.RemoveAt (i); + } + } + #endregion // Private Methods + + #region Internal Methods + + internal void ScanForLinks (int start, int end, ref bool link_changed) + { + Line line = null; + LineEnding lastending = LineEnding.Rich; + + // make sure we start scanning at the real begining of the line + while (true) { + if (start != 1 && GetLine (start - 1).ending == LineEnding.Wrap) + start--; + else + break; + } + + for (int i = start; i <= end && i <= lines; i++) { + line = GetLine (i); + + if (lastending != LineEnding.Wrap) + ScanForLinks (line, ref link_changed); + + lastending = line.ending; + + if (lastending == LineEnding.Wrap && (i + 1) <= end) + end++; + } + } + + // Clear the document and reset state + internal void Empty() { + + document = sentinel; + lines = 0; + + // We always have a blank line + Add (1, String.Empty, owner.Font, owner.ForeColor, LineEnding.None); + + this.RecalculateDocument(owner.CreateGraphicsInternal()); + PositionCaret(0, 0); + + SetSelectionVisible (false); + + selection_start.line = this.document; + selection_start.pos = 0; + selection_start.tag = selection_start.line.tags; + selection_end.line = this.document; + selection_end.pos = 0; + selection_end.tag = selection_end.line.tags; + char_count = 0; + + viewport_x = 0; + viewport_y = 0; + + document_x = 0; + document_y = 0; + + if (owner.IsHandleCreated) + owner.Invalidate (); + } + + internal void PositionCaret(Line line, int pos) { + caret.tag = line.FindTag (pos); + + MoveCaretToTextTag (); + + caret.line = line; + caret.pos = pos; + + if (owner.IsHandleCreated) { + if (owner.Focused) { + if (caret.height != caret.tag.Height) + XplatUI.CreateCaret (owner.Handle, caret_width, caret.height); + XplatUI.SetCaretPos(owner.Handle, + offset_x + (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, + offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); + } + + if (CaretMoved != null) CaretMoved(this, EventArgs.Empty); + } + + // We set this at the end because we use the heights to determine whether or + // not we need to recreate the caret + caret.height = caret.tag.Height; + + } + + internal void PositionCaret(int x, int y) { + if (!owner.IsHandleCreated) { + return; + } + + caret.tag = FindCursor(x, y, out caret.pos); + + MoveCaretToTextTag (); + + caret.line = caret.tag.Line; + caret.height = caret.tag.Height; + + if (owner.ShowSelection && (!selection_visible || owner.show_caret_w_selection)) { + XplatUI.CreateCaret (owner.Handle, caret_width, caret.height); + XplatUI.SetCaretPos(owner.Handle, + (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x + offset_x, + offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); + } + + if (CaretMoved != null) CaretMoved(this, EventArgs.Empty); + } + + internal void CaretHasFocus() { + if ((caret.tag != null) && owner.IsHandleCreated) { + XplatUI.CreateCaret(owner.Handle, caret_width, caret.height); + XplatUI.SetCaretPos(owner.Handle, + offset_x + (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, + offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); + + DisplayCaret (); + } + + if (owner.IsHandleCreated && SelectionLength () > 0) { + InvalidateSelectionArea (); + } + } + + internal void CaretLostFocus() { + if (!owner.IsHandleCreated) { + return; + } + XplatUI.DestroyCaret(owner.Handle); + } + + internal void AlignCaret () + { + AlignCaret (true); + } + + internal void AlignCaret(bool changeCaretTag) { + if (!owner.IsHandleCreated) { + return; + } + + if (changeCaretTag) { + caret.tag = LineTag.FindTag (caret.line, caret.pos); + + MoveCaretToTextTag (); + } + + // if the caret has had SelectionFont changed to a + // different height, we reflect changes unless the new + // font is larger than the line (line recalculations + // ignore empty tags) in which case we make it equal + // the line height and then when text is entered + if (caret.tag.Height > caret.tag.Line.Height) { + caret.height = caret.line.height; + } else { + caret.height = caret.tag.Height; + } + + if (owner.Focused) { + XplatUI.CreateCaret(owner.Handle, caret_width, caret.height); + XplatUI.SetCaretPos (owner.Handle, + offset_x + (int) caret.tag.Line.widths [caret.pos] + caret.line.X - viewport_x, + offset_y + caret.line.Y + viewport_y + caret_shift); + DisplayCaret (); + } + + if (CaretMoved != null) CaretMoved(this, EventArgs.Empty); + } + + internal void UpdateCaret() { + if (!owner.IsHandleCreated || caret.tag == null) { + return; + } + + MoveCaretToTextTag (); + + if (caret.tag.Height != caret.height) { + caret.height = caret.tag.Height; + if (owner.Focused) { + XplatUI.CreateCaret(owner.Handle, caret_width, caret.height); + } + } + + if (owner.Focused) { + XplatUI.SetCaretPos(owner.Handle, + offset_x + (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, + offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); + DisplayCaret (); + } + + if (CaretMoved != null) CaretMoved(this, EventArgs.Empty); + } + + internal void DisplayCaret() { + if (!owner.IsHandleCreated) { + return; + } + + if (owner.ShowSelection && (!selection_visible || owner.show_caret_w_selection)) { + XplatUI.CaretVisible(owner.Handle, true); + } + } + + internal void HideCaret() { + if (!owner.IsHandleCreated) { + return; + } + + if (owner.Focused) { + XplatUI.CaretVisible(owner.Handle, false); + } + } + + + internal void MoveCaretToTextTag () + { + if (caret.tag == null || caret.tag.IsTextTag) + return; + + + + if (caret.pos < caret.tag.Start) { + caret.tag = caret.tag.Previous; + } else { + caret.tag = caret.tag.Next; + } + } + + internal void MoveCaret(CaretDirection direction) { + // FIXME should we use IsWordSeparator to detect whitespace, instead + // of looking for actual spaces in the Word move cases? + + bool nowrap = false; + switch(direction) { + case CaretDirection.CharForwardNoWrap: + nowrap = true; + goto case CaretDirection.CharForward; + case CaretDirection.CharForward: { + caret.pos++; + if (caret.pos > caret.line.TextLengthWithoutEnding ()) { + if (!nowrap) { + // Go into next line + if (caret.line.line_no < this.lines) { + caret.line = GetLine(caret.line.line_no+1); + caret.pos = 0; + caret.tag = caret.line.tags; + } else { + caret.pos--; + } + } else { + // Single line; we stay where we are + caret.pos--; + } + } else { + if ((caret.tag.Start - 1 + caret.tag.Length) < caret.pos) { + caret.tag = caret.tag.Next; + } + } + UpdateCaret(); + return; + } + + case CaretDirection.CharBackNoWrap: + nowrap = true; + goto case CaretDirection.CharBack; + case CaretDirection.CharBack: { + if (caret.pos > 0) { + // caret.pos--; // folded into the if below + + if (--caret.pos > 0) { + if (caret.tag.Start > caret.pos) { + caret.tag = caret.tag.Previous; + } + } + } else { + if (caret.line.line_no > 1 && !nowrap) { + caret.line = GetLine(caret.line.line_no - 1); + caret.pos = caret.line.TextLengthWithoutEnding (); + caret.tag = LineTag.FindTag(caret.line, caret.pos); + } + } + UpdateCaret(); + return; + } + + case CaretDirection.WordForward: { + int len; + + len = caret.line.text.Length; + if (caret.pos < len) { + while ((caret.pos < len) && (caret.line.text[caret.pos] != ' ')) { + caret.pos++; + } + if (caret.pos < len) { + // Skip any whitespace + while ((caret.pos < len) && (caret.line.text[caret.pos] == ' ')) { + caret.pos++; + } + } + caret.tag = LineTag.FindTag(caret.line, caret.pos); + } else { + if (caret.line.line_no < this.lines) { + caret.line = GetLine(caret.line.line_no + 1); + caret.pos = 0; + caret.tag = caret.line.tags; + } + } + UpdateCaret(); + return; + } + + case CaretDirection.WordBack: { + if (caret.pos > 0) { + caret.pos--; + + while ((caret.pos > 0) && (caret.line.text[caret.pos] == ' ')) { + caret.pos--; + } + + while ((caret.pos > 0) && (caret.line.text[caret.pos] != ' ')) { + caret.pos--; + } + + if (caret.line.text.ToString(caret.pos, 1) == " ") { + if (caret.pos != 0) { + caret.pos++; + } else { + caret.line = GetLine(caret.line.line_no - 1); + caret.pos = caret.line.text.Length; + } + } + caret.tag = LineTag.FindTag(caret.line, caret.pos); + } else { + if (caret.line.line_no > 1) { + caret.line = GetLine(caret.line.line_no - 1); + caret.pos = caret.line.text.Length; + caret.tag = LineTag.FindTag(caret.line, caret.pos); + } + } + UpdateCaret(); + return; + } + + case CaretDirection.LineUp: { + if (caret.line.line_no > 1) { + int pixel; + + pixel = (int)caret.line.widths[caret.pos]; + PositionCaret(pixel, GetLine(caret.line.line_no - 1).Y); + + DisplayCaret (); + } + return; + } + + case CaretDirection.LineDown: { + if (caret.line.line_no < lines) { + int pixel; + + pixel = (int)caret.line.widths[caret.pos]; + PositionCaret(pixel, GetLine(caret.line.line_no + 1).Y); + + DisplayCaret (); + } + return; + } + + case CaretDirection.Home: { + if (caret.pos > 0) { + caret.pos = 0; + caret.tag = caret.line.tags; + UpdateCaret(); + } + return; + } + + case CaretDirection.End: { + if (caret.pos < caret.line.TextLengthWithoutEnding ()) { + caret.pos = caret.line.TextLengthWithoutEnding (); + caret.tag = LineTag.FindTag(caret.line, caret.pos); + UpdateCaret(); + } + return; + } + + case CaretDirection.PgUp: { + + if (caret.line.line_no == 1 && owner.richtext) { + owner.vscroll.Value = 0; + Line line = GetLine (1); + PositionCaret (line, 0); + } + + int y_offset = caret.line.Y + caret.line.height - 1 - viewport_y; + int index; + LineTag top = FindCursor ((int) caret.line.widths [caret.pos], + viewport_y - viewport_height, out index); + + owner.vscroll.Value = Math.Min (top.Line.Y, owner.vscroll.Maximum - viewport_height); + PositionCaret ((int) caret.line.widths [caret.pos], y_offset + viewport_y); + + return; + } + + case CaretDirection.PgDn: { + + if (caret.line.line_no == lines && owner.richtext) { + owner.vscroll.Value = owner.vscroll.Maximum - viewport_height + 1; + Line line = GetLine (lines); + PositionCaret (line, line.TextLengthWithoutEnding()); + } + + int y_offset = caret.line.Y - viewport_y; + int index; + LineTag top = FindCursor ((int) caret.line.widths [caret.pos], + viewport_y + viewport_height, out index); + + owner.vscroll.Value = Math.Min (top.Line.Y, owner.vscroll.Maximum - viewport_height); + PositionCaret ((int) caret.line.widths [caret.pos], y_offset + viewport_y); + + return; + } + + case CaretDirection.CtrlPgUp: { + PositionCaret(0, viewport_y); + DisplayCaret (); + return; + } + + case CaretDirection.CtrlPgDn: { + Line line; + LineTag tag; + int index; + + tag = FindCursor (0, viewport_y + viewport_height, out index); + if (tag.Line.line_no > 1) { + line = GetLine(tag.Line.line_no - 1); + } else { + line = tag.Line; + } + PositionCaret(line, line.Text.Length); + DisplayCaret (); + return; + } + + case CaretDirection.CtrlHome: { + caret.line = GetLine(1); + caret.pos = 0; + caret.tag = caret.line.tags; + + UpdateCaret(); + return; + } + + case CaretDirection.CtrlEnd: { + caret.line = GetLine(lines); + caret.pos = caret.line.TextLengthWithoutEnding (); + caret.tag = LineTag.FindTag(caret.line, caret.pos); + + UpdateCaret(); + return; + } + + case CaretDirection.SelectionStart: { + caret.line = selection_start.line; + caret.pos = selection_start.pos; + caret.tag = selection_start.tag; + + UpdateCaret(); + return; + } + + case CaretDirection.SelectionEnd: { + caret.line = selection_end.line; + caret.pos = selection_end.pos; + caret.tag = selection_end.tag; + + UpdateCaret(); + return; + } + } + } + + internal void DumpDoc () + { + Console.WriteLine ("", lines); + for (int i = 1; i <= lines ; i++) { + Line line = GetLine (i); + Console.WriteLine ("", line.line_no, line.ending); + + LineTag tag = line.tags; + while (tag != null) { + Console.Write ("\t", + tag.GetType (), tag.Start, tag.Length, tag.Font, tag.Color); + Console.Write (tag.Text ()); + Console.WriteLine (""); + tag = tag.Next; + } + Console.WriteLine (""); + } + Console.WriteLine (""); + } + + // UIA: Used via reflection by TextProviderBehavior + internal void GetVisibleLineIndexes (Rectangle clip, out int start, out int end) + { + if (multiline) { + /* Expand the region slightly to be sure to + * paint the full extent of the line of text. + * See bug 464464. + */ + start = GetLineByPixel(clip.Top + viewport_y - offset_y - 1, false).line_no; + end = GetLineByPixel(clip.Bottom + viewport_y - offset_y + 1, false).line_no; + } else { + start = GetLineByPixel(clip.Left + viewport_x - offset_x, false).line_no; + end = GetLineByPixel(clip.Right + viewport_x - offset_x, false).line_no; + } + } + + internal void Draw (Graphics g, Rectangle clip) + { + Line line; // Current line being drawn + LineTag tag; // Current tag being drawn + int start; // First line to draw + int end; // Last line to draw + StringBuilder text; // String representing the current line + int line_no; + Color tag_color; + Color current_color; + + // First, figure out from what line to what line we need to draw + GetVisibleLineIndexes (clip, out start, out end); + + // remove links in the list (used for mouse down events) that are within the clip area. + InvalidateLinks (clip); + + /// + /// We draw the single border ourself + /// + if (owner.actual_border_style == BorderStyle.FixedSingle) { + WidgetPaint.DrawBorder (g, owner.ClientRectangle, Color.Black, ButtonBorderStyle.Solid); + } + + /// Make sure that we aren't drawing one more line then we need to + line = GetLine (end - 1); + if (line != null && clip.Bottom == offset_y + line.Y + line.height - viewport_y) + end--; + + line_no = start; + + #if Debug + DateTime n = DateTime.Now; + Console.WriteLine ("Started drawing: {0}s {1}ms", n.Second, n.Millisecond); + Console.WriteLine ("CLIP: {0}", clip); + Console.WriteLine ("S: {0}", GetLine (start).text); + Console.WriteLine ("E: {0}", GetLine (end).text); + #endif + + // Non multiline selection can be handled outside of the loop + if (!multiline && selection_visible && owner.ShowSelection) { + g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorHighlight), + offset_x + selection_start.line.widths [selection_start.pos] + + selection_start.line.X - viewport_x, + offset_y + selection_start.line.Y, + (selection_end.line.X + selection_end.line.widths [selection_end.pos]) - + (selection_start.line.X + selection_start.line.widths [selection_start.pos]), + selection_start.line.height); + } + + while (line_no <= end) { + line = GetLine (line_no); + float line_y = line.Y - viewport_y + offset_y; + + tag = line.tags; + if (!calc_pass) { + text = line.text; + } else { + if (PasswordCache.Length < line.text.Length) + PasswordCache.Append(Char.Parse(password_char), line.text.Length - PasswordCache.Length); + else if (PasswordCache.Length > line.text.Length) + PasswordCache.Remove(line.text.Length, PasswordCache.Length - line.text.Length); + text = PasswordCache; + } + + int line_selection_start = text.Length + 1; + int line_selection_end = text.Length + 1; + if (selection_visible && owner.ShowSelection && + (line_no >= selection_start.line.line_no) && + (line_no <= selection_end.line.line_no)) { + + if (line_no == selection_start.line.line_no) + line_selection_start = selection_start.pos + 1; + else + line_selection_start = 1; + + if (line_no == selection_end.line.line_no) + line_selection_end = selection_end.pos + 1; + else + line_selection_end = text.Length + 1; + + if (line_selection_end == line_selection_start) { + // There isn't really selection + line_selection_start = text.Length + 1; + line_selection_end = line_selection_start; + } else if (multiline) { + // lets draw some selection baby!! (non multiline selection is drawn outside the loop) + g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorHighlight), + offset_x + line.widths [line_selection_start - 1] + line.X - viewport_x, + line_y, line.widths [line_selection_end - 1] - line.widths [line_selection_start - 1], + line.height); + } + } + + current_color = line.tags.ColorToDisplay; + while (tag != null) { + + // Skip empty tags + if (tag.Length == 0) { + tag = tag.Next; + continue; + } + + if (((tag.X + tag.Width) < (clip.Left - viewport_x - offset_x)) && + (tag.X > (clip.Right - viewport_x - offset_x))) { + tag = tag.Next; + continue; + } + + if (tag.BackColor != Color.Empty) { + g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (tag.BackColor), + offset_x + tag.X + line.X - viewport_x, + line_y + tag.Shift, tag.Width, line.height); + } + + tag_color = tag.ColorToDisplay; + current_color = tag_color; + + if (!owner.Enabled) { + Color a = tag.Color; + Color b = ThemeEngine.Current.ColorWindowText; + + if ((a.R == b.R) && (a.G == b.G) && (a.B == b.B)) + tag_color = ThemeEngine.Current.ColorGrayText; + + } + + int tag_pos = tag.Start; + current_color = tag_color; + while (tag_pos < tag.Start + tag.Length) { + int old_tag_pos = tag_pos; + + if (tag_pos >= line_selection_start && tag_pos < line_selection_end) { + current_color = ThemeEngine.Current.ColorHighlightText; + tag_pos = Math.Min (tag.End, line_selection_end); + } else if (tag_pos < line_selection_start) { + current_color = tag_color; + tag_pos = Math.Min (tag.End, line_selection_start); + } else { + current_color = tag_color; + tag_pos = tag.End; + } + + Rectangle text_size; + + tag.Draw (g, current_color, + offset_x + line.X - viewport_x, + line_y + tag.Shift, + old_tag_pos - 1, Math.Min (tag.Start + tag.Length, tag_pos) - 1, + text.ToString (), out text_size, tag.IsLink); + + if (tag.IsLink) { + TextBoxBase.LinkRectangle link = new TextBoxBase.LinkRectangle (text_size); + link.LinkTag = tag; + owner.list_links.Add (link); + } + } + tag = tag.Next; + } + + line.DrawEnding (g, line_y); + line_no++; + } + } + + private int GetLineEnding (string line, int start, out LineEnding ending) + { + int res; + int rich_index; + + if (start >= line.Length) { + ending = LineEnding.Wrap; + return -1; + } + + res = line.IndexOf ('\r', start); + rich_index = line.IndexOf ('\n', start); + + // Handle the case where we find both of them, and the \n is before the \r + if (res != -1 && rich_index != -1) + if (rich_index < res) { + ending = LineEnding.Rich; + return rich_index; + } + + if (res != -1) { + if (res + 2 < line.Length && line [res + 1] == '\r' && line [res + 2] == '\n') { + ending = LineEnding.Soft; + return res; + } + if (res + 1 < line.Length && line [res + 1] == '\n') { + ending = LineEnding.Hard; + return res; + } + ending = LineEnding.Limp; + return res; + } + + if (rich_index != -1) { + ending = LineEnding.Rich; + return rich_index; + } + + ending = LineEnding.Wrap; + return line.Length; + } + + // Get the line ending, but only of the types specified + private int GetLineEnding (string line, int start, out LineEnding ending, LineEnding type) + { + int index = start; + int last_length = 0; + + do { + index = GetLineEnding (line, index + last_length, out ending); + last_length = LineEndingLength (ending); + } while + ((ending & type) != ending && index != -1); + + return index == -1 ? line.Length : index; + } + + internal int LineEndingLength (LineEnding ending) + { + switch (ending) { + case LineEnding.Limp: + case LineEnding.Rich: + return 1; + case LineEnding.Hard: + return 2; + case LineEnding.Soft: + return 3; + } + + return 0; + } + + internal string LineEndingToString (LineEnding ending) + { + switch (ending) { + case LineEnding.Limp: + return "\r"; + case LineEnding.Hard: + return "\r\n"; + case LineEnding.Soft: + return "\r\r\n"; + case LineEnding.Rich: + return "\n"; + } + + return string.Empty; + } + + internal LineEnding StringToLineEnding (string ending) + { + switch (ending) { + case "\r": + return LineEnding.Limp; + case "\r\n": + return LineEnding.Hard; + case "\r\r\n": + return LineEnding.Soft; + case "\n": + return LineEnding.Rich; + default: + return LineEnding.None; + } + } + + internal void Insert (Line line, int pos, bool update_caret, string s) + { + Insert (line, pos, update_caret, s, line.FindTag (pos)); + } + + // Insert text at the given position; use formatting at insertion point for inserted text + internal void Insert (Line line, int pos, bool update_caret, string s, LineTag tag) + { + int break_index; + int base_line; + int old_line_count; + int count = 1; + LineEnding ending; + Line split_line; + + // Don't recalculate while we mess around + SuspendRecalc (); + + base_line = line.line_no; + old_line_count = lines; + + // Discard chars after any possible -unlikely- end of file + int eof_index = s.IndexOf ('\0'); + if (eof_index != -1) + s = s.Substring (0, eof_index); + + break_index = GetLineEnding (s, 0, out ending, LineEnding.Hard | LineEnding.Rich); + + // There are no line feeds in our text to be pasted + if (break_index == s.Length) { + line.InsertString (pos, s, tag); + } else { + // Add up to the first line feed to our current position + line.InsertString (pos, s.Substring (0, break_index + LineEndingLength (ending)), tag); + + // Split the rest of the original line to a new line + Split (line, pos + (break_index + LineEndingLength (ending))); + line.ending = ending; + break_index += LineEndingLength (ending); + split_line = GetLine (line.line_no + 1); + + // Insert brand new lines for any more line feeds in the inserted string + while (true) { + int next_break = GetLineEnding (s, break_index, out ending, LineEnding.Hard | LineEnding.Rich); + + if (next_break == s.Length) + break; + + string line_text = s.Substring (break_index, next_break - break_index + + LineEndingLength (ending)); + + Add (base_line + count, line_text, line.alignment, tag.Font, tag.Color, ending); + + Line last = GetLine (base_line + count); + last.ending = ending; + + count++; + break_index = next_break + LineEndingLength (ending); + } + + // Add the remainder of the insert text to the split + // part of the original line + split_line.InsertString (0, s.Substring (break_index)); + } + + // Allow the document to recalculate things + ResumeRecalc (false); + + // Update our character count + CharCount += s.Length; + + UpdateView (line, lines - old_line_count + 1, pos); + + // Move the caret to the end of the inserted text if requested + if (update_caret) { + Line l = GetLine (line.line_no + lines - old_line_count); + PositionCaret (l, l.text.Length); + DisplayCaret (); + } + } + + // Inserts a string at the given position + internal void InsertString (Line line, int pos, string s) + { + // Update our character count + CharCount += s.Length; + + // Insert the text into the Line + line.InsertString (pos, s); + } + + // Inserts a character at the current caret position + internal void InsertCharAtCaret (char ch, bool move_caret) + { + caret.line.InsertString (caret.pos, ch.ToString(), caret.tag); + + // Update our character count + CharCount++; + + undo.RecordTyping (caret.line, caret.pos, ch); + + UpdateView (caret.line, caret.pos); + + if (move_caret) { + caret.pos++; + UpdateCaret (); + SetSelectionToCaret (true); + } + } + + internal void InsertPicture (Line line, int pos, RTF.Picture picture) + { + //LineTag next_tag; + LineTag tag; + int len; + + len = 1; + + // Just a place holder basically + line.text.Insert (pos, "I"); + + PictureTag picture_tag = new PictureTag (line, pos + 1, picture); + + tag = LineTag.FindTag (line, pos); + picture_tag.CopyFormattingFrom (tag); + /*next_tag = */tag.Break (pos + 1); + picture_tag.Previous = tag; + picture_tag.Next = tag.Next; + tag.Next = picture_tag; + + // + // Picture tags need to be surrounded by text tags + // + if (picture_tag.Next == null) { + picture_tag.Next = new LineTag (line, pos + 1); + picture_tag.Next.CopyFormattingFrom (tag); + picture_tag.Next.Previous = picture_tag; + } + + tag = picture_tag.Next; + while (tag != null) { + tag.Start += len; + tag = tag.Next; + } + + line.Grow (len); + line.recalc = true; + + UpdateView (line, pos); + } + + internal void DeleteMultiline (Line start_line, int pos, int length) + { + Marker start = new Marker (); + Marker end = new Marker (); + int start_index = LineTagToCharIndex (start_line, pos); + + start.line = start_line; + start.pos = pos; + start.tag = LineTag.FindTag (start_line, pos); + + CharIndexToLineTag (start_index + length, out end.line, + out end.tag, out end.pos); + + SuspendUpdate (); + + if (start.line == end.line) { + DeleteChars (start.line, pos, end.pos - pos); + } else { + + // Delete first and last lines + DeleteChars (start.line, start.pos, start.line.text.Length - start.pos); + DeleteChars (end.line, 0, end.pos); + + int current = start.line.line_no + 1; + if (current < end.line.line_no) { + for (int i = end.line.line_no - 1; i >= current; i--) { + Delete (i); + } + } + + // BIG FAT WARNING - selection_end.line might be stale due + // to the above Delete() call. DONT USE IT before hitting the end of this method! + + // Join start and end + Combine (start.line.line_no, current); + } + + ResumeUpdate (true); + } + + + // Deletes n characters at the given position; it will not delete past line limits + // pos is 0-based + public void DeleteChars (Line line, int pos, int count) + { + // Reduce our character count + CharCount -= count; + + line.DeleteCharacters (pos, count); + + if (pos >= line.TextLengthWithoutEnding ()) { + LineEnding ending = line.ending; + GetLineEnding (line.text.ToString (), 0, out ending); + + if (ending != line.ending) { + line.ending = ending; + + if (!multiline) { + UpdateView (line, lines, pos); + owner.Invalidate (); + return; + } + } + } + if (!multiline) { + UpdateView (line, lines, pos); + owner.Invalidate (); + } else + UpdateView (line, pos); + } + + // Deletes a character at or after the given position (depending on forward); it will not delete past line limits + public void DeleteChar (Line line, int pos, bool forward) + { + if ((pos == 0 && forward == false) || (pos == line.text.Length && forward == true)) + return; + + undo.BeginUserAction ("Delete"); + + if (forward) { + undo.RecordDeleteString (line, pos, line, pos + 1); + DeleteChars (line, pos, 1); + } else { + undo.RecordDeleteString (line, pos - 1, line, pos); + DeleteChars (line, pos - 1, 1); + } + + undo.EndUserAction (); + } + + // Combine two lines + internal void Combine(int FirstLine, int SecondLine) { + Combine(GetLine(FirstLine), GetLine(SecondLine)); + } + + internal void Combine(Line first, Line second) { + LineTag last; + int shift; + + // strip the ending off of the first lines text + first.text.Length = first.text.Length - LineEndingLength (first.ending); + + // Combine the two tag chains into one + last = first.tags; + + // Maintain the line ending style + first.ending = second.ending; + + while (last.Next != null) { + last = last.Next; + } + + // need to get the shift before setting the next tag since that effects length + shift = last.Start + last.Length - 1; + last.Next = second.tags; + last.Next.Previous = last; + + // Fix up references within the chain + last = last.Next; + while (last != null) { + last.Line = first; + last.Start += shift; + last = last.Next; + } + + // Combine both lines' strings + first.text.Insert(first.text.Length, second.text.ToString()); + first.Grow(first.text.Length); + + // Remove the reference to our (now combined) tags from the doomed line + second.tags = null; + + // Renumber lines + DecrementLines(first.line_no + 2); // first.line_no + 1 will be deleted, so we need to start renumbering one later + + // Mop up + first.recalc = true; + first.height = 0; // This forces RecalcDocument/UpdateView to redraw from this line on + first.Streamline(lines); + + // Update Caret, Selection, etc + if (caret.line == second) { + caret.Combine(first, shift); + } + if (selection_anchor.line == second) { + selection_anchor.Combine(first, shift); + } + if (selection_start.line == second) { + selection_start.Combine(first, shift); + } + if (selection_end.line == second) { + selection_end.Combine(first, shift); + } + + #if Debug + Line check_first; + Line check_second; + + check_first = GetLine(first.line_no); + check_second = GetLine(check_first.line_no + 1); + + Console.WriteLine("Pre-delete: Y of first line: {0}, second line: {1}", check_first.Y, check_second.Y); + #endif + + this.Delete(second); + + #if Debug + check_first = GetLine(first.line_no); + check_second = GetLine(check_first.line_no + 1); + + Console.WriteLine("Post-delete Y of first line: {0}, second line: {1}", check_first.Y, check_second.Y); + #endif + } + + // Split the line at the position into two + internal void Split(int LineNo, int pos) { + Line line; + LineTag tag; + + line = GetLine(LineNo); + tag = LineTag.FindTag(line, pos); + Split(line, tag, pos); + } + + internal void Split(Line line, int pos) { + LineTag tag; + + tag = LineTag.FindTag(line, pos); + Split(line, tag, pos); + } + + ///Split line at given tag and position into two lines + ///if more space becomes available on previous line + internal void Split(Line line, LineTag tag, int pos) { + LineTag new_tag; + Line new_line; + bool move_caret; + bool move_sel_start; + bool move_sel_end; + + move_caret = false; + move_sel_start = false; + move_sel_end = false; + +#if DEBUG + SanityCheck(); + + if (tag.End < pos) + throw new Exception ("Split called with the wrong tag"); +#endif + + // Adjust selection and cursors + if (caret.line == line && caret.pos >= pos) { + move_caret = true; + } + if (selection_start.line == line && selection_start.pos > pos) { + move_sel_start = true; + } + + if (selection_end.line == line && selection_end.pos > pos) { + move_sel_end = true; + } + + // cover the easy case first + if (pos == line.text.Length) { + Add (line.line_no + 1, String.Empty, line.alignment, tag.Font, tag.Color, line.ending); + + new_line = GetLine (line.line_no + 1); + + if (move_caret) { + caret.line = new_line; + caret.tag = new_line.tags; + caret.pos = 0; + + if (selection_visible == false) { + SetSelectionToCaret (true); + } + } + + if (move_sel_start) { + selection_start.line = new_line; + selection_start.pos = 0; + selection_start.tag = new_line.tags; + } + + if (move_sel_end) { + selection_end.line = new_line; + selection_end.pos = 0; + selection_end.tag = new_line.tags; + } + +#if DEBUG + SanityCheck (); +#endif + return; + } + + // We need to move the rest of the text into the new line + Add (line.line_no + 1, line.text.ToString (pos, line.text.Length - pos), line.alignment, tag.Font, tag.Color, line.ending); + + // Now transfer our tags from this line to the next + new_line = GetLine(line.line_no + 1); + + line.recalc = true; + new_line.recalc = true; + + //make sure that if we are at the end of a tag, we start on the begining + //of a new one, if one exists... Stops us creating an empty tag and + //make the operation easier. + if (tag.Next != null && (tag.Next.Start - 1) == pos) + tag = tag.Next; + + if ((tag.Start - 1) == pos) { + int shift; + + // We can simply break the chain and move the tag into the next line + + // if the tag we are moving is the first, create an empty tag + // for the line we are leaving behind + if (tag == line.tags) { + new_tag = new LineTag(line, 1); + new_tag.CopyFormattingFrom (tag); + line.tags = new_tag; + } + + if (tag.Previous != null) { + tag.Previous.Next = null; + } + new_line.tags = tag; + tag.Previous = null; + tag.Line = new_line; + + // Walk the list and correct the start location of the tags we just bumped into the next line + shift = tag.Start - 1; + + new_tag = tag; + while (new_tag != null) { + new_tag.Start -= shift; + new_tag.Line = new_line; + new_tag = new_tag.Next; + } + } else { + int shift; + + new_tag = new LineTag (new_line, 1); + new_tag.Next = tag.Next; + new_tag.CopyFormattingFrom (tag); + new_line.tags = new_tag; + if (new_tag.Next != null) { + new_tag.Next.Previous = new_tag; + } + tag.Next = null; + + shift = pos; + new_tag = new_tag.Next; + while (new_tag != null) { + new_tag.Start -= shift; + new_tag.Line = new_line; + new_tag = new_tag.Next; + + } + } + + if (move_caret) { + caret.line = new_line; + caret.pos = caret.pos - pos; + caret.tag = caret.line.FindTag(caret.pos); + + if (selection_visible == false) { + SetSelectionToCaret (true); + move_sel_start = false; + move_sel_end = false; + } + } + + if (move_sel_start) { + selection_start.line = new_line; + selection_start.pos = selection_start.pos - pos; + if (selection_start.Equals(selection_end)) + selection_start.tag = new_line.FindTag(selection_start.pos); + else + selection_start.tag = new_line.FindTag (selection_start.pos + 1); + } + + if (move_sel_end) { + selection_end.line = new_line; + selection_end.pos = selection_end.pos - pos; + selection_end.tag = new_line.FindTag(selection_end.pos); + } + + CharCount -= line.text.Length - pos; + line.text.Remove(pos, line.text.Length - pos); +#if DEBUG + SanityCheck (); +#endif + } + +#if DEBUG + private void SanityCheck () { + for (int i = 1; i < lines; i++) { + LineTag tag = GetLine (i).tags; + + if (tag.Start != 1) + throw new Exception ("Line doesn't start at the begining"); + + int start = 1; + tag = tag.Next; + + while (tag != null) { + if (tag.Start == start) + throw new Exception ("Empty tag!"); + + if (tag.Start < start) + throw new Exception ("Insane!!"); + + start = tag.Start; + tag = tag.Next; + } + } + } +#endif + + // Adds a line of text, with given font. + // Bumps any line at that line number that already exists down + internal void Add (int LineNo, string Text, Font font, Color color, LineEnding ending) + { + Add (LineNo, Text, alignment, font, color, ending); + } + + internal void Add (int LineNo, string Text, HorizontalAlignment align, Font font, Color color, LineEnding ending) + { + Line add; + Line line; + int line_no; + + CharCount += Text.Length; + + if (LineNo<1 || Text == null) { + if (LineNo<1) { + throw new ArgumentNullException("LineNo", "Line numbers must be positive"); + } else { + throw new ArgumentNullException("Text", "Cannot insert NULL line"); + } + } + + add = new Line (this, LineNo, Text, align, font, color, ending); + + line = document; + while (line != sentinel) { + add.parent = line; + line_no = line.line_no; + + if (LineNo > line_no) { + line = line.right; + } else if (LineNo < line_no) { + line = line.left; + } else { + // Bump existing line numbers; walk all nodes to the right of this one and increment line_no + IncrementLines(line.line_no); + line = line.left; + } + } + + add.left = sentinel; + add.right = sentinel; + + if (add.parent != null) { + if (LineNo > add.parent.line_no) { + add.parent.right = add; + } else { + add.parent.left = add; + } + } else { + // Root node + document = add; + } + + RebalanceAfterAdd(add); + + lines++; + } + + internal virtual void Clear() { + lines = 0; + CharCount = 0; + document = sentinel; + } + + public virtual object Clone() { + Document clone; + + clone = new Document(null); + + clone.lines = this.lines; + clone.document = (Line)document.Clone(); + + return clone; + } + + private void Delete (int LineNo) + { + Line line; + + if (LineNo > lines) + return; + + line = GetLine (LineNo); + + CharCount -= line.text.Length; + + DecrementLines (LineNo + 1); + Delete (line); + } + + private void Delete(Line line1) { + Line line2;// = new Line(); + Line line3; + + if ((line1.left == sentinel) || (line1.right == sentinel)) { + line3 = line1; + } else { + line3 = line1.right; + while (line3.left != sentinel) { + line3 = line3.left; + } + } + + if (line3.left != sentinel) { + line2 = line3.left; + } else { + line2 = line3.right; + } + + line2.parent = line3.parent; + if (line3.parent != null) { + if(line3 == line3.parent.left) { + line3.parent.left = line2; + } else { + line3.parent.right = line2; + } + } else { + document = line2; + } + + if (line3 != line1) { + LineTag tag; + + if (selection_start.line == line3) { + selection_start.line = line1; + } + + if (selection_end.line == line3) { + selection_end.line = line1; + } + + if (selection_anchor.line == line3) { + selection_anchor.line = line1; + } + + if (caret.line == line3) { + caret.line = line1; + } + + + line1.alignment = line3.alignment; + line1.ascent = line3.ascent; + line1.hanging_indent = line3.hanging_indent; + line1.height = line3.height; + line1.indent = line3.indent; + line1.line_no = line3.line_no; + line1.recalc = line3.recalc; + line1.right_indent = line3.right_indent; + line1.ending = line3.ending; + line1.space = line3.space; + line1.tags = line3.tags; + line1.text = line3.text; + line1.widths = line3.widths; + line1.offset = line3.offset; + + tag = line1.tags; + while (tag != null) { + tag.Line = line1; + tag = tag.Next; + } + } + + if (line3.color == LineColor.Black) + RebalanceAfterDelete(line2); + + this.lines--; + } + + // Invalidates the start line until the end of the viewstate + internal void InvalidateLinesAfter (Line start) { + owner.Invalidate (new Rectangle (0, start.Y - viewport_y, viewport_width, viewport_height - start.Y)); + } + + // Invalidate a section of the document to trigger redraw + internal void Invalidate(Line start, int start_pos, Line end, int end_pos) { + Line l1; + Line l2; + int p1; + int p2; + + if ((start == end) && (start_pos == end_pos)) { + return; + } + + if (end_pos == -1) { + end_pos = end.text.Length; + } + + // figure out what's before what so the logic below is straightforward + if (start.line_no < end.line_no) { + l1 = start; + p1 = start_pos; + + l2 = end; + p2 = end_pos; + } else if (start.line_no > end.line_no) { + l1 = end; + p1 = end_pos; + + l2 = start; + p2 = start_pos; + } else { + if (start_pos < end_pos) { + l1 = start; + p1 = start_pos; + + l2 = end; + p2 = end_pos; + } else { + l1 = end; + p1 = end_pos; + + l2 = start; + p2 = start_pos; + } + + int endpoint = (int) l1.widths [p2]; + if (p2 == l1.text.Length + 1) { + endpoint = (int) viewport_width; + } + + #if Debug + Console.WriteLine("Invaliding backwards from {0}:{1} to {2}:{3} {4}", + l1.line_no, p1, l2.line_no, p2, + new Rectangle( + (int)l1.widths[p1] + l1.X - viewport_x, + l1.Y - viewport_y, + (int)l1.widths[p2], + l1.height + ) + ); + #endif + + owner.Invalidate(new Rectangle ( + offset_x + (int)l1.widths[p1] + l1.X - viewport_x, + offset_y + l1.Y - viewport_y, + endpoint - (int) l1.widths [p1] + 1, + l1.height)); + return; + } + + #if Debug + Console.WriteLine("Invaliding from {0}:{1} to {2}:{3} Start => x={4}, y={5}, {6}x{7}", l1.line_no, p1, l2.line_no, p2, (int)l1.widths[p1] + l1.X - viewport_x, l1.Y - viewport_y, viewport_width, l1.height); + Console.WriteLine ("invalidate start line: {0} position: {1}", l1.text, p1); + #endif + + // Three invalidates: + // First line from start + owner.Invalidate(new Rectangle( + offset_x + (int)l1.widths[p1] + l1.X - viewport_x, + offset_y + l1.Y - viewport_y, + viewport_width, + l1.height)); + + + // lines inbetween + if ((l1.line_no + 1) < l2.line_no) { + int y; + + y = GetLine(l1.line_no + 1).Y; + owner.Invalidate(new Rectangle( + offset_x, + offset_y + y - viewport_y, + viewport_width, + l2.Y - y)); + + #if Debug + Console.WriteLine("Invaliding from {0}:{1} to {2}:{3} Middle => x={4}, y={5}, {6}x{7}", l1.line_no, p1, l2.line_no, p2, 0, y - viewport_y, viewport_width, l2.Y - y); + #endif + } + + + // Last line to end + owner.Invalidate(new Rectangle( + offset_x + (int)l2.widths[0] + l2.X - viewport_x, + offset_y + l2.Y - viewport_y, + (int)l2.widths[p2] + 1, + l2.height)); + + #if Debug + Console.WriteLine("Invaliding from {0}:{1} to {2}:{3} End => x={4}, y={5}, {6}x{7}", l1.line_no, p1, l2.line_no, p2, (int)l2.widths[0] + l2.X - viewport_x, l2.Y - viewport_y, (int)l2.widths[p2] + 1, l2.height); + #endif + } + + /// Select text around caret + internal void ExpandSelection(CaretSelection mode, bool to_caret) { + if (to_caret) { + // We're expanding the selection to the caret position + switch(mode) { + case CaretSelection.Line: { + // Invalidate the selection delta + if (caret > selection_prev) { + Invalidate(selection_prev.line, 0, caret.line, caret.line.text.Length); + } else { + Invalidate(selection_prev.line, selection_prev.line.text.Length, caret.line, 0); + } + + if (caret.line.line_no <= selection_anchor.line.line_no) { + selection_start.line = caret.line; + selection_start.tag = caret.line.tags; + selection_start.pos = 0; + + selection_end.line = selection_anchor.line; + selection_end.tag = selection_anchor.tag; + selection_end.pos = selection_anchor.pos; + + selection_end_anchor = true; + } else { + selection_start.line = selection_anchor.line; + selection_start.pos = selection_anchor.height; + selection_start.tag = selection_anchor.line.FindTag(selection_anchor.height + 1); + + selection_end.line = caret.line; + selection_end.tag = caret.line.tags; + selection_end.pos = caret.line.text.Length; + + selection_end_anchor = false; + } + selection_prev.line = caret.line; + selection_prev.tag = caret.tag; + selection_prev.pos = caret.pos; + + break; + } + + case CaretSelection.Word: { + int start_pos; + int end_pos; + + start_pos = FindWordSeparator(caret.line, caret.pos, false); + end_pos = FindWordSeparator(caret.line, caret.pos, true); + + + // Invalidate the selection delta + if (caret > selection_prev) { + Invalidate(selection_prev.line, selection_prev.pos, caret.line, end_pos); + } else { + Invalidate(selection_prev.line, selection_prev.pos, caret.line, start_pos); + } + if (caret < selection_anchor) { + selection_start.line = caret.line; + selection_start.tag = caret.line.FindTag(start_pos + 1); + selection_start.pos = start_pos; + + selection_end.line = selection_anchor.line; + selection_end.tag = selection_anchor.tag; + selection_end.pos = selection_anchor.pos; + + selection_prev.line = caret.line; + selection_prev.tag = caret.tag; + selection_prev.pos = start_pos; + + selection_end_anchor = true; + } else { + selection_start.line = selection_anchor.line; + selection_start.pos = selection_anchor.height; + selection_start.tag = selection_anchor.line.FindTag(selection_anchor.height + 1); + + selection_end.line = caret.line; + selection_end.tag = caret.line.FindTag(end_pos); + selection_end.pos = end_pos; + + selection_prev.line = caret.line; + selection_prev.tag = caret.tag; + selection_prev.pos = end_pos; + + selection_end_anchor = false; + } + break; + } + + case CaretSelection.Position: { + SetSelectionToCaret(false); + return; + } + } + } else { + // We're setting the selection 'around' the caret position + switch(mode) { + case CaretSelection.Line: { + this.Invalidate(caret.line, 0, caret.line, caret.line.text.Length); + + selection_start.line = caret.line; + selection_start.tag = caret.line.tags; + selection_start.pos = 0; + + selection_end.line = caret.line; + selection_end.pos = caret.line.text.Length; + selection_end.tag = caret.line.FindTag(selection_end.pos); + + selection_anchor.line = selection_end.line; + selection_anchor.tag = selection_end.tag; + selection_anchor.pos = selection_end.pos; + selection_anchor.height = 0; + + selection_prev.line = caret.line; + selection_prev.tag = caret.tag; + selection_prev.pos = caret.pos; + + this.selection_end_anchor = true; + + break; + } + + case CaretSelection.Word: { + int start_pos; + int end_pos; + + start_pos = FindWordSeparator(caret.line, caret.pos, false); + end_pos = FindWordSeparator(caret.line, caret.pos, true); + + this.Invalidate(selection_start.line, start_pos, caret.line, end_pos); + + selection_start.line = caret.line; + selection_start.tag = caret.line.FindTag(start_pos + 1); + selection_start.pos = start_pos; + + selection_end.line = caret.line; + selection_end.tag = caret.line.FindTag(end_pos); + selection_end.pos = end_pos; + + selection_anchor.line = selection_end.line; + selection_anchor.tag = selection_end.tag; + selection_anchor.pos = selection_end.pos; + selection_anchor.height = start_pos; + + selection_prev.line = caret.line; + selection_prev.tag = caret.tag; + selection_prev.pos = caret.pos; + + this.selection_end_anchor = true; + + break; + } + } + } + + SetSelectionVisible (!(selection_start == selection_end)); + } + + internal void SetSelectionToCaret(bool start) { + if (start) { + // Invalidate old selection; selection is being reset to empty + this.Invalidate(selection_start.line, selection_start.pos, selection_end.line, selection_end.pos); + + selection_start.line = caret.line; + selection_start.tag = caret.tag; + selection_start.pos = caret.pos; + + // start always also selects end + selection_end.line = caret.line; + selection_end.tag = caret.tag; + selection_end.pos = caret.pos; + + selection_anchor.line = caret.line; + selection_anchor.tag = caret.tag; + selection_anchor.pos = caret.pos; + } else { + // Invalidate from previous end to caret (aka new end) + if (selection_end_anchor) { + if (selection_start != caret) { + this.Invalidate(selection_start.line, selection_start.pos, caret.line, caret.pos); + } + } else { + if (selection_end != caret) { + this.Invalidate(selection_end.line, selection_end.pos, caret.line, caret.pos); + } + } + + if (caret < selection_anchor) { + selection_start.line = caret.line; + selection_start.tag = caret.tag; + selection_start.pos = caret.pos; + + selection_end.line = selection_anchor.line; + selection_end.tag = selection_anchor.tag; + selection_end.pos = selection_anchor.pos; + + selection_end_anchor = true; + } else { + selection_start.line = selection_anchor.line; + selection_start.tag = selection_anchor.tag; + selection_start.pos = selection_anchor.pos; + + selection_end.line = caret.line; + selection_end.tag = caret.tag; + selection_end.pos = caret.pos; + + selection_end_anchor = false; + } + } + + SetSelectionVisible (!(selection_start == selection_end)); + } + + internal void SetSelection(Line start, int start_pos, Line end, int end_pos) { + if (selection_visible) { + Invalidate(selection_start.line, selection_start.pos, selection_end.line, selection_end.pos); + } + + if ((end.line_no < start.line_no) || ((end == start) && (end_pos <= start_pos))) { + selection_start.line = end; + selection_start.tag = LineTag.FindTag(end, end_pos); + selection_start.pos = end_pos; + + selection_end.line = start; + selection_end.tag = LineTag.FindTag(start, start_pos); + selection_end.pos = start_pos; + + selection_end_anchor = true; + } else { + selection_start.line = start; + selection_start.tag = LineTag.FindTag(start, start_pos); + selection_start.pos = start_pos; + + selection_end.line = end; + selection_end.tag = LineTag.FindTag(end, end_pos); + selection_end.pos = end_pos; + + selection_end_anchor = false; + } + + selection_anchor.line = start; + selection_anchor.tag = selection_start.tag; + selection_anchor.pos = start_pos; + + if (((start == end) && (start_pos == end_pos)) || start == null || end == null) { + SetSelectionVisible (false); + } else { + SetSelectionVisible (true); + Invalidate(selection_start.line, selection_start.pos, selection_end.line, selection_end.pos); + } + } + + internal void SetSelectionStart(Line start, int start_pos, bool invalidate) { + // Invalidate from the previous to the new start pos + if (invalidate) + Invalidate(selection_start.line, selection_start.pos, start, start_pos); + + selection_start.line = start; + selection_start.pos = start_pos; + selection_start.tag = LineTag.FindTag(start, start_pos); + + selection_anchor.line = start; + selection_anchor.pos = start_pos; + selection_anchor.tag = selection_start.tag; + + selection_end_anchor = false; + + + if ((selection_end.line != selection_start.line) || (selection_end.pos != selection_start.pos)) { + SetSelectionVisible (true); + } else { + SetSelectionVisible (false); + } + + if (invalidate) + Invalidate(selection_start.line, selection_start.pos, selection_end.line, selection_end.pos); + } + + internal void SetSelectionStart(int character_index, bool invalidate) { + Line line; + LineTag tag; + int pos; + + if (character_index < 0) { + return; + } + + CharIndexToLineTag(character_index, out line, out tag, out pos); + SetSelectionStart(line, pos, invalidate); + } + + internal void SetSelectionEnd(Line end, int end_pos, bool invalidate) { + + if (end == selection_end.line && end_pos == selection_start.pos) { + selection_anchor.line = selection_start.line; + selection_anchor.tag = selection_start.tag; + selection_anchor.pos = selection_start.pos; + + selection_end.line = selection_start.line; + selection_end.tag = selection_start.tag; + selection_end.pos = selection_start.pos; + + selection_end_anchor = false; + } else if ((end.line_no < selection_anchor.line.line_no) || ((end == selection_anchor.line) && (end_pos <= selection_anchor.pos))) { + selection_start.line = end; + selection_start.tag = LineTag.FindTag(end, end_pos); + selection_start.pos = end_pos; + + selection_end.line = selection_anchor.line; + selection_end.tag = selection_anchor.tag; + selection_end.pos = selection_anchor.pos; + + selection_end_anchor = true; + } else { + selection_start.line = selection_anchor.line; + selection_start.tag = selection_anchor.tag; + selection_start.pos = selection_anchor.pos; + + selection_end.line = end; + selection_end.tag = LineTag.FindTag(end, end_pos); + selection_end.pos = end_pos; + + selection_end_anchor = false; + } + + if ((selection_end.line != selection_start.line) || (selection_end.pos != selection_start.pos)) { + SetSelectionVisible (true); + if (invalidate) + Invalidate(selection_start.line, selection_start.pos, selection_end.line, selection_end.pos); + } else { + SetSelectionVisible (false); + // ?? Do I need to invalidate here, tests seem to work without it, but I don't think they should :-s + } + } + + internal void SetSelectionEnd(int character_index, bool invalidate) { + Line line; + LineTag tag; + int pos; + + if (character_index < 0) { + return; + } + + CharIndexToLineTag(character_index, out line, out tag, out pos); + SetSelectionEnd(line, pos, invalidate); + } + + internal void SetSelection(Line start, int start_pos) { + if (selection_visible) { + Invalidate(selection_start.line, selection_start.pos, selection_end.line, selection_end.pos); + } + + selection_start.line = start; + selection_start.pos = start_pos; + selection_start.tag = LineTag.FindTag(start, start_pos); + + selection_end.line = start; + selection_end.tag = selection_start.tag; + selection_end.pos = start_pos; + + selection_anchor.line = start; + selection_anchor.tag = selection_start.tag; + selection_anchor.pos = start_pos; + + selection_end_anchor = false; + SetSelectionVisible (false); + } + + internal void InvalidateSelectionArea() { + Invalidate (selection_start.line, selection_start.pos, selection_end.line, selection_end.pos); + } + + // Return the current selection, as string + internal string GetSelection() { + // We return String.Empty if there is no selection + if ((selection_start.pos == selection_end.pos) && (selection_start.line == selection_end.line)) { + return string.Empty; + } + + if (selection_start.line == selection_end.line) { + return selection_start.line.text.ToString (selection_start.pos, selection_end.pos - selection_start.pos); + } else { + StringBuilder sb; + int i; + int start; + int end; + + sb = new StringBuilder(); + start = selection_start.line.line_no; + end = selection_end.line.line_no; + + sb.Append(selection_start.line.text.ToString(selection_start.pos, selection_start.line.text.Length - selection_start.pos)); + + if ((start + 1) < end) { + for (i = start + 1; i < end; i++) { + sb.Append(GetLine(i).text.ToString()); + } + } + + sb.Append(selection_end.line.text.ToString(0, selection_end.pos)); + + return sb.ToString(); + } + } + + internal void ReplaceSelection(string s, bool select_new) { + int i; + + int selection_start_pos = LineTagToCharIndex (selection_start.line, selection_start.pos); + SuspendRecalc (); + + // First, delete any selected text + if ((selection_start.pos != selection_end.pos) || (selection_start.line != selection_end.line)) { + if (selection_start.line == selection_end.line) { + undo.RecordDeleteString (selection_start.line, selection_start.pos, selection_end.line, selection_end.pos); + + DeleteChars (selection_start.line, selection_start.pos, selection_end.pos - selection_start.pos); + + // The tag might have been removed, we need to recalc it + selection_start.tag = selection_start.line.FindTag(selection_start.pos + 1); + } else { + int start; + int end; + + start = selection_start.line.line_no; + end = selection_end.line.line_no; + + undo.RecordDeleteString (selection_start.line, selection_start.pos, selection_end.line, selection_end.pos); + + InvalidateLinesAfter(selection_start.line); + + // Delete first line + DeleteChars (selection_start.line, selection_start.pos, selection_start.line.text.Length - selection_start.pos); + selection_start.line.recalc = true; + + // Delete last line + DeleteChars(selection_end.line, 0, selection_end.pos); + + start++; + if (start < end) { + for (i = end - 1; i >= start; i--) { + Delete(i); + } + } + + // BIG FAT WARNING - selection_end.line might be stale due + // to the above Delete() call. DONT USE IT before hitting the end of this method! + + // Join start and end + Combine(selection_start.line.line_no, start); + } + } + + + Insert(selection_start.line, selection_start.pos, false, s); + undo.RecordInsertString (selection_start.line, selection_start.pos, s); + ResumeRecalc (false); + + Line begin_update_line = selection_start.line; + int begin_update_pos = selection_start.pos; + + if (!select_new) { + CharIndexToLineTag(selection_start_pos + s.Length, out selection_start.line, + out selection_start.tag, out selection_start.pos); + + selection_end.line = selection_start.line; + selection_end.pos = selection_start.pos; + selection_end.tag = selection_start.tag; + selection_anchor.line = selection_start.line; + selection_anchor.pos = selection_start.pos; + selection_anchor.tag = selection_start.tag; + + SetSelectionVisible (false); + } else { + CharIndexToLineTag(selection_start_pos, out selection_start.line, + out selection_start.tag, out selection_start.pos); + + CharIndexToLineTag(selection_start_pos + s.Length, out selection_end.line, + out selection_end.tag, out selection_end.pos); + + selection_anchor.line = selection_start.line; + selection_anchor.pos = selection_start.pos; + selection_anchor.tag = selection_start.tag; + + SetSelectionVisible (true); + } + + PositionCaret (selection_start.line, selection_start.pos); + UpdateView (begin_update_line, selection_end.line.line_no - begin_update_line.line_no, begin_update_pos); + } + + internal void CharIndexToLineTag(int index, out Line line_out, out LineTag tag_out, out int pos) { + Line line; + LineTag tag; + int i; + int chars; + int start; + + chars = 0; + + for (i = 1; i <= lines; i++) { + line = GetLine(i); + + start = chars; + chars += line.text.Length; + + if (index <= chars) { + // we found the line + tag = line.tags; + + while (tag != null) { + if (index < (start + tag.Start + tag.Length - 1)) { + line_out = line; + tag_out = LineTag.GetFinalTag (tag); + pos = index - start; + return; + } + if (tag.Next == null) { + Line next_line; + + next_line = GetLine(line.line_no + 1); + + if (next_line != null) { + line_out = next_line; + tag_out = LineTag.GetFinalTag (next_line.tags); + pos = 0; + return; + } else { + line_out = line; + tag_out = LineTag.GetFinalTag (tag); + pos = line_out.text.Length; + return; + } + } + tag = tag.Next; + } + } + } + + line_out = GetLine(lines); + tag = line_out.tags; + while (tag.Next != null) { + tag = tag.Next; + } + tag_out = tag; + pos = line_out.text.Length; + } + + internal int LineTagToCharIndex(Line line, int pos) { + int i; + int length; + + // Count first and last line + length = 0; + + // Count the lines in the middle + + for (i = 1; i < line.line_no; i++) { + length += GetLine(i).text.Length; + } + + length += pos; + + return length; + } + + internal int SelectionLength() { + if ((selection_start.pos == selection_end.pos) && (selection_start.line == selection_end.line)) { + return 0; + } + + if (selection_start.line == selection_end.line) { + return selection_end.pos - selection_start.pos; + } else { + int i; + int start; + int end; + int length; + + // Count first and last line + length = selection_start.line.text.Length - selection_start.pos + selection_end.pos + crlf_size; + + // Count the lines in the middle + start = selection_start.line.line_no + 1; + end = selection_end.line.line_no; + + if (start < end) { + for (i = start; i < end; i++) { + Line line = GetLine (i); + length += line.text.Length + LineEndingLength (line.ending); + } + } + + return length; + } + + + } + + + // UIA: Method used via reflection in TextRangeProvider + + /// Give it a Line number and it returns the Line object at with that line number + internal Line GetLine(int LineNo) { + Line line = document; + + while (line != sentinel) { + if (LineNo == line.line_no) { + return line; + } else if (LineNo < line.line_no) { + line = line.left; + } else { + line = line.right; + } + } + + return null; + } + + /// Retrieve the previous tag; walks line boundaries + internal LineTag PreviousTag(LineTag tag) { + Line l; + + if (tag.Previous != null) { + return tag.Previous; + } + + // Next line + if (tag.Line.line_no == 1) { + return null; + } + + l = GetLine(tag.Line.line_no - 1); + if (l != null) { + LineTag t; + + t = l.tags; + while (t.Next != null) { + t = t.Next; + } + return t; + } + + return null; + } + + /// Retrieve the next tag; walks line boundaries + internal LineTag NextTag(LineTag tag) { + Line l; + + if (tag.Next != null) { + return tag.Next; + } + + // Next line + l = GetLine(tag.Line.line_no + 1); + if (l != null) { + return l.tags; + } + + return null; + } + + internal Line ParagraphStart(Line line) { + Line lastline = line; + do { + if (line.line_no <= 1) + break; + + line = lastline; + lastline = GetLine (line.line_no - 1); + } while (lastline.ending == LineEnding.Wrap); + + return line; + } + + internal Line ParagraphEnd(Line line) { + Line l; + + while (line.ending == LineEnding.Wrap) { + l = GetLine(line.line_no + 1); + if ((l == null) || (l.ending != LineEnding.Wrap)) { + break; + } + line = l; + } + return line; + } + + /// Give it a pixel offset coordinate and it returns the Line covering that are (offset + /// is either X or Y depending on if we are multiline + /// + internal Line GetLineByPixel (int offset, bool exact) + { + Line line = document; + Line last = null; + + if (multiline) { + while (line != sentinel) { + last = line; + if ((offset >= line.Y) && (offset < (line.Y+line.height))) { + return line; + } else if (offset < line.Y) { + line = line.left; + } else { + line = line.right; + } + } + } else { + while (line != sentinel) { + last = line; + if ((offset >= line.X) && (offset < (line.X + line.Width))) + return line; + else if (offset < line.X) + line = line.left; + else + line = line.right; + } + } + + if (exact) { + return null; + } + return last; + } + + // UIA: Method used via reflection in TextProviderBehavior + + // Give it x/y pixel coordinates and it returns the Tag at that position + internal LineTag FindCursor (int x, int y, out int index) + { + Line line; + + x -= offset_x; + y -= offset_y; + + line = GetLineByPixel (multiline ? y : x, false); + + LineTag tag = line.GetTag (x); + + if (tag.Length == 0 && tag.Start == 1) + index = 0; + else + index = tag.GetCharIndex (x - line.align_shift); + + return tag; + } + + /// Format area of document in specified font and color + /// 1-based start position on start_line + /// 1-based end position on end_line + internal void FormatText (Line start_line, int start_pos, Line end_line, int end_pos, Font font, + Color color, Color back_color, FormatSpecified specified) + { + Line l; + + // First, format the first line + if (start_line != end_line) { + // First line + LineTag.FormatText(start_line, start_pos, start_line.text.Length - start_pos + 1, font, color, back_color, specified); + + // Format last line + LineTag.FormatText(end_line, 1, end_pos, font, color, back_color, specified); + + // Now all the lines inbetween + for (int i = start_line.line_no + 1; i < end_line.line_no; i++) { + l = GetLine(i); + LineTag.FormatText(l, 1, l.text.Length, font, color, back_color, specified); + } + } else { + // Special case, single line + LineTag.FormatText(start_line, start_pos, end_pos - start_pos, font, color, back_color, specified); + + if ((end_pos - start_pos) == 0 && CaretTag.Length != 0) + CaretTag = CaretTag.Next; + } + } + + internal void RecalculateAlignments () + { + Line line; + int line_no; + + line_no = 1; + + + + while (line_no <= lines) { + line = GetLine(line_no); + + if (line != null) { + switch (line.alignment) { + case HorizontalAlignment.Left: + line.align_shift = 0; + break; + case HorizontalAlignment.Center: + line.align_shift = (viewport_width - (int)line.widths[line.text.Length]) / 2; + break; + case HorizontalAlignment.Right: + line.align_shift = viewport_width - (int)line.widths[line.text.Length] - right_margin; + break; + } + } + + line_no++; + } + return; + } + + /// Calculate formatting for the whole document + internal bool RecalculateDocument(Graphics g) { + return RecalculateDocument(g, 1, this.lines, false); + } + + /// Calculate formatting starting at a certain line + internal bool RecalculateDocument(Graphics g, int start) { + return RecalculateDocument(g, start, this.lines, false); + } + + /// Calculate formatting within two given line numbers + internal bool RecalculateDocument(Graphics g, int start, int end) { + return RecalculateDocument(g, start, end, false); + } + + /// With optimize on, returns true if line heights changed + internal bool RecalculateDocument(Graphics g, int start, int end, bool optimize) { + Line line; + int line_no; + int offset; + int new_width; + bool changed; + int shift; + + if (recalc_suspended > 0) { + recalc_pending = true; + recalc_start = Math.Min (recalc_start, start); + recalc_end = Math.Max (recalc_end, end); + recalc_optimize = optimize; + return false; + } + + // Fixup the positions, they can go kinda nuts + // (this is suspend and resume recalc - they set them to 1 and max) + start = Math.Max (start, 1); + end = Math.Min (end, lines); + + offset = GetLine(start).offset; + line_no = start; + new_width = 0; + shift = this.lines; + if (!optimize) { + changed = true; // We always return true if we run non-optimized + } else { + changed = false; + } + + while (line_no <= (end + this.lines - shift)) { + line = GetLine(line_no++); + line.offset = offset; + + // if we are not calculating a password + if (!calc_pass) { + if (!optimize) { + line.RecalculateLine(g, this); + } else { + if (line.recalc && line.RecalculateLine(g, this)) { + changed = true; + // If the height changed, all subsequent lines change + end = this.lines; + shift = this.lines; + } + } + } else { + if (!optimize) { + line.RecalculatePasswordLine(g, this); + } else { + if (line.recalc && line.RecalculatePasswordLine(g, this)) { + changed = true; + // If the height changed, all subsequent lines change + end = this.lines; + shift = this.lines; + } + } + } + + if (line.widths[line.text.Length] > new_width) { + new_width = (int)line.widths[line.text.Length]; + } + + // Calculate alignment + if (line.alignment != HorizontalAlignment.Left) { + if (line.alignment == HorizontalAlignment.Center) { + line.align_shift = (viewport_width - (int)line.widths[line.text.Length]) / 2; + } else { + line.align_shift = viewport_width - (int)line.widths[line.text.Length] - 1; + } + } + + if (multiline) + offset += line.height; + else + offset += (int) line.widths [line.text.Length]; + + if (line_no > lines) { + break; + } + } + + if (document_x != new_width) { + document_x = new_width; + if (WidthChanged != null) { + WidthChanged(this, null); + } + } + + RecalculateAlignments(); + + line = GetLine(lines); + + if (document_y != line.Y + line.height) { + document_y = line.Y + line.height; + if (HeightChanged != null) { + HeightChanged(this, null); + } + } + + // scan for links and tell us if its all + // changed, so we can update everything + if (EnableLinks) + ScanForLinks (start, end, ref changed); + + UpdateCaret(); + return changed; + } + + internal int Size() { + return lines; + } + + private void owner_HandleCreated(object sender, EventArgs e) { + RecalculateDocument(owner.CreateGraphicsInternal()); + AlignCaret(); + } + + private void owner_VisibleChanged(object sender, EventArgs e) { + if (owner.Visible) { + RecalculateDocument(owner.CreateGraphicsInternal()); + } + } + + internal static bool IsWordSeparator (char ch) + { + switch (ch) { + case ' ': + case '\t': + case '(': + case ')': + case '\r': + case '\n': + return true; + default: + return false; + } + } + + internal int FindWordSeparator(Line line, int pos, bool forward) { + int len; + + len = line.text.Length; + + if (forward) { + for (int i = pos + 1; i < len; i++) { + if (IsWordSeparator(line.Text[i])) { + return i + 1; + } + } + return len; + } else { + for (int i = pos - 1; i > 0; i--) { + if (IsWordSeparator(line.Text[i - 1])) { + return i; + } + } + return 0; + } + } + + /* Search document for text */ + internal bool FindChars(char[] chars, Marker start, Marker end, out Marker result) { + Line line; + int line_no; + int pos; + int line_len; + + // Search for occurence of any char in the chars array + result = new Marker(); + + line = start.line; + line_no = start.line.line_no; + pos = start.pos; + while (line_no <= end.line.line_no) { + line_len = line.text.Length; + while (pos < line_len) { + for (int i = 0; i < chars.Length; i++) { + if (line.text[pos] == chars[i]) { + // Special case + if ((line.line_no == end.line.line_no) && (pos >= end.pos)) { + return false; + } + + result.line = line; + result.pos = pos; + return true; + } + } + pos++; + } + + pos = 0; + line_no++; + line = GetLine(line_no); + } + + return false; + } + + // This version does not build one big string for searching, instead it handles + // line-boundaries, which is faster and less memory intensive + // FIXME - Depending on culture stuff we might have to create a big string and use culturespecific + // search stuff and change it to accept and return positions instead of Markers (which would match + // RichTextBox behaviour better but would be inconsistent with the rest of TextControl) + internal bool Find(string search, Marker start, Marker end, out Marker result, RichTextBoxFinds options) { + Marker last; + string search_string; + Line line; + int line_no; + int pos; + int line_len; + int current; + bool word; + bool word_option; + bool ignore_case; + bool reverse; + char c; + + result = new Marker(); + word_option = ((options & RichTextBoxFinds.WholeWord) != 0); + ignore_case = ((options & RichTextBoxFinds.MatchCase) == 0); + reverse = ((options & RichTextBoxFinds.Reverse) != 0); + + line = start.line; + line_no = start.line.line_no; + pos = start.pos; + current = 0; + + // Prep our search string, lowercasing it if we do case-independent matching + if (ignore_case) { + StringBuilder sb; + sb = new StringBuilder(search); + for (int i = 0; i < sb.Length; i++) { + sb[i] = Char.ToLower(sb[i]); + } + search_string = sb.ToString(); + } else { + search_string = search; + } + + // We need to check if the character before our start position is a wordbreak + if (word_option) { + if (line_no == 1) { + if ((pos == 0) || (IsWordSeparator(line.text[pos - 1]))) { + word = true; + } else { + word = false; + } + } else { + if (pos > 0) { + if (IsWordSeparator(line.text[pos - 1])) { + word = true; + } else { + word = false; + } + } else { + // Need to check the end of the previous line + Line prev_line; + + prev_line = GetLine(line_no - 1); + if (prev_line.ending == LineEnding.Wrap) { + if (IsWordSeparator(prev_line.text[prev_line.text.Length - 1])) { + word = true; + } else { + word = false; + } + } else { + word = true; + } + } + } + } else { + word = false; + } + + // To avoid duplication of this loop with reverse logic, we search + // through the document, remembering the last match and when returning + // report that last remembered match + + last = new Marker(); + last.height = -1; // Abused - we use it to track change + + while (line_no <= end.line.line_no) { + if (line_no != end.line.line_no) { + line_len = line.text.Length; + } else { + line_len = end.pos; + } + + while (pos < line_len) { + + if (word_option && (current == search_string.Length)) { + if (IsWordSeparator(line.text[pos])) { + if (!reverse) { + goto FindFound; + } else { + last = result; + current = 0; + } + } else { + current = 0; + } + } + + if (ignore_case) { + c = Char.ToLower(line.text[pos]); + } else { + c = line.text[pos]; + } + + if (c == search_string[current]) { + + if (current == 0) { + result.line = line; + result.pos = pos; + } + if (!word_option || (word_option && (word || (current > 0)))) { + current++; + } + + if (!word_option && (current == search_string.Length)) { + if (!reverse) { + goto FindFound; + } else { + last = result; + current = 0; + } + } + } else { + current = 0; + } + pos++; + + if (!word_option) { + continue; + } + + if (IsWordSeparator(c)) { + word = true; + } else { + word = false; + } + } + + if (word_option) { + // Mark that we just saw a word boundary + if (line.ending != LineEnding.Wrap || line.line_no == lines - 1) { + word = true; + } + + if (current == search_string.Length) { + if (word) { + if (!reverse) { + goto FindFound; + } else { + last = result; + current = 0; + } + } else { + current = 0; + } + } + } + + pos = 0; + line_no++; + line = GetLine(line_no); + } + + if (reverse) { + if (last.height != -1) { + result = last; + return true; + } + } + + return false; + + FindFound: + if (!reverse) { +// if ((line.line_no == end.line.line_no) && (pos >= end.pos)) { +// return false; +// } + return true; + } + + result = last; + return true; + + } + + /* Marker stuff */ + internal void GetMarker(out Marker mark, bool start) { + mark = new Marker(); + + if (start) { + mark.line = GetLine(1); + mark.tag = mark.line.tags; + mark.pos = 0; + } else { + mark.line = GetLine(lines); + mark.tag = mark.line.tags; + while (mark.tag.Next != null) { + mark.tag = mark.tag.Next; + } + mark.pos = mark.line.text.Length; + } + } + #endregion // Internal Methods + + #region Events + internal event EventHandler CaretMoved; + internal event EventHandler WidthChanged; + internal event EventHandler HeightChanged; + internal event EventHandler LengthChanged; + internal event EventHandler UIASelectionChanged; + #endregion // Events + + #region Administrative + public IEnumerator GetEnumerator() { + // FIXME + return null; + } + + public override bool Equals(object obj) { + if (obj == null) { + return false; + } + + if (!(obj is Document)) { + return false; + } + + if (obj == this) { + return true; + } + + if (ToString().Equals(((Document)obj).ToString())) { + return true; + } + + return false; + } + + public override int GetHashCode() { + return document_id; + } + + public override string ToString() { + return "document " + this.document_id; + } + #endregion // Administrative + } + + internal class PictureTag : LineTag { + + internal RTF.Picture picture; + + internal PictureTag (Line line, int start, RTF.Picture picture) : base (line, start) + { + this.picture = picture; + } + + public override bool IsTextTag { + get { return false; } + } + + public override SizeF SizeOfPosition (Graphics dc, int pos) + { + return picture.Size; + } + + internal override int MaxHeight () + { + return (int) (picture.Height + 0.5F); + } + + public override void Draw (Graphics dc, Color color, float xoff, float y, int start, int end) + { + picture.DrawImage (dc, xoff + Line.widths [start], y, false); + } + + public override void Draw (Graphics dc, Color color, float xoff, float y, int start, int end, string text) + { + picture.DrawImage (dc, xoff + + Line.widths [start], y, false); + } + + public override string Text () + { + return "I"; + } + } + + internal class UndoManager { + + internal enum ActionType { + + Typing, + + // This is basically just cut & paste + InsertString, + DeleteString, + + UserActionBegin, + UserActionEnd + } + + internal class Action { + internal ActionType type; + internal int line_no; + internal int pos; + internal object data; + } + + #region Local Variables + private Document document; + private Stack undo_actions; + private Stack redo_actions; + + //private int caret_line; + //private int caret_pos; + + // When performing an action, we lock the queue, so that the action can't be undone + private bool locked; + #endregion // Local Variables + + #region Constructors + internal UndoManager (Document document) + { + this.document = document; + undo_actions = new Stack (50); + redo_actions = new Stack (50); + } + #endregion // Constructors + + #region Properties + internal bool CanUndo { + get { return undo_actions.Count > 0; } + } + + internal bool CanRedo { + get { return redo_actions.Count > 0; } + } + + internal string UndoActionName { + get { + foreach (Action action in undo_actions) { + if (action.type == ActionType.UserActionBegin) + return (string) action.data; + if (action.type == ActionType.Typing) + return String.Format ("Typing"); + } + return String.Empty; + } + } + + internal string RedoActionName { + get { + foreach (Action action in redo_actions) { + if (action.type == ActionType.UserActionBegin) + return (string) action.data; + if (action.type == ActionType.Typing) + return String.Format ("Typing"); + } + return String.Empty; + } + } + #endregion // Properties + + #region Internal Methods + internal void Clear () + { + undo_actions.Clear(); + redo_actions.Clear(); + } + + internal bool Undo () + { + Action action; + bool user_action_finished = false; + + if (undo_actions.Count == 0) + return false; + + locked = true; + do { + Line start; + action = (Action) undo_actions.Pop (); + + // Put onto redo stack + redo_actions.Push(action); + + // Do the thing + switch(action.type) { + + case ActionType.UserActionBegin: + user_action_finished = true; + break; + + case ActionType.UserActionEnd: + // noop + break; + + case ActionType.InsertString: + start = document.GetLine (action.line_no); + document.SuspendUpdate (); + document.DeleteMultiline (start, action.pos, ((string) action.data).Length + 1); + document.PositionCaret (start, action.pos); + document.SetSelectionToCaret (true); + document.ResumeUpdate (true); + break; + + case ActionType.Typing: + start = document.GetLine (action.line_no); + document.SuspendUpdate (); + document.DeleteMultiline (start, action.pos, ((StringBuilder) action.data).Length); + document.PositionCaret (start, action.pos); + document.SetSelectionToCaret (true); + document.ResumeUpdate (true); + + // This is an open ended operation, so only a single typing operation can be undone at once + user_action_finished = true; + break; + + case ActionType.DeleteString: + start = document.GetLine (action.line_no); + document.SuspendUpdate (); + Insert (start, action.pos, (Line) action.data, true); + document.ResumeUpdate (true); + break; + } + } while (!user_action_finished && undo_actions.Count > 0); + + locked = false; + + return true; + } + + internal bool Redo () + { + Action action; + bool user_action_finished = false; + + if (redo_actions.Count == 0) + return false; + + locked = true; + do { + Line start; + int start_index; + + action = (Action) redo_actions.Pop (); + undo_actions.Push (action); + + switch (action.type) { + + case ActionType.UserActionBegin: + // Noop + break; + + case ActionType.UserActionEnd: + user_action_finished = true; + break; + + case ActionType.InsertString: + start = document.GetLine (action.line_no); + document.SuspendUpdate (); + start_index = document.LineTagToCharIndex (start, action.pos); + document.InsertString (start, action.pos, (string) action.data); + document.CharIndexToLineTag (start_index + ((string) action.data).Length, + out document.caret.line, out document.caret.tag, + out document.caret.pos); + document.UpdateCaret (); + document.SetSelectionToCaret (true); + document.ResumeUpdate (true); + break; + + case ActionType.Typing: + start = document.GetLine (action.line_no); + document.SuspendUpdate (); + start_index = document.LineTagToCharIndex (start, action.pos); + document.InsertString (start, action.pos, ((StringBuilder) action.data).ToString ()); + document.CharIndexToLineTag (start_index + ((StringBuilder) action.data).Length, + out document.caret.line, out document.caret.tag, + out document.caret.pos); + document.UpdateCaret (); + document.SetSelectionToCaret (true); + document.ResumeUpdate (true); + + // This is an open ended operation, so only a single typing operation can be undone at once + user_action_finished = true; + break; + + case ActionType.DeleteString: + start = document.GetLine (action.line_no); + document.SuspendUpdate (); + document.DeleteMultiline (start, action.pos, ((Line) action.data).text.Length); + document.PositionCaret (start, action.pos); + document.SetSelectionToCaret (true); + document.ResumeUpdate (true); + + break; + } + } while (!user_action_finished && redo_actions.Count > 0); + + locked = false; + + return true; + } + #endregion // Internal Methods + + #region Private Methods + + public void BeginUserAction (string name) + { + if (locked) + return; + + // Nuke the redo queue + redo_actions.Clear (); + + Action ua = new Action (); + ua.type = ActionType.UserActionBegin; + ua.data = name; + + undo_actions.Push (ua); + } + + public void EndUserAction () + { + if (locked) + return; + + Action ua = new Action (); + ua.type = ActionType.UserActionEnd; + + undo_actions.Push (ua); + } + + // start_pos, end_pos = 1 based + public void RecordDeleteString (Line start_line, int start_pos, Line end_line, int end_pos) + { + if (locked) + return; + + // Nuke the redo queue + redo_actions.Clear (); + + Action a = new Action (); + + // We cant simply store the string, because then formatting would be lost + a.type = ActionType.DeleteString; + a.line_no = start_line.line_no; + a.pos = start_pos; + a.data = Duplicate (start_line, start_pos, end_line, end_pos); + + undo_actions.Push(a); + } + + public void RecordInsertString (Line line, int pos, string str) + { + if (locked || str.Length == 0) + return; + + // Nuke the redo queue + redo_actions.Clear (); + + Action a = new Action (); + + a.type = ActionType.InsertString; + a.data = str; + a.line_no = line.line_no; + a.pos = pos; + + undo_actions.Push (a); + } + + public void RecordTyping (Line line, int pos, char ch) + { + if (locked) + return; + + // Nuke the redo queue + redo_actions.Clear (); + + Action a = null; + + if (undo_actions.Count > 0) + a = (Action) undo_actions.Peek (); + + if (a == null || a.type != ActionType.Typing) { + a = new Action (); + a.type = ActionType.Typing; + a.data = new StringBuilder (); + a.line_no = line.line_no; + a.pos = pos; + + undo_actions.Push (a); + } + + StringBuilder data = (StringBuilder) a.data; + data.Append (ch); + } + + // start_pos = 1-based + // end_pos = 1-based + public Line Duplicate(Line start_line, int start_pos, Line end_line, int end_pos) + { + Line ret; + Line line; + Line current; + LineTag tag; + LineTag current_tag; + int start; + int end; + int tag_start; + + line = new Line (start_line.document, start_line.ending); + ret = line; + + for (int i = start_line.line_no; i <= end_line.line_no; i++) { + current = document.GetLine(i); + + if (start_line.line_no == i) { + start = start_pos; + } else { + start = 0; + } + + if (end_line.line_no == i) { + end = end_pos; + } else { + end = current.text.Length; + } + + if (end_pos == 0) + continue; + + // Text for the tag + line.text = new StringBuilder (current.text.ToString (start, end - start)); + + // Copy tags from start to start+length onto new line + current_tag = current.FindTag (start + 1); + while ((current_tag != null) && (current_tag.Start <= end)) { + if ((current_tag.Start <= start) && (start < (current_tag.Start + current_tag.Length))) { + // start tag is within this tag + tag_start = start; + } else { + tag_start = current_tag.Start; + } + + tag = new LineTag(line, tag_start - start + 1); + tag.CopyFormattingFrom (current_tag); + + current_tag = current_tag.Next; + + // Add the new tag to the line + if (line.tags == null) { + line.tags = tag; + } else { + LineTag tail; + tail = line.tags; + + while (tail.Next != null) { + tail = tail.Next; + } + tail.Next = tag; + tag.Previous = tail; + } + } + + if ((i + 1) <= end_line.line_no) { + line.ending = current.ending; + + // Chain them (we use right/left as next/previous) + line.right = new Line (start_line.document, start_line.ending); + line.right.left = line; + line = line.right; + } + } + + return ret; + } + + // Insert multi-line text at the given position; use formatting at insertion point for inserted text + internal void Insert(Line line, int pos, Line insert, bool select) + { + Line current; + LineTag tag; + int offset; + int lines; + Line first; + + // Handle special case first + if (insert.right == null) { + + // Single line insert + document.Split(line, pos); + + if (insert.tags == null) { + return; // Blank line + } + + //Insert our tags at the end + tag = line.tags; + + while (tag.Next != null) { + tag = tag.Next; + } + + offset = tag.Start + tag.Length - 1; + + tag.Next = insert.tags; + line.text.Insert(offset, insert.text.ToString()); + + // Adjust start locations + tag = tag.Next; + while (tag != null) { + tag.Start += offset; + tag.Line = line; + tag = tag.Next; + } + // Put it back together + document.Combine(line.line_no, line.line_no + 1); + + if (select) { + document.SetSelectionStart (line, pos, false); + document.SetSelectionEnd (line, pos + insert.text.Length, false); + } + + document.UpdateView(line, pos); + return; + } + + first = line; + lines = 1; + current = insert; + + while (current != null) { + + if (current == insert) { + // Inserting the first line we split the line (and make space) + document.Split(line.line_no, pos); + //Insert our tags at the end of the line + tag = line.tags; + + + if (tag != null && tag.Length != 0) { + while (tag.Next != null) { + tag = tag.Next; + } + offset = tag.Start + tag.Length - 1; + tag.Next = current.tags; + tag.Next.Previous = tag; + + tag = tag.Next; + + } else { + offset = 0; + line.tags = current.tags; + line.tags.Previous = null; + tag = line.tags; + } + + line.ending = current.ending; + } else { + document.Split(line.line_no, 0); + offset = 0; + line.tags = current.tags; + line.tags.Previous = null; + line.ending = current.ending; + tag = line.tags; + } + + // Adjust start locations and line pointers + while (tag != null) { + tag.Start += offset - 1; + tag.Line = line; + tag = tag.Next; + } + + line.text.Insert(offset, current.text.ToString()); + line.Grow(line.text.Length); + + line.recalc = true; + line = document.GetLine(line.line_no + 1); + + // FIXME? Test undo of line-boundaries + if ((current.right == null) && (current.tags.Length != 0)) { + document.Combine(line.line_no - 1, line.line_no); + } + current = current.right; + lines++; + + } + + // Recalculate our document + document.UpdateView(first, lines, pos); + return; + } + #endregion // Private Methods + } +} diff --git a/source/ShiftUI/Internal/TextFormatFlags.cs b/source/ShiftUI/Internal/TextFormatFlags.cs new file mode 100644 index 0000000..6e2c798 --- /dev/null +++ b/source/ShiftUI/Internal/TextFormatFlags.cs @@ -0,0 +1,62 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Author: +// Pedro Martínez Juliá +// +using System; + + + +namespace ShiftUI { + + [FlagsAttribute()] + public enum TextFormatFlags { + Left = 0, + Top = 0, + Default = 0, + GlyphOverhangPadding = 0, + HorizontalCenter = 1, + Right = 2, + VerticalCenter = 4, + Bottom = 8, + WordBreak = 16, + SingleLine = 32, + ExpandTabs = 64, + NoClipping = 256, + ExternalLeading = 512, + NoPrefix = 2048, + Internal = 4096, + TextBoxControl = 8192, + PathEllipsis = 16384, + EndEllipsis = 32768, + ModifyString = 65536, + RightToLeft = 131072, + WordEllipsis = 262144, + NoFullWidthCharacterBreak = 524288, + HidePrefix = 1048576, + PrefixOnly = 2097152, + PreserveGraphicsClipping = 16777216, + PreserveGraphicsTranslateTransform = 33554432, + NoPadding = 268435456, + LeftAndRightPadding = 536870912 + } +} \ No newline at end of file diff --git a/source/ShiftUI/Internal/TextRenderer.cs b/source/ShiftUI/Internal/TextRenderer.cs new file mode 100644 index 0000000..89b3dfa --- /dev/null +++ b/source/ShiftUI/Internal/TextRenderer.cs @@ -0,0 +1,527 @@ +// +// TextRenderer.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +// This has become a monster class for all things text measuring and drawing. +// +// The public API is MeasureText/DrawText, which uses GDI on Win32, and +// GDI+ on other platforms. +// +// There is an internal API MeasureTextInternal/DrawTextInternal, which allows +// you to pass a flag of whether to use GDI or GDI+. This is used mainly for +// Widgets that have the UseCompatibleTextRendering flag. +// +// There are also thread-safe versions of MeasureString/MeasureCharacterRanges +// for things that want to measure strings without having a Graphics object. + +using System.Drawing; +using System.Runtime.InteropServices; +using System.Text; +using System.Drawing.Text; +using System; + +namespace ShiftUI +{ + public sealed class TextRenderer + { + private TextRenderer () + { + } + + #region Public Methods + public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor) + { + DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, TextFormatFlags.Default, false); + } + + public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor) + { + DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, false); + } + + public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor) + { + DrawTextInternal (dc, text, font, pt, foreColor, backColor, TextFormatFlags.Default, false); + } + + public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, TextFormatFlags flags) + { + DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, flags, false); + } + + public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor) + { + DrawTextInternal (dc, text, font, bounds, foreColor, backColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, false); + } + + public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags) + { + DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, flags, false); + } + + public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags) + { + DrawTextInternal (dc, text, font, pt, foreColor, backColor, flags, false); + } + + public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags) + { + DrawTextInternal (dc, text, font, bounds, foreColor, backColor, flags, false); + } + + public static Size MeasureText (string text, Font font) + { + return MeasureTextInternal (Hwnd.GraphicsContext, text, font, Size.Empty, TextFormatFlags.Default, false); + } + + public static Size MeasureText (IDeviceContext dc, string text, Font font) + { + return MeasureTextInternal (dc, text, font, Size.Empty, TextFormatFlags.Default, false); + } + + public static Size MeasureText (string text, Font font, Size proposedSize) + { + return MeasureTextInternal (Hwnd.GraphicsContext, text, font, proposedSize, TextFormatFlags.Default, false); + } + + public static Size MeasureText (IDeviceContext dc, string text, Font font, Size proposedSize) + { + return MeasureTextInternal (dc, text, font, proposedSize, TextFormatFlags.Default, false); + } + + public static Size MeasureText (string text, Font font, Size proposedSize, TextFormatFlags flags) + { + return MeasureTextInternal (Hwnd.GraphicsContext, text, font, proposedSize, flags, false); + } + + public static Size MeasureText (IDeviceContext dc, string text, Font font, Size proposedSize, TextFormatFlags flags) + { + return MeasureTextInternal (dc, text, font, proposedSize, flags, false); + } + #endregion + + #region Internal Methods That Do Stuff + internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags, bool useDrawString) + { + if (dc == null) + throw new ArgumentNullException ("dc"); + + if (text == null || text.Length == 0) + return; + + // We use MS GDI API's unless told not to, or we aren't on Windows + if (!useDrawString && !XplatUI.RunningOnUnix) { + if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter || (flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom) + flags |= TextFormatFlags.SingleLine; + + // Calculate the text bounds (there is often padding added) + Rectangle new_bounds = PadRectangle (bounds, flags); + new_bounds.Offset ((int)(dc as Graphics).Transform.OffsetX, (int)(dc as Graphics).Transform.OffsetY); + + IntPtr hdc = IntPtr.Zero; + bool clear_clip_region = false; + + // If we need to use the graphics clipping region, add it to our hdc + if ((flags & TextFormatFlags.PreserveGraphicsClipping) == TextFormatFlags.PreserveGraphicsClipping) { + Graphics graphics = (Graphics)dc; + Region clip_region = graphics.Clip; + + if (!clip_region.IsInfinite (graphics)) { + IntPtr hrgn = clip_region.GetHrgn (graphics); + hdc = dc.GetHdc (); + SelectClipRgn (hdc, hrgn); + DeleteObject (hrgn); + + clear_clip_region = true; + } + } + + if (hdc == IntPtr.Zero) + hdc = dc.GetHdc (); + + // Set the fore color + if (foreColor != Color.Empty) + SetTextColor (hdc, ColorTranslator.ToWin32 (foreColor)); + + // Set the back color + if (backColor != Color.Transparent && backColor != Color.Empty) { + SetBkMode (hdc, 2); //1-Transparent, 2-Opaque + SetBkColor (hdc, ColorTranslator.ToWin32 (backColor)); + } + else { + SetBkMode (hdc, 1); //1-Transparent, 2-Opaque + } + + XplatUIWin32.RECT r = XplatUIWin32.RECT.FromRectangle (new_bounds); + + IntPtr prevobj; + + if (font != null) { + prevobj = SelectObject (hdc, font.ToHfont ()); + Win32DrawText (hdc, text, text.Length, ref r, (int)flags); + prevobj = SelectObject (hdc, prevobj); + DeleteObject (prevobj); + } + else { + Win32DrawText (hdc, text, text.Length, ref r, (int)flags); + } + + if (clear_clip_region) + SelectClipRgn (hdc, IntPtr.Zero); + + dc.ReleaseHdc (); + } + // Use Graphics.DrawString as a fallback method + else { + Graphics g; + IntPtr hdc = IntPtr.Zero; + + if (dc is Graphics) + g = (Graphics)dc; + else { + hdc = dc.GetHdc (); + g = Graphics.FromHdc (hdc); + } + + StringFormat sf = FlagsToStringFormat (flags); + + Rectangle new_bounds = PadDrawStringRectangle (bounds, flags); + + g.DrawString (text, font, ThemeEngine.Current.ResPool.GetSolidBrush (foreColor), new_bounds, sf); + + if (!(dc is Graphics)) { + g.Dispose (); + dc.ReleaseHdc (); + } + } + } + + internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, Size proposedSize, TextFormatFlags flags, bool useMeasureString) + { + if (!useMeasureString && !XplatUI.RunningOnUnix) { + // Tell DrawText to calculate size instead of draw + flags |= (TextFormatFlags)1024; // DT_CALCRECT + + IntPtr hdc = dc.GetHdc (); + + XplatUIWin32.RECT r = XplatUIWin32.RECT.FromRectangle (new Rectangle (Point.Empty, proposedSize)); + + IntPtr prevobj; + + if (font != null) { + prevobj = SelectObject (hdc, font.ToHfont ()); + Win32DrawText (hdc, text, text.Length, ref r, (int)flags); + prevobj = SelectObject (hdc, prevobj); + DeleteObject (prevobj); + } + else { + Win32DrawText (hdc, text, text.Length, ref r, (int)flags); + } + + dc.ReleaseHdc (); + + // Really, I am just making something up here, which as far as I can tell, MS + // just makes something up as well. This will require lots of tweaking to match MS. :( + Size retval = r.ToRectangle ().Size; + + if (retval.Width > 0 && (flags & TextFormatFlags.NoPadding) == 0) { + retval.Width += 6; + retval.Width += (int)retval.Height / 8; + } + + return retval; + } + else { + StringFormat sf = FlagsToStringFormat (flags); + + Size retval; + + int proposedWidth; + if (proposedSize.Width == 0) + proposedWidth = Int32.MaxValue; + else { + proposedWidth = proposedSize.Width; + if ((flags & TextFormatFlags.NoPadding) == 0) + proposedWidth -= 9; + } + if (dc is Graphics) + retval = (dc as Graphics).MeasureString (text, font, proposedWidth, sf).ToSize (); + else + retval = TextRenderer.MeasureString (text, font, proposedWidth, sf).ToSize (); + + if (retval.Width > 0 && (flags & TextFormatFlags.NoPadding) == 0) + retval.Width += 9; + + return retval; + } + } + #endregion + +#region Internal Methods That Are Just Overloads + internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, bool useDrawString) + { + DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, TextFormatFlags.Default, useDrawString); + } + + internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, bool useDrawString) + { + DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, useDrawString); + } + + internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, bool useDrawString) + { + DrawTextInternal (dc, text, font, pt, foreColor, backColor, TextFormatFlags.Default, useDrawString); + } + + internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, TextFormatFlags flags, bool useDrawString) + { + DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, flags, useDrawString); + } + + internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, bool useDrawString) + { + DrawTextInternal (dc, text, font, bounds, foreColor, backColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, useDrawString); + } + + internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags, bool useDrawString) + { + DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, flags, useDrawString); + } + + internal static Size MeasureTextInternal (string text, Font font, bool useMeasureString) + { + return MeasureTextInternal (Hwnd.GraphicsContext, text, font, Size.Empty, TextFormatFlags.Default, useMeasureString); + } + + internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags, bool useDrawString) + { + Size sz = MeasureTextInternal (dc, text, font, useDrawString); + DrawTextInternal (dc, text, font, new Rectangle (pt, sz), foreColor, backColor, flags, useDrawString); + } + + internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, bool useMeasureString) + { + return MeasureTextInternal (dc, text, font, Size.Empty, TextFormatFlags.Default, useMeasureString); + } + + internal static Size MeasureTextInternal (string text, Font font, Size proposedSize, bool useMeasureString) + { + return MeasureTextInternal (Hwnd.GraphicsContext, text, font, proposedSize, TextFormatFlags.Default, useMeasureString); + } + + internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, Size proposedSize, bool useMeasureString) + { + return MeasureTextInternal (dc, text, font, proposedSize, TextFormatFlags.Default, useMeasureString); + } + + internal static Size MeasureTextInternal (string text, Font font, Size proposedSize, TextFormatFlags flags, bool useMeasureString) + { + return MeasureTextInternal (Hwnd.GraphicsContext, text, font, proposedSize, flags, useMeasureString); + } +#endregion + + #region Thread-Safe Static Graphics Methods + internal static SizeF MeasureString (string text, Font font) + { + return Hwnd.GraphicsContext.MeasureString (text, font); + } + + internal static SizeF MeasureString (string text, Font font, int width) + { + return Hwnd.GraphicsContext.MeasureString (text, font, width); + } + + internal static SizeF MeasureString (string text, Font font, SizeF layoutArea) + { + return Hwnd.GraphicsContext.MeasureString (text, font, layoutArea); + } + + internal static SizeF MeasureString (string text, Font font, int width, StringFormat format) + { + return Hwnd.GraphicsContext.MeasureString (text, font, width, format); + } + + internal static SizeF MeasureString (string text, Font font, PointF origin, StringFormat stringFormat) + { + return Hwnd.GraphicsContext.MeasureString (text, font, origin, stringFormat); + } + + internal static SizeF MeasureString (string text, Font font, SizeF layoutArea, StringFormat stringFormat) + { + return Hwnd.GraphicsContext.MeasureString (text, font, layoutArea, stringFormat); + } + + internal static SizeF MeasureString (string text, Font font, SizeF layoutArea, StringFormat stringFormat, out int charactersFitted, out int linesFilled) + { + return Hwnd.GraphicsContext.MeasureString (text, font, layoutArea, stringFormat, out charactersFitted, out linesFilled); + } + + internal static Region[] MeasureCharacterRanges (string text, Font font, RectangleF layoutRect, StringFormat stringFormat) + { + return Hwnd.GraphicsContext.MeasureCharacterRanges (text, font, layoutRect, stringFormat); + } + + internal static SizeF GetDpi () + { + return new SizeF (Hwnd.GraphicsContext.DpiX, Hwnd.GraphicsContext.DpiY); + } + #endregion + +#region Private Methods + private static StringFormat FlagsToStringFormat (TextFormatFlags flags) + { + StringFormat sf = new StringFormat (); + + // Translation table: http://msdn.microsoft.com/msdnmag/issues/06/03/TextRendering/default.aspx?fig=true#fig4 + + // Horizontal Alignment + if ((flags & TextFormatFlags.HorizontalCenter) == TextFormatFlags.HorizontalCenter) + sf.Alignment = StringAlignment.Center; + else if ((flags & TextFormatFlags.Right) == TextFormatFlags.Right) + sf.Alignment = StringAlignment.Far; + else + sf.Alignment = StringAlignment.Near; + + // Vertical Alignment + if ((flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom) + sf.LineAlignment = StringAlignment.Far; + else if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter) + sf.LineAlignment = StringAlignment.Center; + else + sf.LineAlignment = StringAlignment.Near; + + // Ellipsis + if ((flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis) + sf.Trimming = StringTrimming.EllipsisCharacter; + else if ((flags & TextFormatFlags.PathEllipsis) == TextFormatFlags.PathEllipsis) + sf.Trimming = StringTrimming.EllipsisPath; + else if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis) + sf.Trimming = StringTrimming.EllipsisWord; + else + sf.Trimming = StringTrimming.Character; + + // Hotkey Prefix + if ((flags & TextFormatFlags.NoPrefix) == TextFormatFlags.NoPrefix) + sf.HotkeyPrefix = HotkeyPrefix.None; + else if ((flags & TextFormatFlags.HidePrefix) == TextFormatFlags.HidePrefix) + sf.HotkeyPrefix = HotkeyPrefix.Hide; + else + sf.HotkeyPrefix = HotkeyPrefix.Show; + + // Text Padding + if ((flags & TextFormatFlags.NoPadding) == TextFormatFlags.NoPadding) + sf.FormatFlags |= StringFormatFlags.FitBlackBox; + + // Text Wrapping + if ((flags & TextFormatFlags.SingleLine) == TextFormatFlags.SingleLine) + sf.FormatFlags |= StringFormatFlags.NoWrap; + else if ((flags & TextFormatFlags.TextBoxControl) == TextFormatFlags.TextBoxControl) + sf.FormatFlags |= StringFormatFlags.LineLimit; + + // Other Flags + //if ((flags & TextFormatFlags.RightToLeft) == TextFormatFlags.RightToLeft) + // sf.FormatFlags |= StringFormatFlags.DirectionRightToLeft; + if ((flags & TextFormatFlags.NoClipping) == TextFormatFlags.NoClipping) + sf.FormatFlags |= StringFormatFlags.NoClip; + + return sf; + } + + private static Rectangle PadRectangle (Rectangle r, TextFormatFlags flags) + { + if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == 0 && (flags & TextFormatFlags.HorizontalCenter) == 0) { + r.X += 3; + r.Width -= 3; + } + if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == TextFormatFlags.Right) { + r.Width -= 4; + } + if ((flags & TextFormatFlags.LeftAndRightPadding) == TextFormatFlags.LeftAndRightPadding) { + r.X += 2; + r.Width -= 2; + } + if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis || (flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis || (flags & TextFormatFlags.WordBreak) == TextFormatFlags.WordBreak) { + r.Width -= 4; + } + if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter) { + r.Y += 1; + } + + return r; + } + + private static Rectangle PadDrawStringRectangle (Rectangle r, TextFormatFlags flags) + { + if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == 0 && (flags & TextFormatFlags.HorizontalCenter) == 0) { + r.X += 1; + r.Width -= 1; + } + if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == TextFormatFlags.Right) { + r.Width -= 4; + } + if ((flags & TextFormatFlags.NoPadding) == TextFormatFlags.NoPadding) { + r.X -= 2; + } + if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom) { + r.Y += 1; + } + if ((flags & TextFormatFlags.LeftAndRightPadding) == TextFormatFlags.LeftAndRightPadding) { + r.X += 2; + r.Width -= 2; + } + if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter && XplatUI.RunningOnUnix) { + r.Y -= 1; + } + + return r; + } +#endregion + +#region DllImports (Windows) + [DllImport ("user32", CharSet = CharSet.Unicode, EntryPoint = "DrawText")] + static extern int Win32DrawText (IntPtr hdc, string lpStr, int nCount, ref XplatUIWin32.RECT lpRect, int wFormat); + + [DllImport ("gdi32")] + static extern int SetTextColor (IntPtr hdc, int crColor); + + [DllImport ("gdi32")] + static extern IntPtr SelectObject (IntPtr hDC, IntPtr hObject); + + [DllImport ("gdi32")] + static extern int SetBkColor (IntPtr hdc, int crColor); + + [DllImport ("gdi32")] + static extern int SetBkMode (IntPtr hdc, int iBkMode); + + [DllImport ("gdi32")] + static extern bool DeleteObject (IntPtr objectHandle); + + [DllImport("gdi32")] + static extern bool SelectClipRgn(IntPtr hdc, IntPtr hrgn); +#endregion + } +} diff --git a/source/ShiftUI/Internal/Theme.cs b/source/ShiftUI/Internal/Theme.cs new file mode 100644 index 0000000..4f1eac6 --- /dev/null +++ b/source/ShiftUI/Internal/Theme.cs @@ -0,0 +1,1063 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// Peter Dennis Bartok, pbartok@novell.com +// + +using System.Collections; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Reflection; +using System; + +namespace ShiftUI +{ + internal enum UIIcon { + PlacesRecentDocuments, + PlacesDesktop, + PlacesPersonal, + PlacesMyComputer, + PlacesMyNetwork, + MessageBoxError, + MessageBoxQuestion, + MessageBoxWarning, + MessageBoxInfo, + + NormalFolder + } + + internal struct CPColor { + internal Color Dark; + internal Color DarkDark; + internal Color Light; + internal Color LightLight; + + internal static CPColor Empty; + } + + // Implements a pool of system resources + internal class SystemResPool + { + private Hashtable pens = new Hashtable (); + private Hashtable dashpens = new Hashtable (); + private Hashtable sizedpens = new Hashtable (); + private Hashtable solidbrushes = new Hashtable (); + private Hashtable hatchbrushes = new Hashtable (); + private Hashtable uiImages = new Hashtable(); + private Hashtable cpcolors = new Hashtable (); + + public SystemResPool () {} + + public Pen GetPen (Color color) + { + int hash = color.ToArgb (); + + lock (pens) { + Pen res = pens [hash] as Pen; + if (res != null) + return res; + + Pen pen = new Pen (color); + pens.Add (hash, pen); + return pen; + } + } + + public Pen GetDashPen (Color color, DashStyle dashStyle) + { + string hash = color.ToString() + dashStyle; + + lock (dashpens) { + Pen res = dashpens [hash] as Pen; + if (res != null) + return res; + + Pen pen = new Pen (color); + pen.DashStyle = dashStyle; + dashpens [hash] = pen; + return pen; + } + } + + public Pen GetSizedPen (Color color, int size) + { + string hash = color.ToString () + size; + + lock (sizedpens) { + Pen res = sizedpens [hash] as Pen; + if (res != null) + return res; + + Pen pen = new Pen (color, size); + sizedpens [hash] = pen; + return pen; + } + } + + public SolidBrush GetSolidBrush (Color color) + { + int hash = color.ToArgb (); + + lock (solidbrushes) { + SolidBrush res = solidbrushes [hash] as SolidBrush; + if (res != null) + return res; + + SolidBrush brush = new SolidBrush (color); + solidbrushes.Add (hash, brush); + return brush; + } + } + + public HatchBrush GetHatchBrush (HatchStyle hatchStyle, Color foreColor, Color backColor) + { + string hash = ((int)hatchStyle).ToString () + foreColor.ToString () + backColor.ToString (); + + lock (hatchbrushes) { + HatchBrush brush = (HatchBrush) hatchbrushes[hash]; + if (brush == null) { + brush = new HatchBrush (hatchStyle, foreColor, backColor); + hatchbrushes.Add (hash, brush); + } + return brush; + } + } + + public void AddUIImage (Image image, string name, int size) + { + string hash = name + size.ToString(); + + lock (uiImages) { + if (uiImages.Contains (hash)) + return; + uiImages.Add (hash, image); + } + } + + public Image GetUIImage(string name, int size) + { + string hash = name + size.ToString(); + + Image image = uiImages [hash] as Image; + + return image; + } + + public CPColor GetCPColor (Color color) + { + lock (cpcolors) { + object tmp = cpcolors [color]; + + if (tmp == null) { + CPColor cpcolor = new CPColor (); + cpcolor.Dark = WidgetPaint.Dark (color); + cpcolor.DarkDark = WidgetPaint.DarkDark (color); + cpcolor.Light = WidgetPaint.Light (color); + cpcolor.LightLight = WidgetPaint.LightLight (color); + + cpcolors.Add (color, cpcolor); + + return cpcolor; + } + + return (CPColor)tmp; + } + } + } + + internal abstract class Theme + { + protected Array syscolors; + Font default_font; + protected Color defaultWindowBackColor; + protected Color defaultWindowForeColor; + internal SystemResPool ResPool = new SystemResPool (); + private MethodInfo update; + + protected Theme () + { + } + + private void SetSystemColors (KnownColor kc, Color value) + { + if (update == null) { + Type known_colors = Type.GetType ("System.Drawing.KnownColors, " + Consts.AssemblySystem_Drawing); + if (known_colors != null) + update = known_colors.GetMethod ("Update", BindingFlags.Static | BindingFlags.Public); + } + if (update != null) + update.Invoke (null, new object [2] { (int)kc, value.ToArgb () }); + } + + /* OS Feature support */ + public abstract Version Version { + get; + } + + /* Default properties */ + public virtual Color ColorScrollBar { + get { return SystemColors.ScrollBar; } + set { SetSystemColors (KnownColor.ScrollBar, value); } + } + + public virtual Color ColorDesktop { + get { return SystemColors.Desktop;} + set { SetSystemColors (KnownColor.Desktop, value); } + } + + public virtual Color ColorActiveCaption { + get { return SystemColors.ActiveCaption;} + set { SetSystemColors (KnownColor.ActiveCaption, value); } + } + + public virtual Color ColorInactiveCaption { + get { return SystemColors.InactiveCaption;} + set { SetSystemColors (KnownColor.InactiveCaption, value); } + } + + public virtual Color ColorMenu { + get { return SystemColors.Menu;} + set { SetSystemColors (KnownColor.Menu, value); } + } + + public virtual Color ColorWindow { + get { return SystemColors.Window;} + set { SetSystemColors (KnownColor.Window, value); } + } + + public virtual Color ColorWindowFrame { + get { return SystemColors.WindowFrame;} + set { SetSystemColors (KnownColor.WindowFrame, value); } + } + + public virtual Color ColorMenuText { + get { return SystemColors.MenuText;} + set { SetSystemColors (KnownColor.MenuText, value); } + } + + public virtual Color ColorWindowText { + get { return SystemColors.WindowText;} + set { SetSystemColors (KnownColor.WindowText, value); } + } + + public virtual Color ColorActiveCaptionText { + get { return SystemColors.ActiveCaptionText;} + set { SetSystemColors (KnownColor.ActiveCaptionText, value); } + } + + public virtual Color ColorActiveBorder { + get { return SystemColors.ActiveBorder;} + set { SetSystemColors (KnownColor.ActiveBorder, value); } + } + + public virtual Color ColorInactiveBorder{ + get { return SystemColors.InactiveBorder;} + set { SetSystemColors (KnownColor.InactiveBorder, value); } + } + + public virtual Color ColorAppWorkspace { + get { return SystemColors.AppWorkspace;} + set { SetSystemColors (KnownColor.AppWorkspace, value); } + } + + public virtual Color ColorHighlight { + get { return SystemColors.Highlight;} + set { SetSystemColors (KnownColor.Highlight, value); } + } + + public virtual Color ColorHighlightText { + get { return SystemColors.HighlightText;} + set { SetSystemColors (KnownColor.HighlightText, value); } + } + + public virtual Color ColorControl { + get { return SystemColors.Control; } + set { SetSystemColors (KnownColor.Control, value); } + } + + public virtual Color ColorControlDark { + get { return SystemColors.ControlDark;} + set { SetSystemColors (KnownColor.ControlDark, value); } + } + + public virtual Color ColorGrayText { + get { return SystemColors.GrayText;} + set { SetSystemColors (KnownColor.GrayText, value); } + } + + public virtual Color ColorControlText { + get { return SystemColors.ControlText;} + set { SetSystemColors (KnownColor.ControlText, value); } + } + + public virtual Color ColorInactiveCaptionText { + get { return SystemColors.InactiveCaptionText;} + set { SetSystemColors (KnownColor.InactiveCaptionText, value); } + } + + public virtual Color ColorControlLight { + get { return SystemColors.ControlLight;} + set { SetSystemColors (KnownColor.ControlLight, value); } + } + + public virtual Color ColorControlDarkDark { + get { return SystemColors.ControlDarkDark;} + set { SetSystemColors (KnownColor.ControlDarkDark, value); } + } + + public virtual Color ColorControlLightLight { + get { return SystemColors.ControlLightLight;} + set { SetSystemColors (KnownColor.ControlLightLight, value); } + } + + public virtual Color ColorInfoText { + get { return SystemColors.InfoText;} + set { SetSystemColors (KnownColor.InfoText, value); } + } + + public virtual Color ColorInfo { + get { return SystemColors.Info;} + set { SetSystemColors (KnownColor.Info, value); } + } + + public virtual Color ColorHotTrack { + get { return SystemColors.HotTrack;} + set { SetSystemColors (KnownColor.HotTrack, value);} + } + + public virtual Color DefaultControlBackColor { + get { return ColorControl; } + set { ColorControl = value; } + } + + public virtual Color DefaultControlForeColor { + get { return ColorControlText; } + set { ColorControlText = value; } + } + + public virtual Font DefaultFont { + get { return default_font ?? (default_font = SystemFonts.DefaultFont); } + } + + public virtual Color DefaultWindowBackColor { + get { return defaultWindowBackColor; } + } + + public virtual Color DefaultWindowForeColor { + get { return defaultWindowForeColor; } + } + + public virtual Color GetColor (XplatUIWin32.GetSysColorIndex idx) + { + return (Color) syscolors.GetValue ((int)idx); + } + + public virtual void SetColor (XplatUIWin32.GetSysColorIndex idx, Color color) + { + syscolors.SetValue (color, (int) idx); + } + + // Theme/UI specific defaults + public virtual ArrangeDirection ArrangeDirection { + get { + return ArrangeDirection.Down; + } + } + + public virtual ArrangeStartingPosition ArrangeStartingPosition { + get { + return ArrangeStartingPosition.BottomLeft; + } + } + + public virtual int BorderMultiplierFactor { get { return 1; } } + + public virtual Size BorderSizableSize { + get { + return new Size (3, 3); + } + } + + public virtual Size Border3DSize { + get { + return XplatUI.Border3DSize; + } + } + + public virtual Size BorderStaticSize { + get { + return new Size(1, 1); + } + } + + public virtual Size BorderSize { + get { + return XplatUI.BorderSize; + } + } + + public virtual Size CaptionButtonSize { + get { + return XplatUI.CaptionButtonSize; + } + } + + public virtual int CaptionHeight { + get { + return XplatUI.CaptionHeight; + } + } + + public virtual Size DoubleClickSize { + get { + return new Size(4, 4); + } + } + + public virtual int DoubleClickTime { + get { + return XplatUI.DoubleClickTime; + } + } + + public virtual Size FixedFrameBorderSize { + get { + return XplatUI.FixedFrameBorderSize; + } + } + + public virtual Size FrameBorderSize { + get { + return XplatUI.FrameBorderSize; + } + } + + public virtual int HorizontalFocusThickness { get { return 1; } } + + public virtual int HorizontalScrollBarArrowWidth { + get { + return 16; + } + } + + public virtual int HorizontalScrollBarHeight { + get { + return 16; + } + } + + public virtual int HorizontalScrollBarThumbWidth { + get { + return 16; + } + } + + public virtual Size IconSpacingSize { + get { + return new Size(75, 75); + } + } + + public virtual bool MenuAccessKeysUnderlined { + get { + try { + return XplatUI.MenuAccessKeysUnderlined; + } + catch(Exception ex) { + Console.WriteLine("[ShiftUI] XplatUI error: {0}\r\nInnerException: {1}", ex.Message, ex.InnerException.Message); + return false; + } + } + } + + public virtual Size MenuBarButtonSize { + get { return XplatUI.MenuBarButtonSize; } + } + + public virtual Size MenuButtonSize { + get { + return XplatUI.MenuButtonSize; + } + } + + public virtual Size MenuCheckSize { + get { + return new Size(13, 13); + } + } + + public virtual Font MenuFont { + get { + return default_font ?? (default_font = SystemFonts.DefaultFont); + } + } + + public virtual int MenuHeight { + get { + return XplatUI.MenuHeight; + } + } + + public virtual int MouseWheelScrollLines { + get { + return 3; + } + } + + public virtual bool RightAlignedMenus { + get { + return false; + } + } + + public virtual Size ToolWindowCaptionButtonSize { + get { + return XplatUI.ToolWindowCaptionButtonSize; + } + } + + public virtual int ToolWindowCaptionHeight { + get { + return XplatUI.ToolWindowCaptionHeight; + } + } + + public virtual int VerticalFocusThickness { get { return 1; } } + + public virtual int VerticalScrollBarArrowHeight { + get { + return 16; + } + } + + public virtual int VerticalScrollBarThumbHeight { + get { + return 16; + } + } + + public virtual int VerticalScrollBarWidth { + get { + return 16; + } + } + + public abstract Font WindowBorderFont { + get; + } + + public int Clamp (int value, int lower, int upper) + { + if (value < lower) return lower; + else if (value > upper) return upper; + else return value; + } + + [MonoInternalNote ("Figure out where to point for My Network Places")] + public virtual string Places(UIIcon index) { + switch (index) { + case UIIcon.PlacesRecentDocuments: { + // Default = "Recent Documents" + return Environment.GetFolderPath(Environment.SpecialFolder.Recent); + } + + case UIIcon.PlacesDesktop: { + // Default = "Desktop" + return Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory); + } + + case UIIcon.PlacesPersonal: { + // Default = "My Documents" + return Environment.GetFolderPath(Environment.SpecialFolder.Personal); + } + + case UIIcon.PlacesMyComputer: { + // Default = "My Computer" + return Environment.GetFolderPath(Environment.SpecialFolder.MyComputer); + } + + case UIIcon.PlacesMyNetwork: { + // Default = "My Network Places" + return "/tmp"; + } + + default: { + throw new ArgumentOutOfRangeException("index", index, "Unsupported place"); + } + } + } + + // + // This routine fetches images embedded as assembly resources (not + // resgen resources). It optionally scales the image to fit the + // specified size x dimension (it adjusts y automatically to fit that). + // + private Image GetSizedResourceImage(string name, int width) + { + Image image = ResPool.GetUIImage (name, width); + if (image != null) + return image; + + string fullname; + + if (width > 0) { + // Try name_width + fullname = String.Format("{1}_{0}", name, width); + if (image != null){ + ResPool.AddUIImage (image, name, width); + return image; + } + } + + // Just try name + if (image == null) + return null; + + ResPool.AddUIImage (image, name, 0); + if (image.Width != width && width != 0){ + Console.Error.WriteLine ("warning: requesting icon that not been tuned {0}_{1} {2}", width, name, image.Width); + int height = (image.Height * width)/image.Width; + Bitmap b = new Bitmap (width, height); + using (Graphics g = Graphics.FromImage (b)) + g.DrawImage (image, 0, 0, width, height); + ResPool.AddUIImage (b, name, width); + + return b; + } + return image; + } + + public virtual Image Images(UIIcon index) { + return Images(index, 0); + } + + public virtual Image Images(UIIcon index, int size) { + switch (index) { + case UIIcon.PlacesRecentDocuments: + return GetSizedResourceImage ("document-open.png", size); + case UIIcon.PlacesDesktop: + return GetSizedResourceImage ("user-desktop.png", size); + case UIIcon.PlacesPersonal: + return GetSizedResourceImage ("user-home.png", size); + case UIIcon.PlacesMyComputer: + return GetSizedResourceImage ("computer.png", size); + case UIIcon.PlacesMyNetwork: + return GetSizedResourceImage ("folder-remote.png", size); + + // Icons for message boxes + case UIIcon.MessageBoxError: + return GetSizedResourceImage ("dialog-error.png", size); + case UIIcon.MessageBoxInfo: + return GetSizedResourceImage ("dialog-information.png", size); + case UIIcon.MessageBoxQuestion: + return GetSizedResourceImage ("dialog-question.png", size); + case UIIcon.MessageBoxWarning: + return GetSizedResourceImage ("dialog-warning.png", size); + + // misc Icons + case UIIcon.NormalFolder: + return GetSizedResourceImage ("folder.png", size); + + default: { + throw new ArgumentException("Invalid Icon type requested", "index"); + } + } + } + + public virtual Image Images(string mimetype, string extension, int size) { + return null; + } + + #region Principal Theme Methods + // To let the theme now that a change of defaults (colors, etc) was detected and force a re-read (and possible recreation of cached resources) + public abstract void ResetDefaults(); + + // If the theme writes directly to a window instead of a device context + public abstract bool DoubleBufferingSupported {get;} + #endregion // Principal Theme Methods + + #region OwnerDraw Support + public abstract void DrawOwnerDrawBackground (DrawItemEventArgs e); + public abstract void DrawOwnerDrawFocusRectangle (DrawItemEventArgs e); + #endregion // OwnerDraw Support + + #region Button + public abstract Size CalculateButtonAutoSize (Button button); + public abstract void CalculateButtonTextAndImageLayout (Graphics g, ButtonBase b, out Rectangle textRectangle, out Rectangle imageRectangle); + public abstract void DrawButton (Graphics g, Button b, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle); + public abstract void DrawFlatButton (Graphics g, ButtonBase b, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle); + public abstract void DrawPopupButton (Graphics g, Button b, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle); + #endregion // Button + + #region ButtonBase + // Drawing + public abstract void DrawButtonBase(Graphics dc, Rectangle clip_area, ButtonBase button); + + // Sizing + public abstract Size ButtonBaseDefaultSize{get;} + #endregion // ButtonBase + + #region CheckBox + public abstract Size CalculateCheckBoxAutoSize (CheckBox checkBox); + public abstract void CalculateCheckBoxTextAndImageLayout (ButtonBase b, Point offset, out Rectangle glyphArea, out Rectangle textRectangle, out Rectangle imageRectangle); + public abstract void DrawCheckBox (Graphics g, CheckBox cb, Rectangle glyphArea, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle); + public abstract void DrawCheckBox (Graphics dc, Rectangle clip_area, CheckBox checkbox); + + #endregion // CheckBox + + #region CheckedListBox + // Drawing + public abstract void DrawCheckedListBoxItem (CheckedListBox ctrl, DrawItemEventArgs e); + #endregion // CheckedListBox + + #region ComboBox + // Drawing + public abstract void DrawComboBoxItem (ComboBox ctrl, DrawItemEventArgs e); + public abstract void DrawFlatStyleComboButton (Graphics graphics, Rectangle rectangle, ButtonState state); + public abstract void ComboBoxDrawNormalDropDownButton (ComboBox comboBox, Graphics g, Rectangle clippingArea, Rectangle area, ButtonState state); + public abstract bool ComboBoxNormalDropDownButtonHasTransparentBackground (ComboBox comboBox, ButtonState state); + public abstract bool ComboBoxDropDownButtonHasHotElementStyle (ComboBox comboBox); + public abstract void ComboBoxDrawBackground (ComboBox comboBox, Graphics g, Rectangle clippingArea, FlatStyle style); + public abstract bool CombBoxBackgroundHasHotElementStyle (ComboBox comboBox); + #endregion // ComboBox + + #region Widget + public abstract Font GetLinkFont (Widget control); + #endregion // Widget + + + /* FIXME: I really don't feel like implementing DataGrids. Too much code. + #region Datagrid + public abstract int DataGridPreferredColumnWidth { get; } + public abstract int DataGridMinimumColumnCheckBoxHeight { get; } + public abstract int DataGridMinimumColumnCheckBoxWidth { get; } + + // Default colours + public abstract Color DataGridAlternatingBackColor { get; } + public abstract Color DataGridBackColor { get; } + public abstract Color DataGridBackgroundColor { get; } + public abstract Color DataGridCaptionBackColor { get; } + public abstract Color DataGridCaptionForeColor { get; } + public abstract Color DataGridGridLineColor { get; } + public abstract Color DataGridHeaderBackColor { get; } + public abstract Color DataGridHeaderForeColor { get; } + public abstract Color DataGridLinkColor { get; } + public abstract Color DataGridLinkHoverColor { get; } + public abstract Color DataGridParentRowsBackColor { get; } + public abstract Color DataGridParentRowsForeColor { get; } + public abstract Color DataGridSelectionBackColor { get; } + public abstract Color DataGridSelectionForeColor { get; } + // Paint + public abstract void DataGridPaint (PaintEventArgs pe, DataGrid grid); + public abstract void DataGridPaintCaption (Graphics g, Rectangle clip, DataGrid grid); + public abstract void DataGridPaintColumnHeaders (Graphics g, Rectangle clip, DataGrid grid); + public abstract void DataGridPaintColumnHeader (Graphics g, Rectangle bounds, DataGrid grid, int col); + public abstract void DataGridPaintRowContents (Graphics g, int row, Rectangle row_rect, bool is_newrow, Rectangle clip, DataGrid grid); + public abstract void DataGridPaintRowHeader (Graphics g, Rectangle bounds, int row, DataGrid grid); + public abstract void DataGridPaintRowHeaderArrow (Graphics g, Rectangle bounds, DataGrid grid); + public abstract void DataGridPaintRowHeaderStar (Graphics g, Rectangle bounds, DataGrid grid); + public abstract void DataGridPaintParentRows (Graphics g, Rectangle bounds, DataGrid grid); + public abstract void DataGridPaintParentRow (Graphics g, Rectangle bounds, DataGridDataSource row, DataGrid grid); + public abstract void DataGridPaintRows (Graphics g, Rectangle cells, Rectangle clip, DataGrid grid); + public abstract void DataGridPaintRow (Graphics g, int row, Rectangle row_rect, bool is_newrow, Rectangle clip, DataGrid grid); + public abstract void DataGridPaintRelationRow (Graphics g, int row, Rectangle row_rect, bool is_newrow, Rectangle clip, DataGrid grid); + + #endregion // Datagrid + + #region DataGridView + #region DataGridViewHeaderCell + #region DataGridViewRowHeaderCell + public abstract bool DataGridViewRowHeaderCellDrawBackground (DataGridViewRowHeaderCell cell, Graphics g, Rectangle bounds); + public abstract bool DataGridViewRowHeaderCellDrawSelectionBackground (DataGridViewRowHeaderCell cell); + public abstract bool DataGridViewRowHeaderCellDrawBorder (DataGridViewRowHeaderCell cell, Graphics g, Rectangle bounds); + #endregion + #region DataGridViewColumnHeaderCell + public abstract bool DataGridViewColumnHeaderCellDrawBackground (DataGridViewColumnHeaderCell cell, Graphics g, Rectangle bounds); + public abstract bool DataGridViewColumnHeaderCellDrawBorder (DataGridViewColumnHeaderCell cell, Graphics g, Rectangle bounds); + #endregion + public abstract bool DataGridViewHeaderCellHasPressedStyle (DataGridView dataGridView); + public abstract bool DataGridViewHeaderCellHasHotStyle (DataGridView dataGridView); + #endregion + #endregion +*/ + + #region DateTimePicker + public abstract void DrawDateTimePicker(Graphics dc, Rectangle clip_rectangle, DateTimePicker dtp); + public abstract bool DateTimePickerBorderHasHotElementStyle { get; } + public abstract Rectangle DateTimePickerGetDropDownButtonArea (DateTimePicker dateTimePicker); + public abstract Rectangle DateTimePickerGetDateArea (DateTimePicker dateTimePicker); + public abstract bool DateTimePickerDropDownButtonHasHotElementStyle { get; } + #endregion // DateTimePicker + + #region GroupBox + // Drawing + public abstract void DrawGroupBox (Graphics dc, Rectangle clip_area, GroupBox box); + + // Sizing + public abstract Size GroupBoxDefaultSize{get;} + #endregion // GroupBox + + #region HScrollBar + public abstract Size HScrollBarDefaultSize{get;} // Default size of the scrollbar + #endregion // HScrollBar + + #region ListBox + // Drawing + public abstract void DrawListBoxItem (ListBox ctrl, DrawItemEventArgs e); + #endregion // ListBox + + #region ListView + // Drawing + public abstract void DrawListViewItems (Graphics dc, Rectangle clip_rectangle, ListView control); + public abstract void DrawListViewHeader (Graphics dc, Rectangle clip_rectangle, ListView control); + public abstract void DrawListViewHeaderDragDetails (Graphics dc, ListView control, ColumnHeader drag_column, int target_x); + public abstract bool ListViewHasHotHeaderStyle { get; } + + // Sizing + public abstract int ListViewGetHeaderHeight (ListView listView, Font font); + public abstract Size ListViewCheckBoxSize { get; } + public abstract int ListViewColumnHeaderHeight { get; } + public abstract int ListViewDefaultColumnWidth { get; } + public abstract int ListViewVerticalSpacing { get; } + public abstract int ListViewEmptyColumnWidth { get; } + public abstract int ListViewHorizontalSpacing { get; } + public abstract Size ListViewDefaultSize { get; } + public abstract int ListViewGroupHeight { get; } + public abstract int ListViewItemPaddingWidth { get; } + public abstract int ListViewTileWidthFactor { get; } + public abstract int ListViewTileHeightFactor { get; } + #endregion // ListView + + #region Menus + public abstract void CalcItemSize (Graphics dc, MenuItem item, int y, int x, bool menuBar); + public abstract void CalcPopupMenuSize (Graphics dc, Menu menu); + public abstract int CalcMenuBarSize (Graphics dc, Menu menu, int width); + public abstract void DrawMenuBar (Graphics dc, Menu menu, Rectangle rect); + public abstract void DrawMenuItem (MenuItem item, DrawItemEventArgs e); + public abstract void DrawPopupMenu (Graphics dc, Menu menu, Rectangle cliparea, Rectangle rect); + #endregion // Menus + + #region MonthCalendar + public abstract void DrawMonthCalendar(Graphics dc, Rectangle clip_rectangle, MonthCalendar month_calendar); + #endregion // MonthCalendar + + #region Panel + // Sizing + public abstract Size PanelDefaultSize{get;} + #endregion // Panel + + #region PictureBox + // Drawing + public abstract void DrawPictureBox (Graphics dc, Rectangle clip, PictureBox pb); + + // Sizing + public abstract Size PictureBoxDefaultSize{get;} + #endregion // PictureBox + + /* FIXME: No printing. + #region PrintPreviewControl + public abstract int PrintPreviewControlPadding{get;} + public abstract Size PrintPreviewControlGetPageSize (PrintPreviewControl preview); + public abstract void PrintPreviewWidgetPaint (PaintEventArgs pe, PrintPreviewControl preview, Size page_image_size); + #endregion // PrintPreviewControl +*/ + #region ProgressBar + // Drawing + public abstract void DrawProgressBar (Graphics dc, Rectangle clip_rectangle, ProgressBar progress_bar); + + // Sizing + public abstract Size ProgressBarDefaultSize{get;} + #endregion // ProgressBar + + #region RadioButton + // Drawing + public abstract Size CalculateRadioButtonAutoSize (RadioButton rb); + public abstract void CalculateRadioButtonTextAndImageLayout (ButtonBase b, Point offset, out Rectangle glyphArea, out Rectangle textRectangle, out Rectangle imageRectangle); + public abstract void DrawRadioButton (Graphics g, RadioButton rb, Rectangle glyphArea, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle); + public abstract void DrawRadioButton (Graphics dc, Rectangle clip_rectangle, RadioButton radio_button); + + // Sizing + public abstract Size RadioButtonDefaultSize{get;} + #endregion // RadioButton + + #region ScrollBar + // Drawing + //public abstract void DrawScrollBar (Graphics dc, Rectangle area, ScrollBar bar, ref Rectangle thumb_pos, ref Rectangle first_arrow_area, ref Rectangle second_arrow_area, ButtonState first_arrow, ButtonState second_arrow, ref int scrollbutton_width, ref int scrollbutton_height, bool vert); + public abstract void DrawScrollBar (Graphics dc, Rectangle clip_rectangle, ScrollBar bar); + + // Sizing + public abstract int ScrollBarButtonSize {get;} // Size of the scroll button + + public abstract bool ScrollBarHasHotElementStyles { get; } + + public abstract bool ScrollBarHasPressedThumbStyle { get; } + + public abstract bool ScrollBarHasHoverArrowButtonStyle { get; } + #endregion // ScrollBar + + #region StatusBar + // Drawing + public abstract void DrawStatusBar (Graphics dc, Rectangle clip_rectangle, StatusBar sb); + + // Sizing + public abstract int StatusBarSizeGripWidth {get;} // Size of Resize area + public abstract int StatusBarHorzGapWidth {get;} // Gap between panels + public abstract Size StatusBarDefaultSize{get;} + #endregion // StatusBar + + #region TabControl + public abstract Size TabControlDefaultItemSize {get; } + public abstract Point TabControlDefaultPadding {get; } + public abstract int TabControlMinimumTabWidth {get; } + public abstract Rectangle TabWidgetselectedDelta { get; } + public abstract int TabWidgetselectedSpacing { get; } + public abstract int TabPanelOffsetX { get; } + public abstract int TabPanelOffsetY { get; } + public abstract int TabControlColSpacing { get; } + public abstract Point TabControlImagePadding { get; } + public abstract int TabWidgetscrollerWidth { get; } + + public abstract Rectangle TabControlGetDisplayRectangle (TabWidget tab); + public abstract Rectangle TabControlGetPanelRect (TabWidget tab); + public abstract Size TabControlGetSpacing (TabWidget tab); + public abstract void DrawTabControl (Graphics dc, Rectangle area, TabWidget tab); + #endregion + + #region TextBoxBase + public abstract void TextBoxBaseFillBackground (TextBoxBase textBoxBase, Graphics g, Rectangle clippingArea); + public abstract bool TextBoxBaseHandleWmNcPaint (TextBoxBase textBoxBase, ref Message m); + public abstract bool TextBoxBaseShouldPaintBackground (TextBoxBase textBoxBase); + #endregion + + /*#region ToolBar + // Drawing + public abstract void DrawToolBar (Graphics dc, Rectangle clip_rectangle, ToolBar control); + + // Sizing + public abstract int ToolBarGripWidth {get;} // Grip width for the ToolBar + public abstract int ToolBarImageGripWidth {get;} // Grip width for the Image on the ToolBarButton + public abstract int ToolBarSeparatorWidth {get;} // width of the separator + public abstract int ToolBarDropDownWidth { get; } // width of the dropdown arrow rect + public abstract int ToolBarDropDownArrowWidth { get; } // width for the dropdown arrow on the ToolBarButton + public abstract int ToolBarDropDownArrowHeight { get; } // height for the dropdown arrow on the ToolBarButton + public abstract Size ToolBarDefaultSize{get;} + + public abstract bool ToolBarHasHotElementStyles (ToolBar toolBar); + public abstract bool ToolBarHasHotCheckedElementStyles { get; } + #endregion // ToolBar +*/ + + #region ToolTip + public abstract void DrawToolTip(Graphics dc, Rectangle clip_rectangle, ToolTip.ToolTipWindow control); + public abstract Size ToolTipSize(ToolTip.ToolTipWindow tt, string text); + public abstract bool ToolTipTransparentBackground { get; } + #endregion // ToolTip + + #region BalloonWindow + public abstract void ShowBalloonWindow (IntPtr handle, int timeout, string title, string text, ToolTipIcon icon); + public abstract void HideBalloonWindow (IntPtr handle); + public abstract void DrawBalloonWindow (Graphics dc, Rectangle clip, NotifyIcon.BalloonWindow control); + public abstract Rectangle BalloonWindowRect (NotifyIcon.BalloonWindow control); + #endregion // BalloonWindow + + #region TrackBar + // Drawing + public abstract void DrawTrackBar (Graphics dc, Rectangle clip_rectangle, TrackBar tb); + + // Sizing + public abstract Size TrackBarDefaultSize{get; } // Default size for the TrackBar control + + public abstract int TrackBarValueFromMousePosition (int x, int y, TrackBar tb); + + public abstract bool TrackBarHasHotThumbStyle { get; } + #endregion // TrackBar + + #region UpDownBase + public abstract void UpDownBaseDrawButton (Graphics g, Rectangle bounds, bool top, VisualStyles.PushButtonState state); + public abstract bool UpDownBaseHasHotButtonStyle { get; } + #endregion + + #region VScrollBar + public abstract Size VScrollBarDefaultSize{get;} // Default size of the scrollbar + #endregion // VScrollBar + + #region TreeView + public abstract Size TreeViewDefaultSize { get; } + public abstract void TreeViewDrawNodePlusMinus (TreeView treeView, TreeNode node, Graphics dc, int x, int middle); + #endregion + + #region Managed window + public abstract void DrawManagedWindowDecorations (Graphics dc, Rectangle clip, InternalWindowManager wm); + public abstract int ManagedWindowTitleBarHeight (InternalWindowManager wm); + public abstract int ManagedWindowBorderWidth (InternalWindowManager wm); + public abstract int ManagedWindowIconWidth (InternalWindowManager wm); + public abstract Size ManagedWindowButtonSize (InternalWindowManager wm); + public abstract void ManagedWindowSetButtonLocations (InternalWindowManager wm); + public abstract Rectangle ManagedWindowGetTitleBarIconArea (InternalWindowManager wm); + public abstract Size ManagedWindowGetMenuButtonSize (InternalWindowManager wm); + public abstract bool ManagedWindowTitleButtonHasHotElementStyle (TitleButton button, Form form); + public abstract void ManagedWindowDrawMenuButton (Graphics dc, TitleButton button, Rectangle clip, InternalWindowManager wm); + public abstract void ManagedWindowOnSizeInitializedOrChanged (Form form); + public const int ManagedWindowSpacingAfterLastTitleButton = 2; + #endregion + + #region WidgetPaint Methods + public abstract void CPDrawBorder (Graphics graphics, Rectangle bounds, Color leftColor, int leftWidth, + ButtonBorderStyle leftStyle, Color topColor, int topWidth, ButtonBorderStyle topStyle, + Color rightColor, int rightWidth, ButtonBorderStyle rightStyle, Color bottomColor, + int bottomWidth, ButtonBorderStyle bottomStyle); + + public abstract void CPDrawBorder (Graphics graphics, RectangleF bounds, Color leftColor, int leftWidth, + ButtonBorderStyle leftStyle, Color topColor, int topWidth, ButtonBorderStyle topStyle, + Color rightColor, int rightWidth, ButtonBorderStyle rightStyle, Color bottomColor, + int bottomWidth, ButtonBorderStyle bottomStyle); + + public abstract void CPDrawBorder3D (Graphics graphics, Rectangle rectangle, Border3DStyle style, Border3DSide sides); + public abstract void CPDrawBorder3D (Graphics graphics, Rectangle rectangle, Border3DStyle style, Border3DSide sides, Color control_color); + public abstract void CPDrawButton (Graphics graphics, Rectangle rectangle, ButtonState state); + public abstract void CPDrawCaptionButton (Graphics graphics, Rectangle rectangle, CaptionButton button, ButtonState state); + public abstract void CPDrawCheckBox (Graphics graphics, Rectangle rectangle, ButtonState state); + public abstract void CPDrawComboButton (Graphics graphics, Rectangle rectangle, ButtonState state); + public abstract void CPDrawContainerGrabHandle (Graphics graphics, Rectangle bounds); + public abstract void CPDrawFocusRectangle (Graphics graphics, Rectangle rectangle, Color foreColor, Color backColor); + public abstract void CPDrawGrabHandle (Graphics graphics, Rectangle rectangle, bool primary, bool enabled); + public abstract void CPDrawGrid (Graphics graphics, Rectangle area, Size pixelsBetweenDots, Color backColor); + public abstract void CPDrawImageDisabled (Graphics graphics, Image image, int x, int y, Color background); + public abstract void CPDrawLockedFrame (Graphics graphics, Rectangle rectangle, bool primary); + public abstract void CPDrawMenuGlyph (Graphics graphics, Rectangle rectangle, MenuGlyph glyph, Color color, Color backColor); + public abstract void CPDrawMixedCheckBox (Graphics graphics, Rectangle rectangle, ButtonState state); + public abstract void CPDrawRadioButton (Graphics graphics, Rectangle rectangle, ButtonState state); + public abstract void CPDrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style); + public abstract void CPDrawReversibleLine (Point start, Point end, Color backColor); + public abstract void CPDrawScrollButton (Graphics graphics, Rectangle rectangle, ScrollButton button, ButtonState state); + public abstract void CPDrawSelectionFrame (Graphics graphics, bool active, Rectangle outsideRect, Rectangle insideRect, + Color backColor); + public abstract void CPDrawSizeGrip (Graphics graphics, Color backColor, Rectangle bounds); + public abstract void CPDrawStringDisabled (Graphics graphics, string s, Font font, Color color, RectangleF layoutRectangle, + StringFormat format); + public abstract void CPDrawStringDisabled (IDeviceContext dc, string s, Font font, Color color, Rectangle layoutRectangle, TextFormatFlags format); + public abstract void CPDrawVisualStyleBorder (Graphics graphics, Rectangle bounds); + public abstract void CPDrawBorderStyle (Graphics dc, Rectangle area, BorderStyle border_style); + #endregion // WidgetPaint Methods + } +} diff --git a/source/ShiftUI/Internal/Timer.cs b/source/ShiftUI/Internal/Timer.cs new file mode 100644 index 0000000..e51c40d --- /dev/null +++ b/source/ShiftUI/Internal/Timer.cs @@ -0,0 +1,170 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +using System; +using System.Threading; +using System.ComponentModel; + +namespace ShiftUI { + [DefaultProperty("Interval")] + [DefaultEvent("Tick")] + [ToolboxItemFilter("ShiftUI", ToolboxItemFilterType.Allow)] + public class Timer : Component { + + private bool enabled; + private int interval = 100; + private DateTime expires; + internal Thread thread; + internal bool Busy; + internal IntPtr window; + object Widget_tag; + + internal static readonly int Minimum = 15; + + public Timer () + { + enabled = false; + } + + public Timer (IContainer container) : this () + { + container.Add (this); + } + + [DefaultValue (false)] + public virtual bool Enabled { + get { + return enabled; + } + set { + if (value != enabled) { + enabled = value; + if (value) { + // Use AddTicks so we get some rounding + expires = DateTime.UtcNow.AddMilliseconds (interval > Minimum ? interval : Minimum); + + thread = Thread.CurrentThread; + XplatUI.SetTimer (this); + } else { + XplatUI.KillTimer (this); + thread = null; + } + } + } + } + + [DefaultValue (100)] + public int Interval { + get { + return interval; + } + set { + if (value <= 0) + throw new ArgumentOutOfRangeException ("Interval", string.Format ("'{0}' is not a valid value for Interval. Interval must be greater than 0.", value)); + + if (interval == value) { + return; + } + + interval = value; + + // Use AddTicks so we get some rounding + expires = DateTime.UtcNow.AddMilliseconds (interval > Minimum ? interval : Minimum); + + if (enabled == true) { + XplatUI.KillTimer (this); + XplatUI.SetTimer (this); + } + } + } + + [Localizable(false)] + [Bindable(true)] + [TypeConverter(typeof(StringConverter))] + [DefaultValue(null)] + [MWFCategory("Data")] + public object Tag { + get { + return Widget_tag; + } + + set { + Widget_tag = value; + } + } + + public void Start () + { + Enabled = true; + } + + public void Stop () + { + Enabled = false; + } + + internal DateTime Expires { + get { + return expires; + } + } + + public event EventHandler Tick; + + public override string ToString () + { + return base.ToString () + ", Interval: " + Interval; + } + + internal void Update (DateTime update) + { + expires = update.AddMilliseconds (interval > Minimum ? interval : Minimum); + } + + internal void FireTick () + { + OnTick (EventArgs.Empty); + } + + + protected virtual void OnTick (EventArgs e) + { + if (Tick != null) + Tick (this, e); + } + + protected override void Dispose (bool disposing) + { + base.Dispose (disposing); + Enabled = false; + } + + internal void TickHandler (object sender, EventArgs e) + { + OnTick (e); + } + } +} + diff --git a/source/ShiftUI/Internal/ToolBarAppearance.cs b/source/ShiftUI/Internal/ToolBarAppearance.cs new file mode 100644 index 0000000..ef3e110 --- /dev/null +++ b/source/ShiftUI/Internal/ToolBarAppearance.cs @@ -0,0 +1,40 @@ +// +// ShiftUI.ToolBarAppearance.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (C) 2004 Novell, Inc. +// +// Authors: +// Ravindra (rkumar@novell.com) +// +// + + +// COMPLETE + +namespace ShiftUI +{ + public enum ToolBarAppearance + { + Normal = 0, + Flat = 1 + } +} diff --git a/source/ShiftUI/Internal/ToolBarButtonStyle.cs b/source/ShiftUI/Internal/ToolBarButtonStyle.cs new file mode 100644 index 0000000..fffcd99 --- /dev/null +++ b/source/ShiftUI/Internal/ToolBarButtonStyle.cs @@ -0,0 +1,41 @@ +// +// ShiftUI.ToolBarButtonStyle.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (C) 2004 Novell, Inc. +// +// Authors: +// Ravindra (rkumar@novell.com) +// + + +// COMPLETE + +namespace ShiftUI +{ + public enum ToolBarButtonStyle + { + PushButton = 1, + ToggleButton = 2, + Separator = 3, + DropDownButton =4 + } +} diff --git a/source/ShiftUI/Internal/ToolBarTextAlign.cs b/source/ShiftUI/Internal/ToolBarTextAlign.cs new file mode 100644 index 0000000..9850ca6 --- /dev/null +++ b/source/ShiftUI/Internal/ToolBarTextAlign.cs @@ -0,0 +1,39 @@ +// +// ShiftUI.ToolBarTextAlign.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (C) 2004 Novell, Inc. +// +// Authors: +// Ravindra (rkumar@novell.com) +// + + +// COMPLETE + +namespace ShiftUI +{ + public enum ToolBarTextAlign + { + Underneath = 0, + Right = 1 + } +} diff --git a/source/ShiftUI/Internal/ToolTip.cs b/source/ShiftUI/Internal/ToolTip.cs new file mode 100644 index 0000000..24895fb --- /dev/null +++ b/source/ShiftUI/Internal/ToolTip.cs @@ -0,0 +1,1004 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +using System.Collections; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Text; +using ShiftUI; +using System; + +namespace ShiftUI { + [DefaultEvent ("Popup")] + [ProvideProperty ("ToolTip", typeof(Widget))] + [ToolboxItemFilter("ShiftUI", ToolboxItemFilterType.Allow)] + public class ToolTip : System.ComponentModel.Component, System.ComponentModel.IExtenderProvider { + #region Local variables + internal bool is_active; + internal int automatic_delay; + internal int autopop_delay; + internal int initial_delay; + internal int re_show_delay; + internal bool show_always; + + internal Color back_color; + internal Color fore_color; + + internal ToolTipWindow tooltip_window; // The actual tooltip window + internal Hashtable tooltip_strings; // List of strings for each Widget, indexed by Widget + internal ArrayList Widgets; + internal Widget active_Widget; // Widget for which the tooltip is currently displayed + internal Widget last_Widget; // last Widget the mouse was in + internal Timer timer; // Used for the various intervals + private Form hooked_form; + + private bool isBalloon; + private bool owner_draw; + private bool stripAmpersands; + private ToolTipIcon tool_tip_icon; + private bool useAnimation; + private bool useFading; + private object tag; + + #endregion // Local variables + + #region ToolTipWindow Class + internal class ToolTipWindow : Widget { + #region ToolTipWindow Class Local Variables + private Widget associated_Widget; + internal Icon icon; + internal string title = String.Empty; + internal Rectangle icon_rect; + internal Rectangle title_rect; + internal Rectangle text_rect; + #endregion // ToolTipWindow Class Local Variables + + #region ToolTipWindow Class Constructor + internal ToolTipWindow() { + Visible = false; + Size = new Size(100, 20); + ForeColor = ThemeEngine.Current.ColorInfoText; + BackColor = ThemeEngine.Current.ColorInfo; + + VisibleChanged += new EventHandler(ToolTipWindow_VisibleChanged); + + // UIA Framework: Used to generate UnPopup + VisibleChanged += new EventHandler (OnUIAToolTip_VisibleChanged); + + SetStyle (Widgetstyles.UserPaint | Widgetstyles.AllPaintingInWmPaint, true); + SetStyle (Widgetstyles.ResizeRedraw, true); + if (ThemeEngine.Current.ToolTipTransparentBackground) { + SetStyle (Widgetstyles.SupportsTransparentBackColor, true); + BackColor = Color.Transparent; + } else + SetStyle (Widgetstyles.Opaque, true); + } + + #endregion // ToolTipWindow Class Constructor + + #region ToolTipWindow Class Protected Instance Methods + protected override void OnCreateWidget() { + base.OnCreateWidget (); + XplatUI.SetTopmost(this.window.Handle, true); + } + + protected override CreateParams CreateParams { + get { + CreateParams cp; + + cp = base.CreateParams; + + cp.Style = (int)WindowStyles.WS_POPUP; + cp.Style |= (int)WindowStyles.WS_CLIPSIBLINGS; + + cp.ExStyle = (int)(WindowExStyles.WS_EX_TOOLWINDOW | WindowExStyles.WS_EX_TOPMOST); + + return cp; + } + } + + protected override void OnPaint(PaintEventArgs pevent) { + // We don't do double-buffering on purpose: + // 1) we'd have to meddle with is_visible, it destroys the buffers if !visible + // 2) We don't draw much, no need to double buffer + base.OnPaint(pevent); + + OnDraw (new DrawToolTipEventArgs (pevent.Graphics, associated_Widget, associated_Widget, ClientRectangle, this.Text, this.BackColor, this.ForeColor, this.Font)); + } + + protected override void OnTextChanged (EventArgs args) + { + Invalidate (); + base.OnTextChanged (args); + } + + protected override void WndProc(ref Message m) { + if (m.Msg == (int)Msg.WM_SETFOCUS) { + if (m.WParam != IntPtr.Zero) { + XplatUI.SetFocus(m.WParam); + } + } + base.WndProc (ref m); + } + + + #endregion // ToolTipWindow Class Protected Instance Methods + + #region ToolTipWindow Class Private Methods + internal virtual void OnDraw (DrawToolTipEventArgs e) + { + DrawToolTipEventHandler eh = (DrawToolTipEventHandler)(Events[DrawEvent]); + if (eh != null) + eh (this, e); + else + ThemeEngine.Current.DrawToolTip (e.Graphics, e.Bounds, this); + } + + internal virtual void OnPopup (PopupEventArgs e) + { + PopupEventHandler eh = (PopupEventHandler)(Events[PopupEvent]); + if (eh != null) + eh (this, e); + else + e.ToolTipSize = ThemeEngine.Current.ToolTipSize (this, Text); + } + + private void ToolTipWindow_VisibleChanged(object sender, EventArgs e) { + Widget Widget = (Widget)sender; + + if (Widget.is_visible) { + XplatUI.SetTopmost(Widget.window.Handle, true); + } else { + XplatUI.SetTopmost(Widget.window.Handle, false); + } + } + + // UIA Framework + private void OnUIAToolTip_VisibleChanged (object sender, EventArgs e) + { + if (Visible == false) + OnUnPopup (new PopupEventArgs (associated_Widget, associated_Widget, false, Size.Empty)); + } + + private void OnUnPopup (PopupEventArgs e) + { + PopupEventHandler eh = (PopupEventHandler) (Events [UnPopupEvent]); + if (eh != null) + eh (this, e); + } + + + #endregion // ToolTipWindow Class Protected Instance Methods + + #region Internal Properties + internal override bool ActivateOnShow { get { return false; } } + #endregion + + // This Present is used when we are using the expicit Show methods for 2.0. + // It will not reposition the window. + public void PresentModal (Widget Widget, string text) + { + if (IsDisposed) + return; + + Size display_size; + XplatUI.GetDisplaySize (out display_size); + + associated_Widget = Widget; + + Text = text; + + PopupEventArgs pea = new PopupEventArgs (Widget, Widget, false, Size.Empty); + OnPopup (pea); + + if (pea.Cancel) + return; + + Size = pea.ToolTipSize; + + Visible = true; + } + + public void Present (Widget Widget, string text) + { + if (IsDisposed) + return; + + Size display_size; + XplatUI.GetDisplaySize (out display_size); + + associated_Widget = Widget; + + Text = text; + + PopupEventArgs pea = new PopupEventArgs (Widget, Widget, false, Size.Empty); + OnPopup (pea); + + if (pea.Cancel) + return; + + Size size = pea.ToolTipSize; + + Width = size.Width; + Height = size.Height; + + int cursor_w, cursor_h, hot_x, hot_y; + XplatUI.GetCursorInfo (Widget.Cursor.Handle, out cursor_w, out cursor_h, out hot_x, out hot_y); + Point loc = Widget.MousePosition; + loc.Y += (cursor_h - hot_y); + + if ((loc.X + Width) > display_size.Width) + loc.X = display_size.Width - Width; + + if ((loc.Y + Height) > display_size.Height) + loc.Y = Widget.MousePosition.Y - Height - hot_y; + + Location = loc; + Visible = true; + BringToFront (); + } + + + #region Internal Events + static object DrawEvent = new object (); + static object PopupEvent = new object (); + + // UIA Framework + static object UnPopupEvent = new object (); + + public event DrawToolTipEventHandler Draw { + add { Events.AddHandler (DrawEvent, value); } + remove { Events.RemoveHandler (DrawEvent, value); } + } + + public event PopupEventHandler Popup { + add { Events.AddHandler (PopupEvent, value); } + remove { Events.RemoveHandler (PopupEvent, value); } + } + + internal event PopupEventHandler UnPopup { + add { Events.AddHandler (UnPopupEvent, value); } + remove { Events.RemoveHandler (UnPopupEvent, value); } + } + #endregion + } + #endregion // ToolTipWindow Class + + #region Public Constructors & Destructors + public ToolTip() { + + // Defaults from MS + is_active = true; + automatic_delay = 500; + autopop_delay = 5000; + initial_delay = 500; + re_show_delay = 100; + show_always = false; + back_color = SystemColors.Info; + fore_color = SystemColors.InfoText; + + isBalloon = false; + stripAmpersands = false; + useAnimation = true; + useFading = true; + tooltip_strings = new Hashtable(5); + Widgets = new ArrayList(5); + + tooltip_window = new ToolTipWindow(); + tooltip_window.MouseLeave += new EventHandler(Widget_MouseLeave); + tooltip_window.Draw += new DrawToolTipEventHandler (tooltip_window_Draw); + tooltip_window.Popup += new PopupEventHandler (tooltip_window_Popup); + + // UIA Framework: Static event handlers + tooltip_window.UnPopup += delegate (object sender, PopupEventArgs args) { + OnUnPopup (args); + }; + UnPopup += new PopupEventHandler (OnUIAUnPopup); + + timer = new Timer(); + timer.Enabled = false; + timer.Tick +=new EventHandler(timer_Tick); + + } + + + #region UIA Framework: Events, Delegates and Methods + // NOTE: + // We are using Reflection to add/remove internal events. + // Class ToolTipListener uses the events. + // + // - UIAUnPopup. Event used to generate ChildRemoved in ToolTip + // - UIAToolTipHookUp. Event used to keep track of associated Widgets + // - UIAToolTipUnhookUp. Event used to remove track of associated Widgets + static object UnPopupEvent = new object (); + + internal event PopupEventHandler UnPopup { + add { Events.AddHandler (UnPopupEvent, value); } + remove { Events.RemoveHandler (UnPopupEvent, value); } + } + + internal static event PopupEventHandler UIAUnPopup; + internal static event WidgetEventHandler UIAToolTipHookUp; + internal static event WidgetEventHandler UIAToolTipUnhookUp; + + internal Rectangle UIAToolTipRectangle { + get { return tooltip_window.Bounds; } + } + + internal static void OnUIAUnPopup (object sender, PopupEventArgs args) + { + if (UIAUnPopup != null) + UIAUnPopup (sender, args); + } + + internal static void OnUIAToolTipHookUp (object sender, WidgetEventArgs args) + { + if (UIAToolTipHookUp != null) + UIAToolTipHookUp (sender, args); + } + + internal static void OnUIAToolTipUnhookUp (object sender, WidgetEventArgs args) + { + if (UIAToolTipUnhookUp != null) + UIAToolTipUnhookUp (sender, args); + } + + #endregion + + public ToolTip(System.ComponentModel.IContainer cont) : this() { + cont.Add (this); + } + + ~ToolTip() { + } + #endregion // Public Constructors & Destructors + + #region Public Instance Properties + [DefaultValue (true)] + public bool Active { + get { + return is_active; + } + + set { + if (is_active != value) { + is_active = value; + + if (tooltip_window.Visible) { + tooltip_window.Visible = false; + active_Widget = null; + } + } + } + } + + [DefaultValue (500)] + [RefreshProperties (RefreshProperties.All)] + public int AutomaticDelay { + get { + return automatic_delay; + } + + set { + if (automatic_delay != value) { + automatic_delay = value; + autopop_delay = automatic_delay * 10; + initial_delay = automatic_delay; + re_show_delay = automatic_delay / 5; + } + } + } + + [RefreshProperties (RefreshProperties.All)] + public int AutoPopDelay { + get { + return autopop_delay; + } + + set { + if (autopop_delay != value) { + autopop_delay = value; + } + } + } + + [DefaultValue ("Color [Info]")] + public Color BackColor { + get { return this.back_color; } + set { this.back_color = value; tooltip_window.BackColor = value; } + } + + [DefaultValue ("Color [InfoText]")] + public Color ForeColor + { + get { return this.fore_color; } + set { this.fore_color = value; tooltip_window.ForeColor = value; } + } + + [RefreshProperties (RefreshProperties.All)] + public int InitialDelay { + get { + return initial_delay; + } + + set { + if (initial_delay != value) { + initial_delay = value; + } + } + } + + [DefaultValue (false)] + public bool OwnerDraw { + get { return this.owner_draw; } + set { this.owner_draw = value; } + } + + [RefreshProperties (RefreshProperties.All)] + public int ReshowDelay { + get { + return re_show_delay; + } + + set { + if (re_show_delay != value) { + re_show_delay = value; + } + } + } + + [DefaultValue (false)] + public bool ShowAlways { + get { + return show_always; + } + + set { + if (show_always != value) { + show_always = value; + } + } + } + + + [DefaultValue (false)] + public bool IsBalloon { + get { return isBalloon; } + set { isBalloon = value; } + } + + [Browsable (true)] + [DefaultValue (false)] + public bool StripAmpersands { + get { return stripAmpersands; } + set { stripAmpersands = value; } + } + + [Localizable (false)] + [Bindable (true)] + [TypeConverter (typeof (StringConverter))] + [DefaultValue (null)] + public object Tag { + get { return tag; } + set { tag = value; } + } + + [DefaultValue (ToolTipIcon.None)] + public ToolTipIcon ToolTipIcon { + get { return this.tool_tip_icon; } + set { + switch (value) { + case ToolTipIcon.None: + tooltip_window.icon = null; + break; + case ToolTipIcon.Error: + tooltip_window.icon = SystemIcons.Error; + break; + case ToolTipIcon.Warning: + tooltip_window.icon = SystemIcons.Warning; + break; + case ToolTipIcon.Info: + tooltip_window.icon = SystemIcons.Information; + break; + } + + tool_tip_icon = value; + } + } + + [DefaultValue ("")] + public string ToolTipTitle { + get { return tooltip_window.title; } + set { + if (value == null) + value = String.Empty; + + tooltip_window.title = value; + } + } + + [Browsable (true)] + [DefaultValue (true)] + public bool UseAnimation { + get { return useAnimation; } + set { useAnimation = value; } + } + + [Browsable (true)] + [DefaultValue (true)] + public bool UseFading { + get { return useFading; } + set { useFading = value; } + } + + #endregion // Public Instance Properties + + #region Protected Properties + protected virtual CreateParams CreateParams + { + get + { + CreateParams cp = new CreateParams (); + + cp.Style = 2; + + return cp; + } + } + #endregion + + #region Public Instance Methods + public bool CanExtend(object target) { + return false; + } + + [Localizable (true)] + [DefaultValue ("")] + public string GetToolTip (Widget Widget) + { + string tooltip = (string)tooltip_strings[Widget]; + if (tooltip == null) + return ""; + return tooltip; + } + + public void RemoveAll() { + tooltip_strings.Clear(); + //UIA Framework: ToolTip isn't associated anymore + foreach (Widget Widget in Widgets) + OnUIAToolTipUnhookUp (this, new WidgetEventArgs (Widget)); + + Widgets.Clear(); + } + + public void SetToolTip(Widget Widget, string caption) { + // UIA Framework + OnUIAToolTipHookUp (this, new WidgetEventArgs (Widget)); + tooltip_strings[Widget] = caption; + + // no need for duplicates + if (!Widgets.Contains(Widget)) { + Widget.MouseEnter += new EventHandler(Widget_MouseEnter); + Widget.MouseMove += new MouseEventHandler(Widget_MouseMove); + Widget.MouseLeave += new EventHandler(Widget_MouseLeave); + Widget.MouseDown += new MouseEventHandler (Widget_MouseDown); + Widgets.Add(Widget); + } + + // if SetToolTip is called from a Widget and the mouse is currently over that Widget, + // make sure that tooltip_window.Text gets updated if it's being shown, + // or show the tooltip for it if is not + if (active_Widget == Widget && caption != null && state == TipState.Show) { + Size size = ThemeEngine.Current.ToolTipSize(tooltip_window, caption); + tooltip_window.Width = size.Width; + tooltip_window.Height = size.Height; + tooltip_window.Text = caption; + timer.Stop (); + timer.Start (); + } else if (Widget.IsHandleCreated && MouseInWidget (Widget, false)) + ShowTooltip (Widget); + } + + public override string ToString() { + return base.ToString() + " InitialDelay: " + initial_delay + ", ShowAlways: " + show_always; + } + + public void Show (string text, IWin32Window window) + { + Show (text, window, 0); + } + + public void Show (string text, IWin32Window window, int duration) + { + if (window == null) + throw new ArgumentNullException ("window"); + if (duration < 0) + throw new ArgumentOutOfRangeException ("duration", "duration cannot be less than zero"); + + if (!Active) + return; + + timer.Stop (); + + Widget c = (Widget)window; + + XplatUI.SetOwner (tooltip_window.Handle, c.TopLevelWidget.Handle); + + // If the mouse is in the requested window, use that position + // Else, center in the requested window + if (c.ClientRectangle.Contains (c.PointToClient (Widget.MousePosition))) { + tooltip_window.Location = Widget.MousePosition; + tooltip_strings[c] = text; + HookupWidgetEvents (c); + } + else + tooltip_window.Location = c.PointToScreen (new Point (c.Width / 2, c.Height / 2)); + + // We need to hide our tooltip if the form loses focus, is closed, or is minimized + HookupFormEvents ((Form)c.TopLevelWidget); + + tooltip_window.PresentModal ((Widget)window, text); + + state = TipState.Show; + + if (duration > 0) { + timer.Interval = duration; + timer.Start (); + } + } + + public void Show (string text, IWin32Window window, Point point) + { + Show (text, window, point, 0); + } + + public void Show (string text, IWin32Window window, int x, int y) + { + Show (text, window, new Point (x, y), 0); + } + + public void Show (string text, IWin32Window window, Point point, int duration) + { + if (window == null) + throw new ArgumentNullException ("window"); + if (duration < 0) + throw new ArgumentOutOfRangeException ("duration", "duration cannot be less than zero"); + + if (!Active) + return; + + timer.Stop (); + + Widget c = (Widget)window; + + Point display_point = c.PointToScreen (Point.Empty); + display_point.X += point.X; + display_point.Y += point.Y; + + XplatUI.SetOwner (tooltip_window.Handle, c.TopLevelWidget.Handle); + + // We need to hide our tooltip if the form loses focus, is closed, or is minimized + HookupFormEvents ((Form)c.TopLevelWidget); + + tooltip_window.Location = display_point; + tooltip_window.PresentModal ((Widget)window, text); + + state = TipState.Show; + + if (duration > 0) { + timer.Interval = duration; + timer.Start (); + } + } + + public void Show (string text, IWin32Window window, int x, int y, int duration) + { + Show (text, window, new Point (x, y), duration); + } + + public void Hide (IWin32Window win) + { + timer.Stop (); + state = TipState.Initial; + + UnhookFormEvents (); + tooltip_window.Visible = false; + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + protected override void Dispose(bool disposing) { + // call the base impl first to avoid conflicts with any parent's events + base.Dispose (disposing); + + if (disposing) { + // Mop up the mess; or should we wait for the GC to kick in? + timer.Stop(); + timer.Dispose(); + + // Not sure if we should clean up tooltip_window + tooltip_window.Dispose(); + + tooltip_strings.Clear(); + + //UIA Framework: ToolTip isn't associated anymore + foreach (Widget Widget in Widgets) + OnUIAToolTipUnhookUp (this, new WidgetEventArgs (Widget)); + Widgets.Clear(); + } + } + + protected void StopTimer () + { + timer.Stop (); + } + #endregion // Protected Instance Methods + + internal enum TipState { + Initial, + Show, + Down + } + + TipState state = TipState.Initial; + + #region Private Methods + + private void HookupFormEvents (Form form) + { + hooked_form = form; + + form.Deactivate += new EventHandler (Form_Deactivate); + form.Closed += new EventHandler (Form_Closed); + form.Resize += new EventHandler (Form_Resize); + } + + private void HookupWidgetEvents (Widget widget) + { + if (!Widgets.Contains (widget)) { + widget.MouseEnter += new EventHandler (Widget_MouseEnter); + widget.MouseMove += new MouseEventHandler (Widget_MouseMove); + widget.MouseLeave += new EventHandler (Widget_MouseLeave); + widget.MouseDown += new MouseEventHandler (Widget_MouseDown); + Widgets.Add (widget); + } + } + + private void UnhookWidgetEvents (Widget widget) + { + widget.MouseEnter -= new EventHandler (Widget_MouseEnter); + widget.MouseMove -= new MouseEventHandler (Widget_MouseMove); + widget.MouseLeave -= new EventHandler (Widget_MouseLeave); + widget.MouseDown -= new MouseEventHandler (Widget_MouseDown); + } + private void UnhookFormEvents () + { + if (hooked_form == null) + return; + + hooked_form.Deactivate -= new EventHandler (Form_Deactivate); + hooked_form.Closed -= new EventHandler (Form_Closed); + hooked_form.Resize -= new EventHandler (Form_Resize); + + hooked_form = null; + } + + + private void Form_Resize (object sender, EventArgs e) + { + Form f = (Form)sender; + + if (f.WindowState == FormWindowState.Minimized) + tooltip_window.Visible = false; + } + + private void Form_Closed (object sender, EventArgs e) + { + tooltip_window.Visible = false; + } + + private void Form_Deactivate (object sender, EventArgs e) + { + tooltip_window.Visible = false; + } + + internal void Present (Widget Widget, string text) + { + tooltip_window.Present (Widget, text); + } + + private void Widget_MouseEnter (object sender, EventArgs e) + { + ShowTooltip (sender as Widget); + } + + private void ShowTooltip (Widget Widget) + { + last_Widget = Widget; + + // Whatever we're displaying right now, we don't want it anymore + tooltip_window.Visible = false; + timer.Stop(); + state = TipState.Initial; + + if (!is_active) + return; + + // ShowAlways Widgets whether the Widgets in non-active forms + // can display its tooltips, even if they are not current active Widget. + if (!show_always && Widget.FindForm () != Form.ActiveForm) + return; + + string text = (string)tooltip_strings[Widget]; + if (text != null && text.Length > 0) { + if (active_Widget == null) { + timer.Interval = Math.Max (initial_delay, 1); + } else { + timer.Interval = Math.Max (re_show_delay, 1); + } + + active_Widget = Widget; + timer.Start (); + } + } + + private void timer_Tick(object sender, EventArgs e) { + timer.Stop(); + + switch (state) { + case TipState.Initial: + if (active_Widget == null) + return; + tooltip_window.Present (active_Widget, (string)tooltip_strings[active_Widget]); + state = TipState.Show; + timer.Interval = autopop_delay; + timer.Start(); + break; + + case TipState.Show: + tooltip_window.Visible = false; + state = TipState.Down; + break; + + default: + throw new Exception ("Timer shouldn't be running in state: " + state); + } + } + + private void tooltip_window_Popup (object sender, PopupEventArgs e) + { + e.ToolTipSize = ThemeEngine.Current.ToolTipSize (tooltip_window, tooltip_window.Text); + OnPopup (e); + } + + private void tooltip_window_Draw (object sender, DrawToolTipEventArgs e) + { + if (OwnerDraw) + OnDraw (e); + else + ThemeEngine.Current.DrawToolTip (e.Graphics, e.Bounds, tooltip_window); + } + + private bool MouseInWidget (Widget Widget, bool fuzzy) { + Point m; + Point c; + Size cw; + + if (Widget == null) { + return false; + } + + m = Widget.MousePosition; + c = new Point(Widget.Bounds.X, Widget.Bounds.Y); + if (Widget.Parent != null) { + c = Widget.Parent.PointToScreen(c); + } + cw = Widget.ClientSize; + + + Rectangle rect = new Rectangle (c, cw); + + // + // We won't get mouse move events on all platforms with the exact same + // frequency, so cheat a bit. + if (fuzzy) + rect.Inflate (2, 2); + + return rect.Contains (m); + } + + private void Widget_MouseLeave(object sender, EventArgs e) + { + timer.Stop (); + + active_Widget = null; + tooltip_window.Visible = false; + + if (last_Widget == sender) + last_Widget = null; + } + + + void Widget_MouseDown (object sender, MouseEventArgs e) + { + timer.Stop(); + + active_Widget = null; + tooltip_window.Visible = false; + + if (last_Widget == sender) + last_Widget = null; + } + + private void Widget_MouseMove(object sender, MouseEventArgs e) { + if (state != TipState.Down) { + timer.Stop(); + timer.Start(); + } + } + + internal void OnDraw (DrawToolTipEventArgs e) + { + DrawToolTipEventHandler eh = (DrawToolTipEventHandler)(Events[DrawEvent]); + if (eh != null) + eh (this, e); + } + + internal void OnPopup (PopupEventArgs e) + { + PopupEventHandler eh = (PopupEventHandler) (Events [PopupEvent]); + if (eh != null) + eh (this, e); + } + + internal void OnUnPopup (PopupEventArgs e) + { + PopupEventHandler eh = (PopupEventHandler) (Events [UnPopupEvent]); + if (eh != null) + eh (this, e); + } + + internal bool Visible { + get { return tooltip_window.Visible; } + } + #endregion // Private Methods + + #region Events + static object PopupEvent = new object (); + static object DrawEvent = new object (); + + public event PopupEventHandler Popup { + add { Events.AddHandler (PopupEvent, value); } + remove { Events.RemoveHandler (PopupEvent, value); } + } + + public event DrawToolTipEventHandler Draw { + add { Events.AddHandler (DrawEvent, value); } + remove { Events.RemoveHandler (DrawEvent, value); } + } + #endregion + } +} diff --git a/source/ShiftUI/Internal/ToolTipIcon.cs b/source/ShiftUI/Internal/ToolTipIcon.cs new file mode 100644 index 0000000..2adcca8 --- /dev/null +++ b/source/ShiftUI/Internal/ToolTipIcon.cs @@ -0,0 +1,39 @@ +// +// ToolTipIcon.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum ToolTipIcon + { + None = 0, + Info = 1, + Warning = 2, + Error = 3 + } +} diff --git a/source/ShiftUI/Internal/ToolWindowManager.cs b/source/ShiftUI/Internal/ToolWindowManager.cs new file mode 100644 index 0000000..ba080d7 --- /dev/null +++ b/source/ShiftUI/Internal/ToolWindowManager.cs @@ -0,0 +1,47 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Rolf Bjarne Kvinge (RKvinge@novell.com) +// +// + + +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + internal class ToolWindowManager : InternalWindowManager + { + public ToolWindowManager (Form form) + : base (form) + { + + } + + public override void SetWindowState (FormWindowState old_state, FormWindowState window_state) + { + // Do nothing here. + } + } +} diff --git a/source/ShiftUI/Internal/TreeNodeCollection.cs b/source/ShiftUI/Internal/TreeNodeCollection.cs new file mode 100644 index 0000000..5323579 --- /dev/null +++ b/source/ShiftUI/Internal/TreeNodeCollection.cs @@ -0,0 +1,611 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +using System; +using System.Collections; +using System.ComponentModel; +using System.Globalization; +using System.Collections.Generic; + +namespace ShiftUI { + //[Editor("ShiftUI.Design.TreeNodeCollectionEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))] + public class TreeNodeCollection : IList, ICollection, IEnumerable { + + private static readonly int OrigSize = 50; + + private TreeNode owner; + private int count; + private TreeNode [] nodes; + + private TreeNodeCollection () + { + } + + internal TreeNodeCollection (TreeNode owner) + { + this.owner = owner; + nodes = new TreeNode [OrigSize]; + } + + [Browsable(false)] + public int Count { + get { return count; } + } + + public bool IsReadOnly { + get { return false; } + } + + bool ICollection.IsSynchronized { + get { return false; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + bool IList.IsFixedSize { + get { return false; } + } + + object IList.this [int index] { + get { + return this [index]; + } + set { + if (!(value is TreeNode)) + throw new ArgumentException ("Parameter must be of type TreeNode.", "value"); + this [index] = (TreeNode) value; + } + } + + public virtual TreeNode this [int index] { + get { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("index"); + return nodes [index]; + } + set { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("index"); + SetupNode (value); + nodes [index] = value; + } + } + + public virtual TreeNode this [string key] { + get { + for (int i = 0; i < count; i++) + if (string.Compare (key, nodes[i].Name, true) == 0) + return nodes[i]; + + return null; + } + } + + bool UsingSorting { + get { + TreeView tv = owner == null ? null : owner.TreeView; + return tv != null && (tv.Sorted || tv.TreeViewNodeSorter != null); + } + } + + public virtual TreeNode Add (string text) + { + TreeNode res = new TreeNode (text); + Add (res); + return res; + } + + public virtual int Add (TreeNode node) + { + if (node == null) + throw new ArgumentNullException("node"); + + int index; + TreeView tree_view = null; + + if (owner != null) + tree_view = owner.TreeView; + + if (tree_view != null && UsingSorting) { + index = AddSorted (node); + } else { + if (count >= nodes.Length) + Grow (); + index = count; + count++; + nodes[index] = node; + } + + SetupNode (node); + + // UIA Framework Event: Collection Changed + if (tree_view != null) + tree_view.OnUIACollectionChanged (owner, new CollectionChangeEventArgs (CollectionChangeAction.Add, node)); + return index; + } + + public virtual TreeNode Add (string key, string text) + { + TreeNode node = new TreeNode (text); + node.Name = key; + Add (node); + return node; + } + + public virtual TreeNode Add (string key, string text, int imageIndex) + { + TreeNode node = Add (key, text); + node.ImageIndex = imageIndex; + return node; + } + + public virtual TreeNode Add (string key, string text, string imageKey) + { + TreeNode node = Add (key, text); + node.ImageKey = imageKey; + return node; + + } + + public virtual TreeNode Add (string key, string text, int imageIndex, int selectedImageIndex) + { + TreeNode node = Add (key, text); + node.ImageIndex = imageIndex; + node.SelectedImageIndex = selectedImageIndex; + return node; + } + + public virtual TreeNode Add (string key, string text, string imageKey, string selectedImageKey) + { + TreeNode node = Add (key, text); + node.ImageKey = imageKey; + node.SelectedImageKey = selectedImageKey; + return node; + } + + public virtual void AddRange (TreeNode [] nodes) + { + if (nodes == null) + throw new ArgumentNullException("nodes"); + + // We can't just use Array.Copy because the nodes also + // need to have some properties set when they are added. + for (int i = 0; i < nodes.Length; i++) + Add (nodes [i]); + } + + public virtual void Clear () + { + while (count > 0) + RemoveAt (0, false); + + Array.Clear (nodes, 0, count); + count = 0; + + TreeView tree_view = null; + if (owner != null) { + tree_view = owner.TreeView; + if (tree_view != null) { + tree_view.UpdateBelow (owner); + tree_view.RecalculateVisibleOrder (owner); + tree_view.UpdateScrollBars (false); + } + } + } + + public bool Contains (TreeNode node) + { + return Array.IndexOf (nodes, node, 0, count) != -1; + } + + public virtual bool ContainsKey (string key) + { + for (int i = 0; i < count; i++) { + if (string.Compare (nodes [i].Name, key, true, CultureInfo.InvariantCulture) == 0) + return true; + } + return false; + } + + public void CopyTo (Array dest, int index) + { + Array.Copy (nodes, index, dest, index, count); + } + + public IEnumerator GetEnumerator () + { + return new TreeNodeEnumerator (this); + } + + public int IndexOf (TreeNode node) + { + return Array.IndexOf (nodes, node); + } + + public virtual int IndexOfKey (string key) + { + for (int i = 0; i < count; i++) { + if (string.Compare (nodes [i].Name, key, true, CultureInfo.InvariantCulture) == 0) + return i; + } + return -1; + } + + public virtual TreeNode Insert (int index, string text) + { + TreeNode node = new TreeNode (text); + Insert (index, node); + return node; + } + + public virtual void Insert (int index, TreeNode node) + { + if (count >= nodes.Length) + Grow (); + + Array.Copy (nodes, index, nodes, index + 1, count - index); + nodes [index] = node; + count++; + + // If we can use sorting, it means we have an owner *and* a TreeView + if (UsingSorting) + Sort (owner.TreeView.TreeViewNodeSorter); + + SetupNode (node); + } + + public virtual TreeNode Insert (int index, string key, string text) + { + TreeNode node = new TreeNode (text); + node.Name = key; + Insert (index, node); + return node; + } + + public virtual TreeNode Insert (int index, string key, string text, int imageIndex) + { + TreeNode node = new TreeNode (text); + node.Name = key; + node.ImageIndex = imageIndex; + Insert (index, node); + return node; + } + + public virtual TreeNode Insert (int index, string key, string text, string imageKey) + { + TreeNode node = new TreeNode (text); + node.Name = key; + node.ImageKey = imageKey; + Insert (index, node); + return node; + } + + public virtual TreeNode Insert (int index, string key, string text, int imageIndex, int selectedImageIndex) + { + TreeNode node = new TreeNode (text, imageIndex, selectedImageIndex); + node.Name = key; + Insert (index, node); + return node; + } + + public virtual TreeNode Insert (int index, string key, string text, string imageKey, string selectedImageKey) + { + TreeNode node = new TreeNode (text); + node.Name = key; + node.ImageKey = imageKey; + node.SelectedImageKey = selectedImageKey; + Insert (index, node); + return node; + } + + public void Remove (TreeNode node) + { + if (node == null) + throw new NullReferenceException (); + + int index = IndexOf (node); + if (index != -1) + RemoveAt (index); + } + + public virtual void RemoveAt (int index) + { + RemoveAt (index, true); + } + + private void RemoveAt (int index, bool update) + { + TreeNode removed = nodes [index]; + TreeNode prev = GetPrevNode (removed); + TreeNode new_selected = null; + bool re_set_selected = false; + bool visible = removed.IsVisible; + + TreeView tree_view = null; + if (owner != null) + tree_view = owner.TreeView; + + if (tree_view != null) { + tree_view.RecalculateVisibleOrder (prev); + + if (removed == tree_view.SelectedNode) { + if (removed.IsExpanded) + removed.Collapse(); // Fix Xamarin Bugzilla 5010. + re_set_selected = true; + OpenTreeNodeEnumerator oe = new OpenTreeNodeEnumerator (removed); + if (oe.MoveNext () && oe.MoveNext ()) { + new_selected = oe.CurrentNode; + } else { + oe = new OpenTreeNodeEnumerator (removed); + oe.MovePrevious (); + new_selected = oe.CurrentNode == removed ? null : oe.CurrentNode; + } + } + } + + Array.Copy (nodes, index + 1, nodes, index, count - index - 1); + count--; + + nodes[count] = null; + + if (nodes.Length > OrigSize && nodes.Length > (count * 2)) + Shrink (); + + if (tree_view != null && re_set_selected) { + tree_view.SelectedNode = new_selected; + } + + TreeNode parent = removed.parent; + removed.parent = null; + + if (update && tree_view != null && visible) { + tree_view.RecalculateVisibleOrder (prev); + tree_view.UpdateScrollBars (false); + tree_view.UpdateBelow (parent); + } + + // UIA Framework Event: Collection Changed + if (tree_view != null) + tree_view.OnUIACollectionChanged (owner, new CollectionChangeEventArgs (CollectionChangeAction.Remove, removed)); + } + + public virtual void RemoveByKey (string key) + { + TreeNode node = this[key]; + + if (node != null) + Remove (node); + } + + private TreeNode GetPrevNode (TreeNode node) + { + OpenTreeNodeEnumerator one = new OpenTreeNodeEnumerator (node); + + if (one.MovePrevious () && one.MovePrevious ()) + return one.CurrentNode; + return null; + } + + private void SetupNode (TreeNode node) + { + // We used to remove this from the previous parent, but .Net + // skips this step (even if setting the owner field). + //node.Remove (); + + node.parent = owner; + + TreeView tree_view = null; + if (owner != null) + tree_view = owner.TreeView; + + if (tree_view != null) { + // We may need to invalidate this entire node collection if sorted. + TreeNode prev = UsingSorting ? owner : GetPrevNode (node); + + if (tree_view.IsHandleCreated && node.ArePreviousNodesExpanded) + tree_view.RecalculateVisibleOrder (prev); + if (owner == tree_view.root_node || node.Parent.IsVisible && node.Parent.IsExpanded) + tree_view.UpdateScrollBars (false); + + tree_view.UpdateBelow (owner); + } + } + + int IList.Add (object node) + { + return Add ((TreeNode) node); + } + + bool IList.Contains (object node) + { + return Contains ((TreeNode) node); + } + + int IList.IndexOf (object node) + { + return IndexOf ((TreeNode) node); + } + + void IList.Insert (int index, object node) + { + Insert (index, (TreeNode) node); + } + + void IList.Remove (object node) + { + Remove ((TreeNode) node); + } + + private int AddSorted (TreeNode node) + { + if (count >= nodes.Length) + Grow (); + + TreeView tree_view = owner.TreeView; + if (tree_view.TreeViewNodeSorter != null) { // Custom sorting + nodes [count++] = node; + Sort (tree_view.TreeViewNodeSorter); + return count - 1; + } + + CompareInfo compare = Application.CurrentCulture.CompareInfo; + int index = 0; + bool found = false; + for (int i = 0; i < count; i++) { + index = i; + int comp = compare.Compare (node.Text, nodes [i].Text); + if (comp < 0) { + found = true; + break; + } + } + + // Stick it at the end + if (!found) + index = count; + + // Move the nodes up and adjust their indices + for (int i = count - 1; i >= index; i--) { + nodes [i + 1] = nodes [i]; + } + count++; + nodes [index] = node; + + return index; + } + + // Would be nice to do this without running through the collection twice + internal void Sort (IComparer sorter) { + Array.Sort (nodes, 0, count, sorter == null ? new TreeNodeComparer (Application.CurrentCulture.CompareInfo) : sorter); + + for (int i = 0; i < count; i++) { + nodes [i].Nodes.Sort (sorter); + } + + // Sorted may have been set to false even if TreeViewNodeSorter is being used. + TreeView tv = owner == null ? null : owner.TreeView; + if (tv != null) + tv.sorted = true; + } + + private void Grow () + { + TreeNode [] nn = new TreeNode [nodes.Length + 50]; + Array.Copy (nodes, nn, nodes.Length); + nodes = nn; + } + + private void Shrink () + { + int len = (count + 1 > OrigSize ? count + 1 : OrigSize); + TreeNode [] nn = new TreeNode [len]; + Array.Copy (nodes, nn, count); + nodes = nn; + } + + public TreeNode[] Find (string key, bool searchAllChildren) + { + List results = new List (0); + Find (key, searchAllChildren, this, results); + + return results.ToArray (); + } + + private static void Find (string key, bool searchAllChildren, TreeNodeCollection nodes, List results) + { + for (int i = 0; i < nodes.Count; i++) { + TreeNode thisNode = nodes [i]; + + if (string.Compare (thisNode.Name, key, true, CultureInfo.InvariantCulture) == 0) + results.Add (thisNode); + + } + // Need to match the Microsoft order. + + if (searchAllChildren){ + for (int i = 0; i < nodes.Count; i++){ + TreeNodeCollection childNodes = nodes [i].Nodes; + if (childNodes.Count > 0) { + Find (key, searchAllChildren, childNodes, results); + } + } + } + } + + internal class TreeNodeEnumerator : IEnumerator { + + private TreeNodeCollection collection; + private int index = -1; + + public TreeNodeEnumerator (TreeNodeCollection collection) + { + this.collection = collection; + } + + public object Current { + get { + if (index == -1) + return null; + return collection [index]; + } + } + + public bool MoveNext () + { + if (index + 1 >= collection.Count) + return false; + index++; + return true; + } + + public void Reset () + { + index = -1; + } + } + + private class TreeNodeComparer : IComparer { + + private CompareInfo compare; + + public TreeNodeComparer (CompareInfo compare) + { + this.compare = compare; + } + + public int Compare (object x, object y) + { + TreeNode l = (TreeNode) x; + TreeNode r = (TreeNode) y; + int res = compare.Compare (l.Text, r.Text); + + return (res == 0 ? l.Index - r.Index : res); + } + } + } +} + diff --git a/source/ShiftUI/Internal/TreeNodeConverter.cs b/source/ShiftUI/Internal/TreeNodeConverter.cs new file mode 100644 index 0000000..d9682b4 --- /dev/null +++ b/source/ShiftUI/Internal/TreeNodeConverter.cs @@ -0,0 +1,55 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// NOT COMPLETE + +using System.ComponentModel; +using System.Globalization; +using System; + +namespace ShiftUI { + public class TreeNodeConverter : TypeConverter { + + #region Public Instance Methods + public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof (string)) + return true; + return base.CanConvertTo (context, destinationType); + } + + public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, + object value, Type destinationType) + { + // Regardless of the type of object passed in this does a ToString + if (destinationType == typeof (string) && value != null) + return value.ToString (); + return base.ConvertTo (context, culture, value, destinationType); + } + + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Internal/TreeViewHitTestInfo.cs b/source/ShiftUI/Internal/TreeViewHitTestInfo.cs new file mode 100644 index 0000000..7e5c19a --- /dev/null +++ b/source/ShiftUI/Internal/TreeViewHitTestInfo.cs @@ -0,0 +1,51 @@ +// +// TreeViewHitTestLocations.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// + + +namespace ShiftUI { + + public class TreeViewHitTestInfo { + + private TreeNode node; + private TreeViewHitTestLocations location; + + public TreeViewHitTestInfo (TreeNode hitNode, TreeViewHitTestLocations hitLocation) + { + this.node = hitNode; + this.location = hitLocation; + } + + public TreeNode Node { + get { return node; } + } + + public TreeViewHitTestLocations Location { + get { return location; } + } + } +} diff --git a/source/ShiftUI/Internal/TreeViewImageIndexConverter.cs b/source/ShiftUI/Internal/TreeViewImageIndexConverter.cs new file mode 100644 index 0000000..f66b205 --- /dev/null +++ b/source/ShiftUI/Internal/TreeViewImageIndexConverter.cs @@ -0,0 +1,89 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +using System; +using System.Drawing; +using System.Collections; +using System.ComponentModel; + + +namespace ShiftUI { + + public class TreeViewImageIndexConverter : ImageIndexConverter { + + public TreeViewImageIndexConverter () + { + } + + #region Protected Properties + protected override bool IncludeNoneAsStandardValue { + get { return false; } + } + #endregion + + #region Public Methods + public override object ConvertFrom (System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + { + string indexStr; + + if (value != null && value is string) { + indexStr = (string)value; + + if (indexStr.Equals ("(default)", StringComparison.InvariantCultureIgnoreCase)) + return -1; + else if (indexStr.Equals ("(none)", StringComparison.InvariantCultureIgnoreCase)) + return -2; + + return Int32.Parse (indexStr); + } else + return base.ConvertFrom (context, culture, value); + } + + public override object ConvertTo (System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof (string)) { + if (value == null) + return string.Empty; + else if (value is int && (int)value == -1) + return "(default)"; + else if (value is int && (int)value == -2) + return "(none)"; + else if (value is string && ((string)value).Length == 0) + return string.Empty; + else + return value.ToString (); + } else + return base.ConvertTo (context, culture, value, destinationType); + } + + public override StandardValuesCollection GetStandardValues (System.ComponentModel.ITypeDescriptorContext context) + { + int[] stdVal = new int[] { -1, -2 }; + return new TypeConverter.StandardValuesCollection (stdVal); + } + #endregion + } +} + diff --git a/source/ShiftUI/Internal/TreeViewImageKeyConverter.cs b/source/ShiftUI/Internal/TreeViewImageKeyConverter.cs new file mode 100644 index 0000000..78ff1d5 --- /dev/null +++ b/source/ShiftUI/Internal/TreeViewImageKeyConverter.cs @@ -0,0 +1,51 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Jonathan Pobst monkey@jpobst.com +// + +using System.Drawing; +using System.ComponentModel; +using System.Collections; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI +{ + public class TreeViewImageKeyConverter : ImageKeyConverter + { + #region Constructors + public TreeViewImageKeyConverter () { } + #endregion Constructors + + #region Public Methods + // XXX - Can't find the difference from the base method + public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, + object value, Type destinationType) + { + return base.ConvertTo (context, culture, value, destinationType); + } + #endregion Public Methods + } +} diff --git a/source/ShiftUI/Internal/VScrollProperties.cs b/source/ShiftUI/Internal/VScrollProperties.cs new file mode 100644 index 0000000..e790787 --- /dev/null +++ b/source/ShiftUI/Internal/VScrollProperties.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Authors: +// Olivier Dufour olivier.duff@free.fr +// + +namespace ShiftUI +{ + public class VScrollProperties : ScrollProperties + { + public VScrollProperties (ScrollableWidget container) : base (container) + { + scroll_bar = container.vscrollbar; + } + } +} diff --git a/source/ShiftUI/Internal/Win32DnD.cs b/source/ShiftUI/Internal/Win32DnD.cs new file mode 100644 index 0000000..24cf2da --- /dev/null +++ b/source/ShiftUI/Internal/Win32DnD.cs @@ -0,0 +1,1081 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// Srikanth Madikeri (csri_1986@yahoo.com) - Win32 Drop files. +// + +// NOT COMPLETE + +using System; +using System.Collections; +using System.Drawing; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Text; + +namespace ShiftUI { + internal class Win32DnD { + #region Local Variables + private const uint DATADIR_GET = 1; + private const uint S_OK = 0x00000000; + private const uint S_FALSE = 0x00000001; + private const uint DRAGDROP_S_DROP = 0x00040100; + private const uint DRAGDROP_S_CANCEL = 0x00040101; + private const uint DRAGDROP_S_USEDEFAULTCURSORS = 0x00040102; + private const uint E_NOTIMPL = unchecked((uint)0x80004001); + private const uint E_NOINTERFACE = unchecked((uint)0x80004002); + private const uint E_FAIL = unchecked((uint)0x80004005); + private const uint OLE_E_ADVISENOTSUPPORTED = unchecked((uint)0x80040003); + private const uint DV_E_FORMATETC = unchecked((uint)0x80040064); + + // To call function pointers + //private static object[] GetDataArgs; + + // IDataObject Delegates + private static QueryInterfaceDelegate DOQueryInterface; + private static AddRefDelegate DOAddRef; + private static ReleaseDelegate DORelease; + private static GetDataDelegate GetData; + private static GetDataHereDelegate GetDataHere; + private static QueryGetDataDelegate QueryGetData; + private static GetCanonicalFormatEtcDelegate GetCanonicalFormatEtc; + private static SetDataDelegate SetData; + private static EnumFormatEtcDelegate EnumFormatEtc; + private static DAdviseDelegate DAdvise; + private static DUnadviseDelegate DUnadvise; + private static EnumDAdviseDelegate EnumDAdvise; + + // IDropSource Delegates + private static QueryInterfaceDelegate DSQueryInterface; + private static AddRefDelegate DSAddRef; + private static ReleaseDelegate DSRelease; + private static QueryContinueDragDelegate QueryContinueDrag; + private static GiveFeedbackDelegate GiveFeedback; + + // IDropTarget Delegates + private static QueryInterfaceDelegate DTQueryInterface; + private static AddRefDelegate DTAddRef; + private static ReleaseDelegate DTRelease; + private static DragEnterDelegate DragEnter; + private static DragOverDelegate DragOver; + private static DragLeaveDelegate DragLeave; + private static DropDelegate Drop; + + private static DragEventArgs DragDropEventArgs; + private static GiveFeedbackEventArgs DragFeedbackEventArgs; + private static QueryContinueDragEventArgs DragContinueEventArgs; + private static ArrayList DragFormats; + private static FORMATETC[] DragFormatArray; + private static ArrayList DragMediums; + #endregion // Local Variables + + #region Delegate Definitions + // IUnknown + internal delegate uint QueryInterfaceDelegate(IntPtr @this, ref Guid riid, IntPtr ppvObject); + internal delegate uint AddRefDelegate(IntPtr @this); + internal delegate uint ReleaseDelegate(IntPtr @this); + + // IDataObject + internal delegate uint GetDataDelegate(IntPtr @this, ref FORMATETC pformatetcIn, IntPtr pmedium); + internal delegate uint GetDataHereDelegate(IntPtr @this, ref FORMATETC pformatetc, ref STGMEDIUM pmedium); + internal delegate uint QueryGetDataDelegate(IntPtr @this, ref FORMATETC pformatetc); + internal delegate uint GetCanonicalFormatEtcDelegate(IntPtr @this, ref FORMATETC pformatetcIn, IntPtr pformatetcOut); + internal delegate uint SetDataDelegate(IntPtr @this, ref FORMATETC pformatetc, ref STGMEDIUM pmedium, bool release); + internal delegate uint EnumFormatEtcDelegate(IntPtr @this, uint direction, IntPtr ppenumFormatEtc); + internal delegate uint DAdviseDelegate(IntPtr @this, ref FORMATETC pformatetc, uint advf, IntPtr pAdvSink, ref uint pdwConnection); + internal delegate uint DUnadviseDelegate(IntPtr @this, uint pdwConnection); + internal delegate uint EnumDAdviseDelegate(IntPtr @this, IntPtr ppenumAdvise); + + // IDropSource + internal delegate uint QueryContinueDragDelegate(IntPtr @this, bool fEscapePressed, uint grfkeyState); + internal delegate uint GiveFeedbackDelegate(IntPtr @this, uint pdwEffect); + + // IDropTarget + internal delegate uint DragEnterDelegate(IntPtr @this, IntPtr pDataObj, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect); + internal delegate uint DragOverDelegate(IntPtr @this, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect); + internal delegate uint DragLeaveDelegate(IntPtr @this); + internal delegate uint DropDelegate(IntPtr @this, IntPtr pDataObj, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect); + #endregion // Delegate Definitions + + [StructLayout(LayoutKind.Sequential)] + internal struct FORMATETC { + [MarshalAs(UnmanagedType.U2)] + internal ClipboardFormats cfFormat; + internal IntPtr ptd; + internal DVASPECT dwAspect; + internal int lindex; + internal TYMED tymed; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct STGMEDIUM { + internal TYMED tymed; + internal IntPtr hHandle; + internal IntPtr pUnkForRelease; + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + internal struct DROPFILES { + internal uint pFiles; + internal uint pt_x; + internal uint pt_y; + internal bool fNC; + internal bool fWide; + internal string pText; + } + + internal enum DVASPECT { + DVASPECT_CONTENT = 1, + DVASPECT_THUMBNAIL = 2, + DVASPECT_ICON = 4, + DVASPECT_DOCPRINT = 8 + } + + internal enum TYMED { + TYMED_HGLOBAL = 1, + TYMED_FILE = 2, + TYMED_ISTREAM = 4, + TYMED_ISTORAGE = 8, + TYMED_GDI = 16, + TYMED_MFPICT = 32, + TYMED_ENHMF = 64, + TYMED_NULL = 0 + } + + private static readonly Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046"); + private static readonly Guid IID_IDataObject = new Guid("0000010e-0000-0000-C000-000000000046"); + private static readonly Guid IID_IDropSource = new Guid("00000121-0000-0000-C000-000000000046"); + private static readonly Guid IID_IDropTarget = new Guid("00000122-0000-0000-C000-000000000046"); + + static Win32DnD() + { + // Required for all other OLE functions to work + Win32OleInitialize(IntPtr.Zero); + + // We reuse those + DragDropEventArgs = new DragEventArgs(new DataObject(DataFormats.FileDrop, new string[0]), 0, 0, 0, DragDropEffects.None, DragDropEffects.None); + DragFeedbackEventArgs = new GiveFeedbackEventArgs(DragDropEffects.None, true); + DragContinueEventArgs = new QueryContinueDragEventArgs(0, false, DragAction.Continue); + DragFormats = new ArrayList(); + DragFormatArray = new FORMATETC[0]; + DragMediums = new ArrayList(); + + // Set up delegates + // IDataObject + DOQueryInterface = new QueryInterfaceDelegate(ComIDataObject.QueryInterface); + DOAddRef = new AddRefDelegate(ComIDataObject.AddRef); + DORelease = new ReleaseDelegate(ComIDataObject.Release); + GetData = new GetDataDelegate(ComIDataObject.GetData); + GetDataHere = new GetDataHereDelegate(ComIDataObject.GetDataHere); + QueryGetData = new QueryGetDataDelegate(ComIDataObject.QueryGetData); + GetCanonicalFormatEtc = new GetCanonicalFormatEtcDelegate(ComIDataObject.GetCanonicalFormatEtc); + SetData = new SetDataDelegate(ComIDataObject.SetData); + EnumFormatEtc = new EnumFormatEtcDelegate(ComIDataObject.EnumFormatEtc); + DAdvise = new DAdviseDelegate(ComIDataObject.DAdvise); + DUnadvise = new DUnadviseDelegate(ComIDataObject.DUnadvise); + EnumDAdvise = new EnumDAdviseDelegate(ComIDataObject.EnumDAdvise); + + // IDropSource + DSQueryInterface = new QueryInterfaceDelegate(ComIDropSource.QueryInterface); + DSAddRef = new AddRefDelegate(ComIDropSource.AddRef); + DSRelease = new ReleaseDelegate(ComIDropSource.Release); + QueryContinueDrag = new QueryContinueDragDelegate(ComIDropSource.QueryContinueDrag); + GiveFeedback = new GiveFeedbackDelegate(ComIDropSource.GiveFeedback); + + // IDropTarget + DTQueryInterface = new QueryInterfaceDelegate(ComIDropTarget.QueryInterface); + DTAddRef = new AddRefDelegate(ComIDropTarget.AddRef); + DTRelease = new ReleaseDelegate(ComIDropTarget.Release); + DragEnter = new DragEnterDelegate(ComIDropTarget.DragEnter); + DragOver = new DragOverDelegate(ComIDropTarget.DragOver); + DragLeave = new DragLeaveDelegate(ComIDropTarget.DragLeave); + Drop = new DropDelegate(ComIDropTarget.Drop); + } + + internal class ComIDataObject { + [StructLayout(LayoutKind.Sequential)] + internal struct DataObjectStruct { + internal IntPtr vtbl; + internal QueryInterfaceDelegate QueryInterface; + internal AddRefDelegate AddRef; + internal ReleaseDelegate Release; + internal GetDataDelegate GetData; + internal GetDataHereDelegate GetDataHere; + internal QueryGetDataDelegate QueryGetData; + internal GetCanonicalFormatEtcDelegate GetCanonicalFormatEtc; + internal SetDataDelegate SetData; + internal EnumFormatEtcDelegate EnumFormatEtc; + internal DAdviseDelegate DAdvise; + internal DUnadviseDelegate DUnadvise; + internal EnumDAdviseDelegate EnumDAdvise; + } + + internal static IntPtr GetUnmanaged() { + DataObjectStruct data_object; + IntPtr data_object_ptr; + long offset; + + data_object = new DataObjectStruct(); + + data_object.QueryInterface = Win32DnD.DOQueryInterface; + data_object.AddRef = Win32DnD.DOAddRef; + data_object.Release = Win32DnD.DORelease; + data_object.GetData = Win32DnD.GetData; + data_object.GetDataHere = Win32DnD.GetDataHere; + data_object.QueryGetData = Win32DnD.QueryGetData; + data_object.GetCanonicalFormatEtc = Win32DnD.GetCanonicalFormatEtc; + data_object.SetData = Win32DnD.SetData; + data_object.EnumFormatEtc = Win32DnD.EnumFormatEtc; + data_object.DAdvise = Win32DnD.DAdvise; + data_object.DUnadvise = Win32DnD.DUnadvise; + data_object.EnumDAdvise = Win32DnD.EnumDAdvise; + + data_object_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(DataObjectStruct))); + Marshal.StructureToPtr(data_object, data_object_ptr, false); + + // Update vtbl pointer + offset = data_object_ptr.ToInt64(); + offset += Marshal.SizeOf(typeof(IntPtr)); + Marshal.WriteIntPtr(data_object_ptr, new IntPtr(offset)); + + return data_object_ptr; + } + + internal static void ReleaseUnmanaged(IntPtr data_object_ptr) { + Marshal.FreeHGlobal(data_object_ptr); + } + + internal static uint QueryInterface(IntPtr @this, ref Guid riid, IntPtr ppvObject) { + try { + if (IID_IUnknown.Equals(riid) || IID_IDataObject.Equals(riid)) { + Marshal.WriteIntPtr(ppvObject, @this); + return S_OK; + } + } + + catch (Exception e) { + Console.WriteLine("Got exception {0}", e.Message); + } + + Marshal.WriteIntPtr(ppvObject, IntPtr.Zero); + return E_NOINTERFACE; + } + + internal static uint AddRef(IntPtr @this) { + // We only use this for DnD, try and fake it + return 1; + } + + internal static uint Release(IntPtr @this) { + // We only use this for DnD, try and fake it + return 0; + } + + internal static STGMEDIUM medium = new STGMEDIUM(); + internal static uint GetData(IntPtr this_, ref FORMATETC pformatetcIn, IntPtr pmedium) { + int index; + + index = FindFormat(pformatetcIn); + if (index != -1) { + medium.tymed = TYMED.TYMED_HGLOBAL; + medium.hHandle = XplatUIWin32.DupGlobalMem(((STGMEDIUM)DragMediums[index]).hHandle); + medium.pUnkForRelease = IntPtr.Zero; + try { + Marshal.StructureToPtr(medium, pmedium, false); + } + catch (Exception e) { + Console.WriteLine("Error: {0}", e.Message); + } + return S_OK; + } + + return DV_E_FORMATETC; + } + + internal static uint GetDataHere(IntPtr @this, ref FORMATETC pformatetc, ref STGMEDIUM pmedium) { + return DV_E_FORMATETC; + } + + internal static uint QueryGetData(IntPtr @this, ref FORMATETC pformatetc) { + if (FindFormat(pformatetc) != -1) { + return S_OK; + } + return DV_E_FORMATETC; + } + + internal static uint GetCanonicalFormatEtc(IntPtr @this, ref FORMATETC pformatetcIn, IntPtr pformatetcOut) { + Marshal.WriteIntPtr(pformatetcOut, Marshal.SizeOf(typeof(IntPtr)), IntPtr.Zero); + return E_NOTIMPL; + } + + internal static uint SetData(IntPtr this_, ref FORMATETC pformatetc, ref STGMEDIUM pmedium, bool release) { + return E_NOTIMPL; + } + + internal static uint EnumFormatEtc(IntPtr this_, uint direction, IntPtr ppenumFormatEtc) { + if (direction == DATADIR_GET) { + IntPtr ppenum_ptr; + + ppenum_ptr = IntPtr.Zero; + DragFormatArray = new FORMATETC[DragFormats.Count]; + + for (int i = 0; i < DragFormats.Count; i++) { + DragFormatArray[i] = (FORMATETC)DragFormats[i]; + } + Win32SHCreateStdEnumFmtEtc((uint)DragFormatArray.Length, DragFormatArray, ref ppenum_ptr); + Marshal.WriteIntPtr(ppenumFormatEtc, ppenum_ptr); + return S_OK; + } + return E_NOTIMPL; + } + + internal static uint DAdvise(IntPtr this_, ref FORMATETC pformatetc, uint advf, IntPtr pAdvSink, ref uint pdwConnection) { + return OLE_E_ADVISENOTSUPPORTED; + } + + internal static uint DUnadvise(IntPtr this_, uint pdwConnection) { + return OLE_E_ADVISENOTSUPPORTED; + } + + internal static uint EnumDAdvise(IntPtr this_, IntPtr ppenumAdvise) { + return OLE_E_ADVISENOTSUPPORTED; + } + } + + internal class ComIDataObjectUnmanaged { + [StructLayout(LayoutKind.Sequential)] + internal struct IDataObjectUnmanaged { + internal IntPtr QueryInterface; + internal IntPtr AddRef; + internal IntPtr Release; + internal IntPtr GetData; + internal IntPtr GetDataHere; + internal IntPtr QueryGetData; + internal IntPtr GetCanonicalFormatEtc; + internal IntPtr SetData; + internal IntPtr EnumFormatEtc; + internal IntPtr DAdvise; + internal IntPtr DUnadvise; + internal IntPtr EnumDAdvise; + } + + private static bool Initialized; + private static MethodInfo GetDataMethod; + //private static MethodInfo GetDataHereMethod; + private static MethodInfo QueryGetDataMethod; + //private static MethodInfo GetCanonicalFormatEtcMethod; + //private static MethodInfo SetDataMethod; + //private static MethodInfo EnumFormatEtcMethod; + //private static MethodInfo DAdviseMethod; + //private static MethodInfo DUnadviseMethod; + //private static MethodInfo EnumDAdviseMethod; + private static object[] MethodArguments; + + private IDataObjectUnmanaged vtbl; + private IntPtr @this; + + internal ComIDataObjectUnmanaged(IntPtr data_object_ptr) { + if (!Initialized) { + Initialize(); + } + + vtbl = new IDataObjectUnmanaged(); + @this = data_object_ptr; + try { + vtbl = (IDataObjectUnmanaged)Marshal.PtrToStructure(Marshal.ReadIntPtr(data_object_ptr), typeof(IDataObjectUnmanaged)); + } + + catch (Exception e) { + Console.WriteLine("Exception {0}", e.Message); + } + } + + private static void Initialize() { + AssemblyName assembly; + AssemblyBuilder assembly_builder; + + if (Initialized) { + return; + } + + assembly = new AssemblyName(); + assembly.Name = "XplatUIWin32.FuncPtrInterface"; + assembly_builder = AppDomain.CurrentDomain.DefineDynamicAssembly(assembly, AssemblyBuilderAccess.Run); + + MethodArguments = new object[6]; + GetDataMethod = CreateFuncPtrInterface(assembly_builder, "GetData", typeof(uint), 3); + //GetDataHereMethod = CreateFuncPtrInterface(assembly_builder, "GetDataHere", typeof(uint), 3); + QueryGetDataMethod = CreateFuncPtrInterface(assembly_builder, "QueryGetData", typeof(uint), 2); + //GetCanonicalFormatEtcMethod = CreateFuncPtrInterface(assembly_builder, "GetCanonicalFormatEtc", typeof(uint), 3); + //SetDataMethod = CreateFuncPtrInterface(assembly_builder, "SetData", typeof(uint), 4); + //EnumFormatEtcMethod = CreateFuncPtrInterface(assembly_builder, "EnumFormatEtc", typeof(uint), 3); + //DAdviseMethod = CreateFuncPtrInterface(assembly_builder, "DAdvise", typeof(uint), 5); + //DUnadviseMethod = CreateFuncPtrInterface(assembly_builder, "DUnadvise", typeof(uint), 2); + //EnumDAdviseMethod = CreateFuncPtrInterface(assembly_builder, "EnumDAdvise", typeof(uint), 2); + + Initialized = true; + } + + internal uint QueryInterface(Guid riid, IntPtr ppvObject) { + uint ret; + IntPtr riid_ptr; + + riid_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid))); + Marshal.StructureToPtr(riid, riid_ptr, false); + + MethodArguments[0] = vtbl.QueryInterface; + MethodArguments[1] = this.@this; + MethodArguments[2] = riid_ptr; + MethodArguments[3] = ppvObject; + + try { + ret = (uint)GetDataMethod.Invoke(null, MethodArguments); + } + + catch (Exception e) { + Console.WriteLine("Caught exception {0}", e.Message); + ret = E_FAIL; + } + + Marshal.FreeHGlobal(riid_ptr); + + return ret; + } + + internal uint AddRef() { + // We only use this for DnD, try and fake it + return 1; + } + + internal uint Release() { + // We only use this for DnD, try and fake it + return 0; + } + + internal uint GetData(FORMATETC pformatetcIn, ref STGMEDIUM pmedium) { + uint ret; + IntPtr pformatetcIn_ptr; + IntPtr pmedium_ptr; + + pformatetcIn_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FORMATETC))); + Marshal.StructureToPtr(pformatetcIn, pformatetcIn_ptr, false); + + pmedium_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(STGMEDIUM))); + + MethodArguments[0] = vtbl.GetData; + MethodArguments[1] = this.@this; + MethodArguments[2] = pformatetcIn_ptr; + MethodArguments[3] = pmedium_ptr; + + try { + ret = (uint)GetDataMethod.Invoke(null, MethodArguments); + Marshal.PtrToStructure(pmedium_ptr, pmedium); + } + + catch (Exception e) { + Console.WriteLine("Caught exception {0}", e.Message); + ret = E_FAIL; + } + + Marshal.FreeHGlobal(pformatetcIn_ptr); + Marshal.FreeHGlobal(pmedium_ptr); + + return ret; + } + + internal uint GetDataHere(FORMATETC pformatetc, ref STGMEDIUM pmedium) { + return E_NOTIMPL; + } + + internal uint QueryGetData(FORMATETC pformatetc) { + uint ret; + IntPtr pformatetc_ptr; + + pformatetc_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FORMATETC))); + Marshal.StructureToPtr(pformatetc, pformatetc_ptr, false); + + MethodArguments[0] = vtbl.GetData; + MethodArguments[1] = this.@this; + MethodArguments[2] = pformatetc_ptr; + + try { + ret = (uint)QueryGetDataMethod.Invoke(null, MethodArguments); + } + + catch (Exception e) { + Console.WriteLine("Caught exception {0}", e.Message); + ret = E_FAIL; + } + + Marshal.FreeHGlobal(pformatetc_ptr); + + return ret; + } + + internal uint GetCanonicalFormatEtc(FORMATETC pformatetcIn, ref FORMATETC pformatetcOut) { + return E_NOTIMPL; + } + + internal uint SetData(FORMATETC pformatetc, STGMEDIUM pmedium, bool release) { + return E_NOTIMPL; + } + + internal uint EnumFormatEtc(uint direction, IntPtr ppenumFormatEtc) { + return E_NOTIMPL; + } + + internal uint DAdvise(FORMATETC pformatetc, uint advf, IntPtr pAdvSink, ref uint pdwConnection) { + return OLE_E_ADVISENOTSUPPORTED; + } + + internal uint DUnadvise(uint pdwConnection) { + return OLE_E_ADVISENOTSUPPORTED; + } + + internal uint EnumDAdvise(IntPtr ppenumAdvise) { + return OLE_E_ADVISENOTSUPPORTED; + } + } + + + internal class ComIDropSource { + [StructLayout(LayoutKind.Sequential)] + internal struct IDropSource { + internal IntPtr vtbl; + internal IntPtr Window; + internal QueryInterfaceDelegate QueryInterface; + internal AddRefDelegate AddRef; + internal ReleaseDelegate Release; + internal QueryContinueDragDelegate QueryContinueDrag; + internal GiveFeedbackDelegate GiveFeedback; + } + + internal static IntPtr GetUnmanaged(IntPtr Window) { + IDropSource drop_source; + IntPtr drop_source_ptr; + long offset; + + drop_source = new IDropSource(); + drop_source.QueryInterface = Win32DnD.DSQueryInterface; + drop_source.AddRef = Win32DnD.DSAddRef; + drop_source.Release = Win32DnD.DSRelease; + drop_source.QueryContinueDrag = Win32DnD.QueryContinueDrag; + drop_source.GiveFeedback = Win32DnD.GiveFeedback; + drop_source.Window = Window; + + drop_source_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(drop_source)); + Marshal.StructureToPtr(drop_source, drop_source_ptr, false); + + // Update vtbl pointer + offset = drop_source_ptr.ToInt64(); + offset += 2 * Marshal.SizeOf(typeof(IntPtr)); + Marshal.WriteIntPtr(drop_source_ptr, new IntPtr(offset)); + + return drop_source_ptr; + } + + internal static void ReleaseUnmanaged(IntPtr drop_source_ptr) { + Marshal.FreeHGlobal(drop_source_ptr); + } + + internal static uint QueryInterface(IntPtr @this, ref Guid riid, IntPtr ppvObject) { + try { + if (IID_IUnknown.Equals(riid) || IID_IDropSource.Equals(riid)) { + Marshal.WriteIntPtr(ppvObject, @this); + return S_OK; + } + } + + catch (Exception e) { + Console.WriteLine("Got exception {0}", e.Message); + } + + Marshal.WriteIntPtr(ppvObject, IntPtr.Zero); + return E_NOINTERFACE; + } + + internal static uint AddRef(IntPtr @this) { + // We only use this for DnD, try and fake it + return 1; + } + + internal static uint Release(IntPtr @this) { + // We only use this for DnD, try and fake it + return 0; + } + + internal static uint QueryContinueDrag(IntPtr @this, bool fEscapePressed, uint grfkeyState) { + IntPtr window; + + window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr))); + + // LAMESPEC? - according to MSDN, when the any mousebutton is *pressed* it defaults to Drop. + // According to COM customary behaviour it's the other way round; which is what we do here + if (fEscapePressed) { + DragContinueEventArgs.drag_action = DragAction.Cancel; + } else if ((grfkeyState & (1+2+16)) == 0) { // Left, middle and right mouse button not pressed + DragContinueEventArgs.drag_action = DragAction.Drop; + } else { + DragContinueEventArgs.drag_action = DragAction.Continue; + } + + DragContinueEventArgs.escape_pressed = fEscapePressed; + DragContinueEventArgs.key_state = (int)grfkeyState; + + Widget.FromHandle(window).DndContinueDrag(DragContinueEventArgs); + + if (DragContinueEventArgs.drag_action == DragAction.Cancel) { + return DRAGDROP_S_CANCEL; + } else if (DragContinueEventArgs.drag_action == DragAction.Drop) { + return DRAGDROP_S_DROP; + } + return S_OK; + } + + internal static uint GiveFeedback(IntPtr @this, uint pdwEffect) { + IntPtr window; + + window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr))); + + DragFeedbackEventArgs.effect = (DragDropEffects)pdwEffect; + DragFeedbackEventArgs.use_default_cursors = true; + + Widget.FromHandle(window).DndFeedback(DragFeedbackEventArgs); + + if (DragFeedbackEventArgs.use_default_cursors) { + return DRAGDROP_S_USEDEFAULTCURSORS; + } + return S_OK; + } + } + + internal class ComIDropTarget { + [StructLayout(LayoutKind.Sequential)] + internal struct IDropTarget { + internal IntPtr vtbl; + internal IntPtr Window; + internal QueryInterfaceDelegate QueryInterface; + internal AddRefDelegate AddRef; + internal ReleaseDelegate Release; + + internal DragEnterDelegate DragEnter; + internal DragOverDelegate DragOver; + internal DragLeaveDelegate DragLeave; + internal DropDelegate Drop; + } + + internal static IntPtr GetUnmanaged(IntPtr Window) { + IDropTarget drop_target; + IntPtr drop_target_ptr; + long offset; + + drop_target = new IDropTarget(); + drop_target.QueryInterface = Win32DnD.DTQueryInterface; + drop_target.AddRef = Win32DnD.DTAddRef; + drop_target.Release = Win32DnD.DTRelease; + drop_target.DragEnter = Win32DnD.DragEnter; + drop_target.DragOver = Win32DnD.DragOver; + drop_target.DragLeave = Win32DnD.DragLeave; + drop_target.Drop = Win32DnD.Drop; + drop_target.Window = Window; + + drop_target_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(drop_target)); + Marshal.StructureToPtr(drop_target, drop_target_ptr, false); + + // Update vtbl pointer + offset = drop_target_ptr.ToInt64(); + offset += 2 * Marshal.SizeOf(typeof(IntPtr)); + Marshal.WriteIntPtr(drop_target_ptr, new IntPtr(offset)); + + return drop_target_ptr; + } + + internal static void ReleaseUnmanaged(IntPtr drop_target_ptr) { + Marshal.FreeHGlobal(drop_target_ptr); + } + + internal static uint QueryInterface(IntPtr @this, ref Guid riid, IntPtr ppvObject) { + try { + if (IID_IUnknown.Equals(riid) || IID_IDropTarget.Equals(riid)) { + Marshal.WriteIntPtr(ppvObject, @this); + return S_OK; + } + } + + catch (Exception e) { + Console.WriteLine("Got exception {0}", e.Message); + } + + Marshal.WriteIntPtr(ppvObject, IntPtr.Zero); + return E_NOINTERFACE; + } + + internal static uint AddRef(IntPtr @this) { + // We only use this for DnD, try and fake it + return 1; + } + + internal static uint Release(IntPtr @this) { + // We only use this for DnD, try and fake it + return 0; + } + + internal static uint DragEnter(IntPtr @this, IntPtr pDataObj, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect) { + IntPtr window; + + window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr))); + + DragDropEventArgs.x = pt_x.ToInt32(); + DragDropEventArgs.y = pt_y.ToInt32(); + DragDropEventArgs.allowed_effect = (DragDropEffects)Marshal.ReadIntPtr(pdwEffect).ToInt32(); + DragDropEventArgs.current_effect = DragDropEventArgs.AllowedEffect; + DragDropEventArgs.keystate = (int)grfkeyState; + + Widget.FromHandle(window).DndEnter(DragDropEventArgs); + + Marshal.WriteInt32(pdwEffect, (int)DragDropEventArgs.Effect); + + return S_OK; + } + + internal static uint DragOver(IntPtr @this, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect) { + IntPtr window; + + window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr))); + + DragDropEventArgs.x = pt_x.ToInt32(); + DragDropEventArgs.y = pt_y.ToInt32(); + DragDropEventArgs.allowed_effect = (DragDropEffects)Marshal.ReadIntPtr(pdwEffect).ToInt32(); + DragDropEventArgs.current_effect = DragDropEventArgs.AllowedEffect; + DragDropEventArgs.keystate = (int)grfkeyState; + + Widget.FromHandle(window).DndOver(DragDropEventArgs); + + Marshal.WriteInt32(pdwEffect, (int)DragDropEventArgs.Effect); + + return S_OK; + } + + internal static uint DragLeave(IntPtr @this) { + IntPtr window; + + window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr))); + + Widget.FromHandle(window).DndLeave(EventArgs.Empty); + + return S_OK; + } + + internal static uint Drop(IntPtr @this, IntPtr pDataObj, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect) + { + IntPtr window; + + window = Marshal.ReadIntPtr (@this, Marshal.SizeOf (typeof (IntPtr))); + + DragDropEventArgs.x = pt_x.ToInt32 (); + DragDropEventArgs.y = pt_y.ToInt32 (); + DragDropEventArgs.allowed_effect = (DragDropEffects) Marshal.ReadIntPtr (pdwEffect).ToInt32(); + DragDropEventArgs.current_effect = DragDropEventArgs.AllowedEffect; + DragDropEventArgs.keystate = (int) grfkeyState; + + Widget control = Widget.FromHandle (window); + if (control != null) { + control.DndDrop (DragDropEventArgs); + return S_FALSE; + } + + Marshal.WriteInt32 (pdwEffect, (int) DragDropEventArgs.Effect); + + return S_OK; + } + } + + internal static bool HandleWMDropFiles(ref MSG msg) { + IntPtr hDrop; + int count; + StringBuilder sb; + string[] dropfiles; + + hDrop = msg.wParam; + count = Win32DragQueryFile(hDrop, -1, IntPtr.Zero, 0); + + dropfiles = new string[count]; + + sb = new StringBuilder(256); + for (int i = 0; i < count; i++) { + Win32DragQueryFile(hDrop, i, sb, sb.Capacity); + dropfiles[i] = sb.ToString(); + } + + DragDropEventArgs.Data.SetData(DataFormats.FileDrop, dropfiles); + + Widget.FromHandle(msg.hwnd).DndDrop(DragDropEventArgs); + + return true; + } + + private static bool AddFormatAndMedium(ClipboardFormats cfFormat, object data) { + STGMEDIUM medium; + FORMATETC format; + IntPtr hmem; + IntPtr hmem_ptr; + byte[] b; + + switch(cfFormat) { + case ClipboardFormats.CF_TEXT: { + b = XplatUIWin32.StringToAnsi ((string)data); + hmem = XplatUIWin32.CopyToMoveableMemory (b); + break; + } + + case ClipboardFormats.CF_UNICODETEXT: { + b = XplatUIWin32.StringToUnicode ((string)data); + hmem = XplatUIWin32.CopyToMoveableMemory (b); + break; + } + + case ClipboardFormats.CF_HDROP: { + IEnumerator e; + StringBuilder sb; + long hmem_string_ptr; + IntPtr string_buffer; + int string_buffer_size; + + sb = new StringBuilder(); + + // Make sure object is enumerable; otherwise + if ((data is string) || !(data is IEnumerable)) { + sb.Append(data.ToString()); + sb.Append('\0'); + sb.Append('\0'); + } else { + e = ((IEnumerable)data).GetEnumerator(); + while (e.MoveNext()) { + sb.Append(e.Current.ToString()); + sb.Append('\0'); + } + sb.Append('\0'); + } + + string_buffer = Marshal.StringToHGlobalUni(sb.ToString()); + string_buffer_size = (int)XplatUIWin32.Win32GlobalSize(string_buffer); + + // Write DROPFILES structure + hmem = XplatUIWin32.Win32GlobalAlloc(XplatUIWin32.GAllocFlags.GMEM_MOVEABLE | XplatUIWin32.GAllocFlags.GMEM_DDESHARE, 0x14 + string_buffer_size); + hmem_ptr = XplatUIWin32.Win32GlobalLock(hmem); + Marshal.WriteInt32(hmem_ptr, 0x14); // pFiles + Marshal.WriteInt32(hmem_ptr, 1 * Marshal.SizeOf(typeof(uint)), 0); // point.x + Marshal.WriteInt32(hmem_ptr, 2 * Marshal.SizeOf(typeof(uint)), 0); // point.y + Marshal.WriteInt32(hmem_ptr, 3 * Marshal.SizeOf(typeof(uint)), 0); // fNc + Marshal.WriteInt32(hmem_ptr, 4 * Marshal.SizeOf(typeof(uint)), 1); // fWide + + hmem_string_ptr = (long)hmem_ptr; + hmem_string_ptr += 0x14; + + XplatUIWin32.Win32CopyMemory(new IntPtr(hmem_string_ptr), string_buffer, string_buffer_size); + Marshal.FreeHGlobal(string_buffer); + XplatUIWin32.Win32GlobalUnlock(hmem_ptr); + + break; + } + + case ClipboardFormats.CF_DIB: { + b = XplatUIWin32.ImageToDIB((Image)data); + hmem = XplatUIWin32.CopyToMoveableMemory (b); + break; + } + + default: { + hmem = IntPtr.Zero; + break; + } + } + + if (hmem != IntPtr.Zero) { + medium = new STGMEDIUM(); + medium.tymed = TYMED.TYMED_HGLOBAL; + medium.hHandle = hmem; + medium.pUnkForRelease = IntPtr.Zero; + DragMediums.Add(medium); + + format = new FORMATETC(); + format.ptd = IntPtr.Zero; + format.dwAspect = DVASPECT.DVASPECT_CONTENT; + format.lindex = -1; + format.tymed = TYMED.TYMED_HGLOBAL; + format.cfFormat = cfFormat; + DragFormats.Add(format); + + return true; + } + + return false; + } + + private static int FindFormat(FORMATETC pformatetc) { + for (int i = 0; i < DragFormats.Count; i++) { + if ((((FORMATETC)DragFormats[i]).cfFormat == pformatetc.cfFormat) && + (((FORMATETC)DragFormats[i]).dwAspect == pformatetc.dwAspect) && + ((((FORMATETC)DragFormats[i]).tymed & pformatetc.tymed)) != 0) { + return i; + } + } + return -1; + } + + private static void BuildFormats(object data) { + + DragFormats.Clear(); + DragMediums.Clear(); + + // Build our formats based on object data + if (data is String) { + AddFormatAndMedium(ClipboardFormats.CF_TEXT, data); + AddFormatAndMedium(ClipboardFormats.CF_UNICODETEXT, data); + AddFormatAndMedium(ClipboardFormats.CF_HDROP, data); + } else if (data is Bitmap) { + AddFormatAndMedium(ClipboardFormats.CF_DIB, data); + } else if (data is ICollection) { + // FIXME - test with .Net and found how this is handled + AddFormatAndMedium(ClipboardFormats.CF_HDROP, data); + } else if (data is ISerializable) { + // FIXME - test with .Net and found how this is handled + } + } + + internal static DragDropEffects StartDrag(IntPtr Window, object data, DragDropEffects allowed) { + IntPtr result; + IntPtr data_object; + IntPtr drop_source; + + BuildFormats(data); + + data_object = ComIDataObject.GetUnmanaged(); + drop_source = ComIDropSource.GetUnmanaged(Window); + + result = (IntPtr)DragDropEffects.None; + + Win32DoDragDrop(data_object, drop_source, (IntPtr)allowed, ref result); + + // Cleanup again + ComIDataObject.ReleaseUnmanaged(data_object); + ComIDropSource.ReleaseUnmanaged(drop_source); + DragFormats.Clear(); + DragFormatArray = null; + DragMediums.Clear(); + + return (DragDropEffects)result.ToInt32(); + } + + internal static bool UnregisterDropTarget(IntPtr Window) { + Win32RevokeDragDrop(Window); + return true; + } + + internal static bool RegisterDropTarget(IntPtr Window) { + Hwnd hwnd; + IntPtr drop_target; + uint result; + + hwnd = Hwnd.ObjectFromWindow(Window); + if (hwnd == null) { + return false; + } + + drop_target = ComIDropTarget.GetUnmanaged(Window); + hwnd.marshal_free_list.Add(drop_target); + result = Win32RegisterDragDrop(Window, drop_target); + + if (result != S_OK) { + return false; + } + return true; + } + + // Thanks, Martin + static MethodInfo CreateFuncPtrInterface(AssemblyBuilder assembly, string MethodName, Type ret_type, int param_count) { + ModuleBuilder mb; + TypeBuilder tb; + Type[] il_param_types; + Type[] param_types; + + mb = assembly.DefineDynamicModule("XplatUIWin32.FuncInterface" + MethodName); + tb = mb.DefineType ("XplatUIWin32.FuncInterface" + MethodName, TypeAttributes.Public); + + param_types = new Type[param_count]; + il_param_types = new Type[param_count + 1]; + + il_param_types[param_count] = typeof(IntPtr); + for (int i = 0; i < param_count; i++) { + param_types[i] = typeof(IntPtr); + il_param_types[i] = typeof(IntPtr); + } + + MethodBuilder method = tb.DefineMethod ( + MethodName, MethodAttributes.Static | MethodAttributes.Public, + ret_type, il_param_types); + + ILGenerator ig = method.GetILGenerator (); + if (param_count > 5) ig.Emit (OpCodes.Ldarg_S, 6); + if (param_count > 4) ig.Emit (OpCodes.Ldarg_S, 5); + if (param_count > 3) ig.Emit (OpCodes.Ldarg_S, 4); + if (param_count > 2) ig.Emit (OpCodes.Ldarg_3); + if (param_count > 1) ig.Emit (OpCodes.Ldarg_2); + if (param_count > 0) ig.Emit (OpCodes.Ldarg_1); + ig.Emit (OpCodes.Ldarg_0); + ig.EmitCalli (OpCodes.Calli, CallingConvention.StdCall, ret_type, param_types); + ig.Emit (OpCodes.Ret); + + Type t = tb.CreateType (); + MethodInfo m = t.GetMethod (MethodName); + + return m; + } + + [DllImport ("ole32.dll", EntryPoint="RegisterDragDrop", CallingConvention=CallingConvention.StdCall)] + private extern static uint Win32RegisterDragDrop(IntPtr Window, IntPtr pDropTarget); + + [DllImport ("ole32.dll", EntryPoint="RevokeDragDrop", CallingConvention=CallingConvention.StdCall)] + private extern static int Win32RevokeDragDrop(IntPtr Window); + + [DllImport ("ole32.dll", EntryPoint="DoDragDrop", CallingConvention=CallingConvention.StdCall)] + private extern static uint Win32DoDragDrop(IntPtr pDataObject, IntPtr pDropSource, IntPtr dwOKEffect, ref IntPtr pdwEffect); + + //[DllImport ("shell32.dll", EntryPoint="DragAcceptFiles", CallingConvention=CallingConvention.StdCall)] + //private extern static int Win32DragAcceptFiles(IntPtr Window, bool fAccept); + + [DllImport ("ole32.dll", EntryPoint="OleInitialize", CallingConvention=CallingConvention.StdCall)] + private extern static int Win32OleInitialize(IntPtr pvReserved); + + [DllImport ("shell32.dll", EntryPoint="DragQueryFileW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + private extern static int Win32DragQueryFile(IntPtr hDrop, int iFile, IntPtr lpszFile, int cch); + + [DllImport ("shell32.dll", EntryPoint="DragQueryFileW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + private extern static int Win32DragQueryFile(IntPtr hDrop, int iFile, StringBuilder lpszFile, int cch); + + [DllImport ("shell32.dll", EntryPoint="SHCreateStdEnumFmtEtc", CallingConvention=CallingConvention.StdCall)] + private extern static uint Win32SHCreateStdEnumFmtEtc(uint cfmt, FORMATETC[] afmt, ref IntPtr ppenumFormatEtc); + } +} diff --git a/source/ShiftUI/Internal/WindowHandler.cs b/source/ShiftUI/Internal/WindowHandler.cs new file mode 100644 index 0000000..cb59ca4 --- /dev/null +++ b/source/ShiftUI/Internal/WindowHandler.cs @@ -0,0 +1,235 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Geoff Norton +// +// + +using System; +using System.Drawing; +using ShiftUI; +using System.Runtime.InteropServices; + +namespace ShiftUI.CarbonInternal { + internal class WindowHandler : EventHandlerBase, IEventHandler { + internal const uint kEventWindowUpdate = 1; + internal const uint kEventWindowDrawContent = 2; + internal const uint kEventWindowActivated = 5; + internal const uint kEventWindowDeactivated = 6; + internal const uint kEventWindowGetClickActivation = 7; + internal const uint kEventWindowShowing = 22; + internal const uint kEventWindowHiding = 23; + internal const uint kEventWindowShown = 24; + internal const uint kEventWindowHidden = 25; + internal const uint kEventWindowCollapsing = 86; + internal const uint kEventWindowExpanding = 87; + internal const uint kEventWindowZoomed = 76; + internal const uint kEventWindowBoundsChanging = 26; + internal const uint kEventWindowBoundsChanged = 27; + internal const uint kEventWindowResizeStarted = 28; + internal const uint kEventWindowResizeCompleted = 29; + internal const uint kEventWindowDragStarted = 30; + internal const uint kEventWindowDragCompleted = 31; + internal const uint kEventWindowTransitionStarted = 88; + internal const uint kEventWindowTransitionCompleted = 89; + internal const uint kEventWindowClickDragRgn = 32; + internal const uint kEventWindowClickResizeRgn = 33; + internal const uint kEventWindowClickCollapseRgn = 34; + internal const uint kEventWindowClickCloseRgn = 35; + internal const uint kEventWindowClickZoomRgn = 36; + internal const uint kEventWindowClickContentRgn = 37; + internal const uint kEventWindowClickProxyIconRgn = 38; + internal const uint kEventWindowClickToolbarButtonRgn = 41; + internal const uint kEventWindowClickStructureRgn = 42; + internal const uint kEventWindowCursorChange = 40; + internal const uint kEventWindowCollapse = 66; + internal const uint kEventWindowCollapsed = 67; + internal const uint kEventWindowCollapseAll = 68; + internal const uint kEventWindowExpand = 69; + internal const uint kEventWindowExpanded = 70; + internal const uint kEventWindowExpandAll = 71; + internal const uint kEventWindowClose = 72; + internal const uint kEventWindowClosed = 73; + internal const uint kEventWindowCloseAll = 74; + internal const uint kEventWindowZoom = 75; + internal const uint kEventWindowZoomAll = 77; + internal const uint kEventWindowContextualMenuSelect = 78; + internal const uint kEventWindowPathSelect = 79; + internal const uint kEventWindowGetIdealSize = 80; + internal const uint kEventWindowGetMinimumSize = 81; + internal const uint kEventWindowGetMaximumSize = 82; + internal const uint kEventWindowConstrain = 83; + internal const uint kEventWindowHandleContentClick = 85; + internal const uint kEventWindowGetDockTileMenu = 90; + internal const uint kEventWindowHandleActivate = 91; + internal const uint kEventWindowHandleDeactivate = 92; + internal const uint kEventWindowProxyBeginDrag = 128; + internal const uint kEventWindowProxyEndDrag = 129; + internal const uint kEventWindowToolbarSwitchMode = 150; + internal const uint kEventWindowFocusAcquired = 200; + internal const uint kEventWindowFocusRelinquish = 201; + internal const uint kEventWindowFocusContent = 202; + internal const uint kEventWindowFocusToolbar = 203; + internal const uint kEventWindowDrawerOpening = 220; + internal const uint kEventWindowDrawerOpened = 221; + internal const uint kEventWindowDrawerClosing = 222; + internal const uint kEventWindowDrawerClosed = 223; + internal const uint kEventWindowDrawFrame = 1000; + internal const uint kEventWindowDrawPart = 1001; + internal const uint kEventWindowGetRegion = 1002; + internal const uint kEventWindowHitTest = 1003; + internal const uint kEventWindowInit = 1004; + internal const uint kEventWindowDispose = 1005; + internal const uint kEventWindowDragHilite = 1006; + internal const uint kEventWindowModified = 1007; + internal const uint kEventWindowSetupProxyDragImage = 1008; + internal const uint kEventWindowStateChanged = 1009; + internal const uint kEventWindowMeasureTitle = 1010; + internal const uint kEventWindowDrawGrowBox = 1011; + internal const uint kEventWindowGetGrowImageRegion = 1012; + internal const uint kEventWindowPaint = 1013; + + internal WindowHandler (XplatUICarbon driver) : base (driver) {} + + public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) { + IntPtr window = Driver.HandleToWindow (handle); + Hwnd hwnd = Hwnd.ObjectFromHandle (window); + if (window != IntPtr.Zero) { + switch (kind) { + case kEventWindowActivated: { + Widget c = Widget.FromHandle (hwnd.client_window); + if (c != null) { + Form form = c.FindForm (); + if (form != null && !form.IsDisposed) { + Driver.SendMessage (form.Handle, Msg.WM_ACTIVATE, (IntPtr) WindowActiveFlags.WA_ACTIVE, IntPtr.Zero); + XplatUICarbon.ActiveWindow = hwnd.client_window; + } + } + + foreach (IntPtr utility_window in XplatUICarbon.UtilityWindows) { + if (utility_window != handle && !XplatUICarbon.IsWindowVisible (utility_window)) + XplatUICarbon.ShowWindow (utility_window); + } + break; + } + case kEventWindowExpanding: + foreach (IntPtr utility_window in XplatUICarbon.UtilityWindows) { + if (utility_window != handle && !XplatUICarbon.IsWindowVisible (utility_window)) + XplatUICarbon.ShowWindow (utility_window); + } + msg.hwnd = hwnd.Handle; + msg.message = Msg.WM_ENTERSIZEMOVE; + return true; + case kEventWindowExpanded: + NativeWindow.WndProc (hwnd.Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + msg.hwnd = hwnd.Handle; + msg.message = Msg.WM_EXITSIZEMOVE; + return true; + case kEventWindowDeactivated: { + Widget c = Widget.FromHandle (hwnd.client_window); + if (c != null) { + Form form = c.FindForm (); + if (form != null && XplatUICarbon.UnactiveWindow != form.Handle) { + Driver.SendMessage (form.Handle, Msg.WM_ACTIVATE, (IntPtr) WindowActiveFlags.WA_INACTIVE, IntPtr.Zero); + XplatUICarbon.ActiveWindow = IntPtr.Zero; + } + } + foreach (IntPtr utility_window in XplatUICarbon.UtilityWindows) { + if (utility_window != handle && XplatUICarbon.IsWindowVisible (utility_window)) + XplatUICarbon.HideWindow (utility_window); + } + break; + } + case kEventWindowCollapsing: + foreach (IntPtr utility_window in XplatUICarbon.UtilityWindows) { + if (utility_window != handle && XplatUICarbon.IsWindowVisible (utility_window)) + XplatUICarbon.HideWindow (utility_window); + } + msg.hwnd = hwnd.Handle; + msg.message = Msg.WM_ENTERSIZEMOVE; + return true; + case kEventWindowCollapsed: + NativeWindow.WndProc (hwnd.Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + msg.hwnd = hwnd.Handle; + msg.message = Msg.WM_EXITSIZEMOVE; + return true; + case kEventWindowClose: + NativeWindow.WndProc (hwnd.Handle, Msg.WM_CLOSE, IntPtr.Zero, IntPtr.Zero); + return false; + case kEventWindowShown: { + msg.message = Msg.WM_SHOWWINDOW; + msg.lParam = (IntPtr) 1; + msg.wParam = (IntPtr) 0; + msg.hwnd = hwnd.Handle; + + return true; + } + case kEventWindowResizeStarted: { + msg.message = Msg.WM_ENTERSIZEMOVE; + msg.hwnd = hwnd.Handle; + return true; + } + case kEventWindowResizeCompleted: { + msg.message = Msg.WM_EXITSIZEMOVE; + msg.hwnd = hwnd.Handle; + + return true; + } + case kEventWindowBoundsChanged: { + Rect window_bounds = new Rect (); + HIRect view_bounds = new HIRect (); + Size size; + + GetWindowBounds (handle, 33, ref window_bounds); + + view_bounds.size.width = window_bounds.right - window_bounds.left; + view_bounds.size.height = window_bounds.bottom - window_bounds.top; + + HIViewSetFrame (hwnd.WholeWindow, ref view_bounds); + + size = XplatUICarbon.TranslateQuartzWindowSizeToWindowSize (Widget.FromHandle (hwnd.Handle).GetCreateParams (), (int)view_bounds.size.width, (int)view_bounds.size.height); + + hwnd.X = (int) window_bounds.left; + hwnd.Y = (int) window_bounds.top; + hwnd.Width = (int) size.Width; + hwnd.Height = (int) size.Height; + + Driver.PerformNCCalc (hwnd); + + msg.hwnd = hwnd.Handle; + msg.message = Msg.WM_WINDOWPOSCHANGED; + Driver.SetCaretPos (XplatUICarbon.Caret.Hwnd, XplatUICarbon.Caret.X, XplatUICarbon.Caret.Y); + + return true; + } + } + } + return false; + } + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int GetWindowBounds (IntPtr handle, uint region, ref Rect bounds); + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int HIViewSetFrame (IntPtr handle, ref HIRect bounds); + } +} diff --git a/source/ShiftUI/Internal/WindowsFormsSynchronizationContext.cs b/source/ShiftUI/Internal/WindowsFormsSynchronizationContext.cs new file mode 100644 index 0000000..ec8ab1c --- /dev/null +++ b/source/ShiftUI/Internal/WindowsFormsSynchronizationContext.cs @@ -0,0 +1,94 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// + +using System; +using System.Threading; +using System.ComponentModel; + + +// Some implementation details: +// http://msdn.microsoft.com/msdnmag/issues/06/06/NETMatters/default.aspx +namespace ShiftUI +{ + public sealed class WindowsFormsSynchronizationContext : SynchronizationContext, IDisposable + { + private static bool auto_installed; + private static Widget invoke_control; + private static SynchronizationContext previous_context; + + #region Public Constructor + public WindowsFormsSynchronizationContext () + { + } + + static WindowsFormsSynchronizationContext () + { + try { + invoke_control = new Widget (); + invoke_control.CreateWidget (); + auto_installed = true; + previous_context = SynchronizationContext.Current; + } + catch (Exception ex) { + Console.WriteLine (ex.Message); + } + } + #endregion + + #region Public Properties + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public static bool AutoInstall { + get { return auto_installed; } + set { auto_installed = value; } + } + #endregion + + #region Public Methods + public override SynchronizationContext CreateCopy () + { + return base.CreateCopy (); + } + + public void Dispose () + { + } + + public override void Post (SendOrPostCallback d, object state) + { + invoke_control.BeginInvoke (d, new object[] { state }); + } + + public override void Send (SendOrPostCallback d, object state) + { + invoke_control.Invoke (d, new object[] { state }); + } + + public static void Uninstall () + { + if (previous_context == null) + previous_context = new SynchronizationContext (); + + SynchronizationContext.SetSynchronizationContext (previous_context); + } + #endregion + } +} diff --git a/source/ShiftUI/Internal/X11Atoms.cs b/source/ShiftUI/Internal/X11Atoms.cs new file mode 100644 index 0000000..ec0232c --- /dev/null +++ b/source/ShiftUI/Internal/X11Atoms.cs @@ -0,0 +1,329 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. (http://www.novell.com) +// +// + +using System; +using ShiftUI; + +namespace ShiftUI.X11Internal { + + internal class X11Atoms { + + // Our atoms + public readonly IntPtr AnyPropertyType = (IntPtr)0; + public readonly IntPtr XA_PRIMARY = (IntPtr)1; + public readonly IntPtr XA_SECONDARY = (IntPtr)2; + public readonly IntPtr XA_ARC = (IntPtr)3; + public readonly IntPtr XA_ATOM = (IntPtr)4; + public readonly IntPtr XA_BITMAP = (IntPtr)5; + public readonly IntPtr XA_CARDINAL = (IntPtr)6; + public readonly IntPtr XA_COLORMAP = (IntPtr)7; + public readonly IntPtr XA_CURSOR = (IntPtr)8; + public readonly IntPtr XA_CUT_BUFFER0 = (IntPtr)9; + public readonly IntPtr XA_CUT_BUFFER1 = (IntPtr)10; + public readonly IntPtr XA_CUT_BUFFER2 = (IntPtr)11; + public readonly IntPtr XA_CUT_BUFFER3 = (IntPtr)12; + public readonly IntPtr XA_CUT_BUFFER4 = (IntPtr)13; + public readonly IntPtr XA_CUT_BUFFER5 = (IntPtr)14; + public readonly IntPtr XA_CUT_BUFFER6 = (IntPtr)15; + public readonly IntPtr XA_CUT_BUFFER7 = (IntPtr)16; + public readonly IntPtr XA_DRAWABLE = (IntPtr)17; + public readonly IntPtr XA_FONT = (IntPtr)18; + public readonly IntPtr XA_INTEGER = (IntPtr)19; + public readonly IntPtr XA_PIXMAP = (IntPtr)20; + public readonly IntPtr XA_POINT = (IntPtr)21; + public readonly IntPtr XA_RECTANGLE = (IntPtr)22; + public readonly IntPtr XA_RESOURCE_MANAGER = (IntPtr)23; + public readonly IntPtr XA_RGB_COLOR_MAP = (IntPtr)24; + public readonly IntPtr XA_RGB_BEST_MAP = (IntPtr)25; + public readonly IntPtr XA_RGB_BLUE_MAP = (IntPtr)26; + public readonly IntPtr XA_RGB_DEFAULT_MAP = (IntPtr)27; + public readonly IntPtr XA_RGB_GRAY_MAP = (IntPtr)28; + public readonly IntPtr XA_RGB_GREEN_MAP = (IntPtr)29; + public readonly IntPtr XA_RGB_RED_MAP = (IntPtr)30; + public readonly IntPtr XA_STRING = (IntPtr)31; + public readonly IntPtr XA_VISUALID = (IntPtr)32; + public readonly IntPtr XA_WINDOW = (IntPtr)33; + public readonly IntPtr XA_WM_COMMAND = (IntPtr)34; + public readonly IntPtr XA_WM_HINTS = (IntPtr)35; + public readonly IntPtr XA_WM_CLIENT_MACHINE = (IntPtr)36; + public readonly IntPtr XA_WM_ICON_NAME = (IntPtr)37; + public readonly IntPtr XA_WM_ICON_SIZE = (IntPtr)38; + public readonly IntPtr XA_WM_NAME = (IntPtr)39; + public readonly IntPtr XA_WM_NORMAL_HINTS = (IntPtr)40; + public readonly IntPtr XA_WM_SIZE_HINTS = (IntPtr)41; + public readonly IntPtr XA_WM_ZOOM_HINTS = (IntPtr)42; + public readonly IntPtr XA_MIN_SPACE = (IntPtr)43; + public readonly IntPtr XA_NORM_SPACE = (IntPtr)44; + public readonly IntPtr XA_MAX_SPACE = (IntPtr)45; + public readonly IntPtr XA_END_SPACE = (IntPtr)46; + public readonly IntPtr XA_SUPERSCRIPT_X = (IntPtr)47; + public readonly IntPtr XA_SUPERSCRIPT_Y = (IntPtr)48; + public readonly IntPtr XA_SUBSCRIPT_X = (IntPtr)49; + public readonly IntPtr XA_SUBSCRIPT_Y = (IntPtr)50; + public readonly IntPtr XA_UNDERLINE_POSITION = (IntPtr)51; + public readonly IntPtr XA_UNDERLINE_THICKNESS = (IntPtr)52; + public readonly IntPtr XA_STRIKEOUT_ASCENT = (IntPtr)53; + public readonly IntPtr XA_STRIKEOUT_DESCENT = (IntPtr)54; + public readonly IntPtr XA_ITALIC_ANGLE = (IntPtr)55; + public readonly IntPtr XA_X_HEIGHT = (IntPtr)56; + public readonly IntPtr XA_QUAD_WIDTH = (IntPtr)57; + public readonly IntPtr XA_WEIGHT = (IntPtr)58; + public readonly IntPtr XA_POINT_SIZE = (IntPtr)59; + public readonly IntPtr XA_RESOLUTION = (IntPtr)60; + public readonly IntPtr XA_COPYRIGHT = (IntPtr)61; + public readonly IntPtr XA_NOTICE = (IntPtr)62; + public readonly IntPtr XA_FONT_NAME = (IntPtr)63; + public readonly IntPtr XA_FAMILY_NAME = (IntPtr)64; + public readonly IntPtr XA_FULL_NAME = (IntPtr)65; + public readonly IntPtr XA_CAP_HEIGHT = (IntPtr)66; + public readonly IntPtr XA_WM_CLASS = (IntPtr)67; + public readonly IntPtr XA_WM_TRANSIENT_FOR = (IntPtr)68; + + public readonly IntPtr WM_PROTOCOLS; + public readonly IntPtr WM_DELETE_WINDOW; + public readonly IntPtr WM_TAKE_FOCUS; + public readonly IntPtr _NET_SUPPORTED; + public readonly IntPtr _NET_CLIENT_LIST; + public readonly IntPtr _NET_NUMBER_OF_DESKTOPS; + public readonly IntPtr _NET_DESKTOP_GEOMETRY; + public readonly IntPtr _NET_DESKTOP_VIEWPORT; + public readonly IntPtr _NET_CURRENT_DESKTOP; + public readonly IntPtr _NET_DESKTOP_NAMES; + public readonly IntPtr _NET_ACTIVE_WINDOW; + public readonly IntPtr _NET_WORKAREA; + public readonly IntPtr _NET_SUPPORTING_WM_CHECK; + public readonly IntPtr _NET_VIRTUAL_ROOTS; + public readonly IntPtr _NET_DESKTOP_LAYOUT; + public readonly IntPtr _NET_SHOWING_DESKTOP; + public readonly IntPtr _NET_CLOSE_WINDOW; + public readonly IntPtr _NET_MOVERESIZE_WINDOW; + public readonly IntPtr _NET_WM_MOVERESIZE; + public readonly IntPtr _NET_RESTACK_WINDOW; + public readonly IntPtr _NET_REQUEST_FRAME_EXTENTS; + public readonly IntPtr _NET_WM_NAME; + public readonly IntPtr _NET_WM_VISIBLE_NAME; + public readonly IntPtr _NET_WM_ICON_NAME; + public readonly IntPtr _NET_WM_VISIBLE_ICON_NAME; + public readonly IntPtr _NET_WM_DESKTOP; + public readonly IntPtr _NET_WM_WINDOW_TYPE; + public readonly IntPtr _NET_WM_STATE; + public readonly IntPtr _NET_WM_ALLOWED_ACTIONS; + public readonly IntPtr _NET_WM_STRUT; + public readonly IntPtr _NET_WM_STRUT_PARTIAL; + public readonly IntPtr _NET_WM_ICON_GEOMETRY; + public readonly IntPtr _NET_WM_ICON; + public readonly IntPtr _NET_WM_PID; + public readonly IntPtr _NET_WM_HANDLED_ICONS; + public readonly IntPtr _NET_WM_USER_TIME; + public readonly IntPtr _NET_FRAME_EXTENTS; + public readonly IntPtr _NET_WM_PING; + public readonly IntPtr _NET_WM_SYNC_REQUEST; + public readonly IntPtr _NET_SYSTEM_TRAY_S; + public readonly IntPtr _NET_SYSTEM_TRAY_ORIENTATION; + public readonly IntPtr _NET_SYSTEM_TRAY_OPCODE; + public readonly IntPtr _NET_WM_STATE_MAXIMIZED_HORZ; + public readonly IntPtr _NET_WM_STATE_MAXIMIZED_VERT; + public readonly IntPtr _XEMBED; + public readonly IntPtr _XEMBED_INFO; + public readonly IntPtr _MOTIF_WM_HINTS; + public readonly IntPtr _NET_WM_STATE_SKIP_TASKBAR; + public readonly IntPtr _NET_WM_STATE_ABOVE; + public readonly IntPtr _NET_WM_STATE_MODAL; + public readonly IntPtr _NET_WM_STATE_HIDDEN; + public readonly IntPtr _NET_WM_CONTEXT_HELP; + public readonly IntPtr _NET_WM_WINDOW_OPACITY; + public readonly IntPtr _NET_WM_WINDOW_TYPE_DESKTOP; + public readonly IntPtr _NET_WM_WINDOW_TYPE_DOCK; + public readonly IntPtr _NET_WM_WINDOW_TYPE_TOOLBAR; + public readonly IntPtr _NET_WM_WINDOW_TYPE_MENU; + public readonly IntPtr _NET_WM_WINDOW_TYPE_UTILITY; + public readonly IntPtr _NET_WM_WINDOW_TYPE_SPLASH; + public readonly IntPtr _NET_WM_WINDOW_TYPE_DIALOG; + public readonly IntPtr _NET_WM_WINDOW_TYPE_NORMAL; + public readonly IntPtr CLIPBOARD; + public readonly IntPtr PRIMARY; + public readonly IntPtr DIB; + public readonly IntPtr OEMTEXT; + public readonly IntPtr UNICODETEXT; + public readonly IntPtr TARGETS; + public readonly IntPtr PostAtom; + public readonly IntPtr AsyncAtom; + + + public X11Atoms (X11Display display) { + + // make sure this array stays in sync with the statements below + string [] atom_names = new string[] { + "WM_PROTOCOLS", + "WM_DELETE_WINDOW", + "WM_TAKE_FOCUS", + "_NET_SUPPORTED", + "_NET_CLIENT_LIST", + "_NET_NUMBER_OF_DESKTOPS", + "_NET_DESKTOP_GEOMETRY", + "_NET_DESKTOP_VIEWPORT", + "_NET_CURRENT_DESKTOP", + "_NET_DESKTOP_NAMES", + "_NET_ACTIVE_WINDOW", + "_NET_WORKAREA", + "_NET_SUPPORTING_WM_CHECK", + "_NET_VIRTUAL_ROOTS", + "_NET_DESKTOP_LAYOUT", + "_NET_SHOWING_DESKTOP", + "_NET_CLOSE_WINDOW", + "_NET_MOVERESIZE_WINDOW", + "_NET_WM_MOVERESIZE", + "_NET_RESTACK_WINDOW", + "_NET_REQUEST_FRAME_EXTENTS", + "_NET_WM_NAME", + "_NET_WM_VISIBLE_NAME", + "_NET_WM_ICON_NAME", + "_NET_WM_VISIBLE_ICON_NAME", + "_NET_WM_DESKTOP", + "_NET_WM_WINDOW_TYPE", + "_NET_WM_STATE", + "_NET_WM_ALLOWED_ACTIONS", + "_NET_WM_STRUT", + "_NET_WM_STRUT_PARTIAL", + "_NET_WM_ICON_GEOMETRY", + "_NET_WM_ICON", + "_NET_WM_PID", + "_NET_WM_HANDLED_ICONS", + "_NET_WM_USER_TIME", + "_NET_FRAME_EXTENTS", + "_NET_WM_PING", + "_NET_WM_SYNC_REQUEST", + "_NET_SYSTEM_TRAY_OPCODE", + "_NET_SYSTEM_TRAY_ORIENTATION", + "_NET_WM_STATE_MAXIMIZED_HORZ", + "_NET_WM_STATE_MAXIMIZED_VERT", + "_NET_WM_STATE_HIDDEN", + "_XEMBED", + "_XEMBED_INFO", + "_MOTIF_WM_HINTS", + "_NET_WM_STATE_SKIP_TASKBAR", + "_NET_WM_STATE_ABOVE", + "_NET_WM_STATE_MODAL", + "_NET_WM_CONTEXT_HELP", + "_NET_WM_WINDOW_OPACITY", + "_NET_WM_WINDOW_TYPE_DESKTOP", + "_NET_WM_WINDOW_TYPE_DOCK", + "_NET_WM_WINDOW_TYPE_TOOLBAR", + "_NET_WM_WINDOW_TYPE_MENU", + "_NET_WM_WINDOW_TYPE_UTILITY", + "_NET_WM_WINDOW_TYPE_DIALOG", + "_NET_WM_WINDOW_TYPE_SPLASH", + "_NET_WM_WINDOW_TYPE_NORMAL", + "CLIPBOARD", + "PRIMARY", + "COMPOUND_TEXT", + "UTF8_STRING", + "TARGETS", + "_SWF_AsyncAtom", + "_SWF_PostMessageAtom", + "_SWF_HoverAtom" }; + + IntPtr[] atoms = new IntPtr [atom_names.Length];; + + Xlib.XInternAtoms (display.Handle, atom_names, atom_names.Length, false, atoms); + + int off = 0; + WM_PROTOCOLS = atoms [off++]; + WM_DELETE_WINDOW = atoms [off++]; + WM_TAKE_FOCUS = atoms [off++]; + _NET_SUPPORTED = atoms [off++]; + _NET_CLIENT_LIST = atoms [off++]; + _NET_NUMBER_OF_DESKTOPS = atoms [off++]; + _NET_DESKTOP_GEOMETRY = atoms [off++]; + _NET_DESKTOP_VIEWPORT = atoms [off++]; + _NET_CURRENT_DESKTOP = atoms [off++]; + _NET_DESKTOP_NAMES = atoms [off++]; + _NET_ACTIVE_WINDOW = atoms [off++]; + _NET_WORKAREA = atoms [off++]; + _NET_SUPPORTING_WM_CHECK = atoms [off++]; + _NET_VIRTUAL_ROOTS = atoms [off++]; + _NET_DESKTOP_LAYOUT = atoms [off++]; + _NET_SHOWING_DESKTOP = atoms [off++]; + _NET_CLOSE_WINDOW = atoms [off++]; + _NET_MOVERESIZE_WINDOW = atoms [off++]; + _NET_WM_MOVERESIZE = atoms [off++]; + _NET_RESTACK_WINDOW = atoms [off++]; + _NET_REQUEST_FRAME_EXTENTS = atoms [off++]; + _NET_WM_NAME = atoms [off++]; + _NET_WM_VISIBLE_NAME = atoms [off++]; + _NET_WM_ICON_NAME = atoms [off++]; + _NET_WM_VISIBLE_ICON_NAME = atoms [off++]; + _NET_WM_DESKTOP = atoms [off++]; + _NET_WM_WINDOW_TYPE = atoms [off++]; + _NET_WM_STATE = atoms [off++]; + _NET_WM_ALLOWED_ACTIONS = atoms [off++]; + _NET_WM_STRUT = atoms [off++]; + _NET_WM_STRUT_PARTIAL = atoms [off++]; + _NET_WM_ICON_GEOMETRY = atoms [off++]; + _NET_WM_ICON = atoms [off++]; + _NET_WM_PID = atoms [off++]; + _NET_WM_HANDLED_ICONS = atoms [off++]; + _NET_WM_USER_TIME = atoms [off++]; + _NET_FRAME_EXTENTS = atoms [off++]; + _NET_WM_PING = atoms [off++]; + _NET_WM_SYNC_REQUEST = atoms [off++]; + _NET_SYSTEM_TRAY_OPCODE = atoms [off++]; + _NET_SYSTEM_TRAY_ORIENTATION = atoms [off++]; + _NET_WM_STATE_MAXIMIZED_HORZ = atoms [off++]; + _NET_WM_STATE_MAXIMIZED_VERT = atoms [off++]; + _NET_WM_STATE_HIDDEN = atoms [off++]; + _XEMBED = atoms [off++]; + _XEMBED_INFO = atoms [off++]; + _MOTIF_WM_HINTS = atoms [off++]; + _NET_WM_STATE_SKIP_TASKBAR = atoms [off++]; + _NET_WM_STATE_ABOVE = atoms [off++]; + _NET_WM_STATE_MODAL = atoms [off++]; + _NET_WM_CONTEXT_HELP = atoms [off++]; + _NET_WM_WINDOW_OPACITY = atoms [off++]; + _NET_WM_WINDOW_TYPE_DESKTOP = atoms [off++]; + _NET_WM_WINDOW_TYPE_DOCK = atoms [off++]; + _NET_WM_WINDOW_TYPE_TOOLBAR = atoms [off++]; + _NET_WM_WINDOW_TYPE_MENU = atoms [off++]; + _NET_WM_WINDOW_TYPE_UTILITY = atoms [off++]; + _NET_WM_WINDOW_TYPE_DIALOG = atoms [off++]; + _NET_WM_WINDOW_TYPE_SPLASH = atoms [off++]; + _NET_WM_WINDOW_TYPE_NORMAL = atoms [off++]; + CLIPBOARD = atoms [off++]; + PRIMARY = atoms [off++]; + OEMTEXT = atoms [off++]; + UNICODETEXT = atoms [off++]; + TARGETS = atoms [off++]; + AsyncAtom = atoms [off++]; + PostAtom = atoms [off++]; + display.HoverState.Atom = atoms [off++]; + + DIB = XA_PIXMAP; + + // XXX multi screen stuff here + _NET_SYSTEM_TRAY_S = Xlib.XInternAtom (display.Handle, "_NET_SYSTEM_TRAY_S" + display.DefaultScreen.ToString(), false); + } + + } + +} + diff --git a/source/ShiftUI/Internal/X11Clipboard.cs b/source/ShiftUI/Internal/X11Clipboard.cs new file mode 100644 index 0000000..b951cc3 --- /dev/null +++ b/source/ShiftUI/Internal/X11Clipboard.cs @@ -0,0 +1,105 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2009 Novell, Inc. +// +// Authors: +// Carlos Alberto Cortez (calberto.cortez@gmail.com) +// + +using System; +using System.Drawing; +using System.Collections; +using System.Collections.Specialized; + +namespace ShiftUI { + + internal class ClipboardData { + ListDictionary source_data; // Source in its different formats, if any + string plain_text_source; // Cached source as plain-text string + Image image_source; // Cached source as image + + internal object Item; // Object on the clipboard + internal ArrayList Formats; // list of formats available in the clipboard + internal bool Retrieving; // true if we are requesting an item + internal bool Enumerating; // true if we are enumerating through all known types + internal XplatUI.ObjectToClipboard Converter; + + public ClipboardData () + { + source_data = new ListDictionary (); + } + + public void ClearSources () + { + source_data.Clear (); + plain_text_source = null; + image_source = null; + } + + public void AddSource (int type, object source) + { + // Try to detect plain text, based on the old behaviour of XplatUIX11, which usually assigns + // -1 as the type when a string is stored in the Clipboard + if (source is string && (type == DataFormats.GetFormat (DataFormats.Text).Id || type == -1)) + plain_text_source = source as string; + else if (source is Image) + image_source = source as Image; + + source_data [type] = source; + } + + public object GetSource (int type) + { + return source_data [type]; + } + + public string GetPlainText () + { + return plain_text_source; + } + + public string GetRtfText () + { + DataFormats.Format format = DataFormats.GetFormat (DataFormats.Rtf); + if (format == null) + return null; // FIXME - is RTF not supported on any system? + + return (string)GetSource (format.Id); + } + + public Image GetImage () + { + return image_source; + } + + public bool IsSourceText { + get { + return plain_text_source != null; + } + } + + public bool IsSourceImage { + get { + return image_source != null; + } + } + } +} + diff --git a/source/ShiftUI/Internal/X11DesktopColors.cs b/source/ShiftUI/Internal/X11DesktopColors.cs new file mode 100644 index 0000000..d3cdd26 --- /dev/null +++ b/source/ShiftUI/Internal/X11DesktopColors.cs @@ -0,0 +1,298 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Dennis Bartok (pbartok@novell.com) +// Alexander Olk (alex.olk@googlemail.com) +// +// + +using System.Drawing; +using System.Runtime.InteropServices; +using System.IO; +using System; + +namespace ShiftUI { + internal class X11DesktopColors { + #region Structs & Enums + [StructLayout(LayoutKind.Sequential)] + internal struct GdkColorStruct { + internal int pixel; + internal short red; + internal short green; + internal short blue; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct GObjectStruct { + public IntPtr Instance; + public IntPtr ref_count; + public IntPtr data; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct GtkStyleStruct { + internal GObjectStruct obj; + [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)] + internal GdkColorStruct[] fg; + [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)] + internal GdkColorStruct[] bg; + [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)] + internal GdkColorStruct[] light; + [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)] + internal GdkColorStruct[] dark; + [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)] + internal GdkColorStruct[] mid; + [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)] + internal GdkColorStruct[] text; + [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)] + internal GdkColorStruct[] baseclr; + [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=5)] + internal GdkColorStruct[] text_aa; /* Halfway between text/base */ + + internal GdkColorStruct black; + internal GdkColorStruct white; + + /* TODO: There is more stuff that we will add when we need it*/ + } + + private enum Desktop { + Gtk, + KDE, + Unknown + } + #endregion // Structs & Enums + + #region Local Variables + static private Desktop desktop; + #endregion // Local Variables + + #region Constructors + static X11DesktopColors() { + FindDesktopEnvironment(); + + switch(desktop) { + case Desktop.Gtk: { + //IntPtr dispmgr; + //IntPtr gdkdisplay; + IntPtr widget; + IntPtr style_ptr; + GtkStyleStruct style; + + try { + GtkInit(); + //dispmgr = gdk_display_manager_get (); + //gdkdisplay = gdk_display_manager_get_default_display (dispmgr); + + widget = gtk_invisible_new (); + gtk_widget_ensure_style (widget); + style_ptr = gtk_widget_get_style (widget); + + style = (GtkStyleStruct) Marshal.PtrToStructure (style_ptr, typeof (GtkStyleStruct)); + + ThemeEngine.Current.ColorControl = ColorFromGdkColor (style.bg[0]); + ThemeEngine.Current.ColorControlText = ColorFromGdkColor (style.fg[0]); + ThemeEngine.Current.ColorControlDark = ColorFromGdkColor (style.dark[0]); + ThemeEngine.Current.ColorControlLight = ColorFromGdkColor (style.light[0]); + ThemeEngine.Current.ColorControlLightLight = WidgetPaint.Light (ThemeEngine.Current.ColorControlLight); + ThemeEngine.Current.ColorControlDarkDark = WidgetPaint.Dark (ThemeEngine.Current.ColorControlDark); + + // We don't want WidgetLight to disappear on a white background! + if (ThemeEngine.Current.ColorControlLight.ToArgb () == Color.White.ToArgb ()) { + ThemeEngine.Current.ColorControlLight = Color.FromArgb (255, 227, 227, 227); + } + widget = gtk_menu_new (); + gtk_widget_ensure_style (widget); + style_ptr = gtk_widget_get_style (widget); + + style = (GtkStyleStruct) Marshal.PtrToStructure (style_ptr, typeof (GtkStyleStruct)); + + ThemeEngine.Current.ColorMenu = ColorFromGdkColor (style.bg [0]); + ThemeEngine.Current.ColorMenuText = ColorFromGdkColor (style.text [0]); + } + + catch (DllNotFoundException) { + Console.Error.WriteLine("Gtk not found (missing LD_LIBRARY_PATH to libgtk-x11-2.0.so.0?), using built-in colorscheme"); + } + + catch { + Console.Error.WriteLine("Gtk colorscheme read failure, using built-in colorscheme"); + } + break; + } + + case Desktop.KDE: { + if (! ReadKDEColorsheme() ) + Console.Error.WriteLine("KDE colorscheme read failure, using built-in colorscheme"); + break; + } + + default: { + break; + } + } + } + + static void GtkInit () + { + gtk_init_check (IntPtr.Zero, IntPtr.Zero); + } + #endregion // Constructors + + #region Properties + static void FindDesktopEnvironment() { + desktop = Desktop.Gtk; + string session = Environment.GetEnvironmentVariable("DESKTOP_SESSION"); + + if ( session != null ) { + session = session.ToUpper( ); + + if ( session == "DEFAULT" ) { + string helper = Environment.GetEnvironmentVariable("KDE_FULL_SESSION"); + + if ( helper != null ) + desktop = Desktop.KDE; + } else + if ( session.StartsWith("KDE") ) + desktop = Desktop.KDE; + } + } + #endregion // Properties + + #region Methods + static internal void Initialize() { + // Do nothing; all is done in our static ctor + } + + private static Color ColorFromGdkColor (GdkColorStruct gtkcolor) { + return Color.FromArgb (255, + (gtkcolor.red >> 8) & 0xff, + (gtkcolor.green >> 8) & 0xff, + (gtkcolor.blue >> 8) & 0xff ); + } + + private static bool ReadKDEColorsheme() { + string full_kdegloabals_filename = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + + "/" + + ".kde/share/config/kdeglobals"; + + if (!File.Exists(full_kdegloabals_filename)) + return false; + + StreamReader sr = new StreamReader(full_kdegloabals_filename); + + string line = sr.ReadLine(); + + Color tmp_color; + + while (line != null) { + line = line.Trim(); + + if (line.StartsWith( "background=")) { + tmp_color = GetColorFromKDEString(line); + + if (tmp_color != Color.Empty) { + ThemeEngine.Current.ColorControl = tmp_color; + ThemeEngine.Current.ColorMenu = tmp_color; + } + } else + if (line.StartsWith( "foreground=")) { + tmp_color = GetColorFromKDEString(line); + + if (tmp_color != Color.Empty) { + ThemeEngine.Current.ColorControlText = tmp_color; + ThemeEngine.Current.ColorMenuText = tmp_color; + } + } else + if (line.StartsWith("selectBackground")) { + tmp_color = GetColorFromKDEString(line); + + if (tmp_color != Color.Empty) { + ThemeEngine.Current.ColorHighlight = tmp_color; + } + } else + if (line.StartsWith("selectForeground")) { + tmp_color = GetColorFromKDEString(line); + + if (tmp_color != Color.Empty) { + ThemeEngine.Current.ColorHighlightText = tmp_color; + } + } + + line = sr.ReadLine(); + } + + sr.Close(); + + return true; + } + + private static Color GetColorFromKDEString(string line) { + string[] split = line.Split(new char[] {'='}); + + if (split.Length > 0) { + line = split[1]; + + split = line.Split(new char[] {','}); + + if (split.Length == 3) { + int r = System.Convert.ToInt32(split[0]); + int g = System.Convert.ToInt32(split[1]); + int b = System.Convert.ToInt32(split[2]); + + return Color.FromArgb(r, g, b); + } + } + + return Color.Empty; + } + #endregion // Methods + + #region DllImports + const string libgdk = "libgdk-x11-2.0.so.0"; + const string libgtk = "libgtk-x11-2.0.so.0"; + + [DllImport(libgtk)] + static extern bool gtk_init_check (IntPtr argc, IntPtr argv); + + [DllImport(libgdk)] + internal static extern IntPtr gdk_display_manager_get (); + + [DllImport(libgdk)] + internal static extern IntPtr gdk_display_manager_get_default_display (IntPtr display_manager); + + [DllImport(libgtk)] + static extern IntPtr gtk_invisible_new (); + + [DllImport(libgtk)] + static extern IntPtr gtk_menu_new (); + + //[DllImport(libgtk)] + //static extern IntPtr gtk_menu_item_new_with_label (string label); + + [DllImport(libgtk)] + static extern void gtk_widget_ensure_style (IntPtr raw); + + [DllImport(libgtk)] + static extern IntPtr gtk_widget_get_style (IntPtr raw); + #endregion // DllImports + } +} diff --git a/source/ShiftUI/Internal/X11Display.cs b/source/ShiftUI/Internal/X11Display.cs new file mode 100644 index 0000000..221e5f1 --- /dev/null +++ b/source/ShiftUI/Internal/X11Display.cs @@ -0,0 +1,2693 @@ +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. (http://www.novell.com) +// +// +using System; +using System.Collections; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using ShiftUI; +// Only do the poll when building with mono for now +#if __MonoCS__ +//using Mono.Unix.Native; +#endif + +namespace ShiftUI.X11Internal { + + internal class X11Display { + + IntPtr display; /* our X handle */ + + // XXX internal because X11Hwnd needs them + internal IntPtr CustomVisual; // Visual for window creation + internal IntPtr CustomColormap; // Colormap for window creation + + X11Keyboard Keyboard; + internal X11Dnd Dnd; // XXX X11Hwnd needs it to enable Dnd + bool detectable_key_auto_repeat; + + X11Atoms atoms; + X11RootHwnd root_hwnd; + X11Hwnd foster_hwnd; + + // Clipboard + IntPtr ClipMagic; + + // Focus tracking + internal X11Hwnd ActiveWindow; + X11Hwnd FocusWindow; + + // Modality support + Stack ModalWindows; // Stack of our modal windows + + // Caret + CaretStruct Caret; + + // mouse hover message generation + // XXX internal because X11Atoms needs to access it.. + internal HoverStruct HoverState; + + // double click message generation + ClickStruct ClickPending; + int DoubleClickInterval; // msec; max interval between clicks to count as double click + + // Support for mouse grab + GrabStruct Grab; + + // Cursors + IntPtr LastCursorWindow; // The last window we set the cursor on + IntPtr LastCursorHandle; // The handle that was last set on LastCursorWindow + IntPtr OverrideCursorHandle; // The cursor that is set to override any other cursors + + // State + Point MousePosition; // Last position of mouse, in screen coords + MouseButtons MouseState; // Last state of mouse buttons + + XErrorHandler ErrorHandler; // Error handler delegate + bool ErrorExceptions; // Throw exceptions on X errors + + Thread event_thread; // the background thread that just watches our X socket + +#if __MonoCS__ + Pollfd[] pollfds; +#endif + + public X11Display (IntPtr display) + { + if (display == IntPtr.Zero) { + throw new ArgumentNullException("Display", + "Could not open display (X-Server required. Check your DISPLAY environment variable)"); + } + + this.display = display; + + // Debugging support + if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) { + Xlib.XSynchronize (display, true); + } + + if (Environment.GetEnvironmentVariable ("MONO_XEXCEPTIONS") != null) { + ErrorExceptions = true; + } + + atoms = new X11Atoms (this); + + DoubleClickInterval = 500; + + HoverState.Interval = 500; + HoverState.Timer = new Timer(); + HoverState.Timer.Enabled = false; + HoverState.Timer.Interval = HoverState.Interval; + HoverState.Timer.Tick += new EventHandler(MouseHover); + HoverState.Size = new Size(4, 4); + HoverState.X = -1; + HoverState.Y = -1; + + ActiveWindow = null; + FocusWindow = null; + ModalWindows = new Stack(3); + + MouseState = MouseButtons.None; + MousePosition = new Point(0, 0); + + Caret.Timer = new Timer(); + Caret.Timer.Interval = 500; // FIXME - where should this number come from? + Caret.Timer.Tick += new EventHandler(CaretCallback); + + // XXX multiscreen work here + root_hwnd = new X11RootHwnd (this, Xlib.XRootWindow (display, DefaultScreen)); + + // XXX do we need a per-screen foster parent? + // Create the foster parent + foster_hwnd = new X11Hwnd (this, + Xlib.XCreateSimpleWindow (display, root_hwnd.WholeWindow, + 0, 0, 1, 1, 4, UIntPtr.Zero, UIntPtr.Zero)); + +#if __MonoCS__ + pollfds = new Pollfd [1]; + pollfds [0] = new Pollfd (); + pollfds [0].fd = Xlib.XConnectionNumber (display); + pollfds [0].events = PollEvents.POLLIN; +#endif + + Keyboard = new X11Keyboard(display, foster_hwnd.Handle); + Dnd = new X11Dnd (display, Keyboard); + + ErrorExceptions = false; + + // Handle any upcoming errors + ErrorHandler = new XErrorHandler (HandleError); + Xlib.XSetErrorHandler (ErrorHandler); + + X11DesktopColors.Initialize(); // XXX we need to figure out how to make this display specific? + + // Disable keyboard autorepeat + try { + Xlib.XkbSetDetectableAutoRepeat (display, true, IntPtr.Zero); + detectable_key_auto_repeat = true; + } catch { + Console.Error.WriteLine ("Could not disable keyboard auto repeat, will attempt to disable manually."); + detectable_key_auto_repeat = false; + } + + // we re-set our error handler here, X11DesktopColor stuff might have stolen it (gtk does) + Xlib.XSetErrorHandler (ErrorHandler); + + // create our event thread (just sits on the X socket waiting for events) + event_thread = new Thread (new ThreadStart (XEventThread)); + event_thread.IsBackground = true; + event_thread.Start (); + } + + #region Callbacks + private void MouseHover(object sender, EventArgs e) + { + HoverState.Timer.Enabled = false; + + if (HoverState.Window != IntPtr.Zero) { + X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow (HoverState.Window); + if (hwnd != null) { + XEvent xevent = new XEvent (); + + xevent.type = XEventName.ClientMessage; + xevent.ClientMessageEvent.display = display; + xevent.ClientMessageEvent.window = HoverState.Window; + xevent.ClientMessageEvent.message_type = HoverState.Atom; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = (IntPtr) (HoverState.Y << 16 | HoverState.X); + + hwnd.Queue.Enqueue (xevent); + } + } + } + + private void CaretCallback (object sender, EventArgs e) + { + if (Caret.Paused) { + return; + } + Caret.On = !Caret.On; + + Xlib.XDrawLine (display, Caret.Hwnd, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height); + } + + internal string WhereString () + { + StackTrace stack; + StackFrame frame; + string newline; + string unknown; + StringBuilder sb; + MethodBase method; + + newline = String.Format("{0}\t {1} ", Environment.NewLine, "at"); + unknown = ""; + sb = new StringBuilder(); + stack = new StackTrace(true); + + for (int i = 0; i < stack.FrameCount; i++) { + frame = stack.GetFrame (i); + sb.Append(newline); + + method = frame.GetMethod(); + if (method != null) { + if (frame.GetFileLineNumber() != 0) + sb.AppendFormat ("{0}.{1} () [{2}:{3}]", + method.DeclaringType.FullName, method.Name, + Path.GetFileName(frame.GetFileName()), frame.GetFileLineNumber()); + else + sb.AppendFormat ("{0}.{1} ()", method.DeclaringType.FullName, method.Name); + } else { + sb.Append(unknown); + } + } + return sb.ToString(); + } + + private int HandleError (IntPtr display, ref XErrorEvent error_event) + { + if (ErrorExceptions) + throw new X11Exception (error_event.display, error_event.resourceid, + error_event.serial, error_event.error_code, + error_event.request_code, error_event.minor_code); + else + Console.WriteLine ("X11 Error encountered: {0}{1}\n", + X11Exception.GetMessage(error_event.display, error_event.resourceid, + error_event.serial, error_event.error_code, + error_event.request_code, error_event.minor_code), + WhereString()); + return 0; + } + #endregion // Callbacks + + private void ShowCaret() + { + if ((Caret.gc == IntPtr.Zero) || Caret.On) { + return; + } + Caret.On = true; + + Xlib.XDrawLine (display, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height); + } + + private void HideCaret() + { + if ((Caret.gc == IntPtr.Zero) || !Caret.On) { + return; + } + Caret.On = false; + + Xlib.XDrawLine (display, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height); + } + + public void CaretVisible (IntPtr handle, bool visible) + { + if (Caret.Hwnd == handle) { + if (visible) { + if (!Caret.Visible) { + Caret.Visible = true; + ShowCaret(); + Caret.Timer.Start(); + } + } else { + Caret.Visible = false; + Caret.Timer.Stop(); + HideCaret(); + } + } + } + + public void AudibleAlert () + { + Xlib.XBell (display, 0); + } + + public void Flush () + { + Xlib.XFlush (display); + } + + public void Close () + { + // XXX shut down the event_thread + Xlib.XCloseDisplay (display); + } + + public IntPtr XGetParent(IntPtr handle) + { + IntPtr Root; + IntPtr Parent; + IntPtr Children; + int ChildCount; + + Xlib.XQueryTree (display, handle, out Root, out Parent, out Children, out ChildCount); + + if (Children!=IntPtr.Zero) { + Xlib.XFree(Children); + } + + return Parent; + } + + public bool SystrayAdd(IntPtr handle, string tip, Icon icon, out ToolTip tt) + { + IntPtr SystrayMgrWindow; + + Xlib.XGrabServer (display); + SystrayMgrWindow = Xlib.XGetSelectionOwner (display, Atoms._NET_SYSTEM_TRAY_S); + Xlib.XUngrabServer (display); + + if (SystrayMgrWindow != IntPtr.Zero) { + XSizeHints size_hints; + X11Hwnd hwnd; + + hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); +#if DriverDebug + Console.WriteLine("Adding Systray Whole:{0:X}, Client:{1:X}", + hwnd.WholeWindow.ToInt32(), hwnd.ClientWindow.ToInt32()); +#endif + + // Oh boy. + if (hwnd.ClientWindow != hwnd.WholeWindow) { + Xlib.XDestroyWindow (display, hwnd.ClientWindow); + hwnd.ClientWindow = hwnd.WholeWindow; + + try { + hwnd.Queue.Lock (); + + /* by virtue of the way the tests are ordered when determining if it's PAINT + or NCPAINT, ClientWindow == WholeWindow will always be PAINT. So, if we're + waiting on an nc_expose, drop it and remove the hwnd from the list (unless + there's a pending expose). */ + hwnd.PendingNCExpose = false; + } + finally { + hwnd.Queue.Unlock (); + } + } + + size_hints = new XSizeHints(); + + size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize); + + size_hints.min_width = 24; + size_hints.min_height = 24; + size_hints.max_width = 24; + size_hints.max_height = 24; + size_hints.base_width = 24; + size_hints.base_height = 24; + + Xlib.XSetWMNormalHints (display, hwnd.WholeWindow, ref size_hints); + + int[] atoms = new int[2]; + atoms [0] = 1; // Version 1 + atoms [1] = 1; // we want to be mapped + + // This line cost me 3 days... + Xlib.XChangeProperty (display, + hwnd.WholeWindow, Atoms._XEMBED_INFO, Atoms._XEMBED_INFO, 32, + PropertyMode.Replace, atoms, 2); + + // Need to pick some reasonable defaults + tt = new ToolTip(); + tt.AutomaticDelay = 100; + tt.InitialDelay = 250; + tt.ReshowDelay = 250; + tt.ShowAlways = true; + + if ((tip != null) && (tip != string.Empty)) { + tt.SetToolTip(Widget.FromHandle(handle), tip); + tt.Active = true; + } else { + tt.Active = false; + } + + SendNetClientMessage (SystrayMgrWindow, + Atoms._NET_SYSTEM_TRAY_OPCODE, + IntPtr.Zero, + (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK, + hwnd.WholeWindow); + + return true; + } + + tt = null; + return false; + } + + public bool SystrayChange (IntPtr handle, string tip, Icon icon, ref ToolTip tt) + { + Widget Widget; + + Widget = Widget.FromHandle(handle); + if (Widget != null && tt != null) { + tt.SetToolTip(Widget, tip); + tt.Active = true; + return true; + } else { + return false; + } + } + + public void SystrayRemove(IntPtr handle, ref ToolTip tt) + { +#if GTKSOCKET_SUPPORTS_REPARENTING + X11Hwnd hwnd; + + hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + /* in the XEMBED spec, it mentions 3 ways for a client window to break the protocol with the embedder. + * 1. The embedder can unmap the window and reparent to the root window (we should probably handle this...) + * 2. The client can reparent its window out of the embedder window. + * 3. The client can destroy its window. + * + * this call to SetParent is case 2, but in + * the spec it also mentions that gtk doesn't + * support this at present. Looking at HEAD + * gtksocket-x11.c jives with this statement. + * + * so we can't reparent. we have to destroy. + */ + SetParent(hwnd.WholeWindow, FosterParent); +#else + Widget Widget = Widget.FromHandle(handle); + if (Widget is NotifyIcon.NotifyIconWindow) + ((NotifyIcon.NotifyIconWindow)Widget).InternalRecreateHandle (); +#endif + + // The caller can now re-dock it later... + if (tt != null) { + tt.Dispose(); + tt = null; + } + } + + public void ResetMouseHover (X11Hwnd hovering) + { + HoverState.Timer.Enabled = hovering != null; + HoverState.X = MousePosition.X; + HoverState.Y = MousePosition.Y; + HoverState.Window = hovering == null ? IntPtr.Zero : hovering.Handle; + } + + public void ShowCursor (bool show) + { + ; // FIXME - X11 doesn't 'hide' the cursor. we could create an empty cursor + } + + public void SetModal (X11Hwnd hwnd, bool Modal) + { + if (Modal) { + ModalWindows.Push(hwnd); + } else { + // XXX do we need to pop until the + // hwnd is off the stack? or just the + // most recently pushed hwnd? + if (ModalWindows.Contains(hwnd)) { + ModalWindows.Pop(); + } + + if (ModalWindows.Count > 0) { + X11Hwnd top_hwnd = (X11Hwnd)ModalWindows.Peek(); + top_hwnd.Activate(); + } + } + } + + public TransparencySupport SupportsTransparency () + { + // compiz adds _NET_WM_WINDOW_OPACITY to _NET_SUPPORTED on the root window, check for that + return ((IList)root_hwnd._NET_SUPPORTED).Contains (Atoms._NET_WM_WINDOW_OPACITY) ? TransparencySupport.GetSet : TransparencySupport.None; + } + + public void SendAsyncMethod (AsyncMethodData method) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(method.Handle); + XEvent xevent = new XEvent (); + + xevent.type = XEventName.ClientMessage; + xevent.ClientMessageEvent.display = display; + xevent.ClientMessageEvent.window = method.Handle; + xevent.ClientMessageEvent.message_type = Atoms.AsyncAtom; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = (IntPtr) GCHandle.Alloc (method); + + hwnd.Queue.Enqueue (xevent); + } + + delegate IntPtr WndProcDelegate (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam); + + public IntPtr SendMessage (IntPtr handle, Msg message, IntPtr wParam, IntPtr lParam) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + if (hwnd == null) + return IntPtr.Zero; + + if (hwnd.Queue.Thread != Thread.CurrentThread) { + AsyncMethodResult result; + AsyncMethodData data; + + result = new AsyncMethodResult (); + data = new AsyncMethodData (); + + data.Handle = hwnd.Handle; + data.Method = new WndProcDelegate (NativeWindow.WndProc); + data.Args = new object[] { hwnd.Handle, message, wParam, lParam }; + data.Result = result; + + SendAsyncMethod (data); +#if DriverDebug || DriverDebugThreads + Console.WriteLine ("Sending {0} message across.", message); +#endif + + return IntPtr.Zero; + } + else { + return NativeWindow.WndProc (hwnd.Handle, message, wParam, lParam); + } + } + + public int SendInput (IntPtr handle, Queue keys) { + if (handle == IntPtr.Zero) + return 0; + + int count = keys.Count; + Hwnd hwnd = Hwnd.ObjectFromHandle(handle); + + while (keys.Count > 0) { + + MSG msg = (MSG)keys.Dequeue(); + + XEvent xevent = new XEvent (); + + xevent.type = (msg.message == Msg.WM_KEYUP ? XEventName.KeyRelease : XEventName.KeyPress); + xevent.KeyEvent.display = display; + + if (hwnd != null) { + xevent.KeyEvent.window = hwnd.whole_window; + } else { + xevent.KeyEvent.window = IntPtr.Zero; + } + + xevent.KeyEvent.keycode = Keyboard.ToKeycode((int)msg.wParam); + + hwnd.Queue.EnqueueLocked (xevent); + } + return count; + } + + // FIXME - I think this should just enqueue directly + public bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam) + { + XEvent xevent = new XEvent (); + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + xevent.type = XEventName.ClientMessage; + xevent.ClientMessageEvent.display = display; + + if (hwnd != null) { + xevent.ClientMessageEvent.window = hwnd.WholeWindow; + } else { + xevent.ClientMessageEvent.window = IntPtr.Zero; + } + + xevent.ClientMessageEvent.message_type = Atoms.PostAtom; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = handle; + xevent.ClientMessageEvent.ptr2 = (IntPtr) message; + xevent.ClientMessageEvent.ptr3 = wparam; + xevent.ClientMessageEvent.ptr4 = lparam; + + hwnd.Queue.Enqueue (xevent); + + return true; + } + + public void SendNetWMMessage (IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) + { + XEvent xev; + + xev = new XEvent(); + xev.ClientMessageEvent.type = XEventName.ClientMessage; + xev.ClientMessageEvent.send_event = true; + xev.ClientMessageEvent.window = window; + xev.ClientMessageEvent.message_type = message_type; + xev.ClientMessageEvent.format = 32; + xev.ClientMessageEvent.ptr1 = l0; + xev.ClientMessageEvent.ptr2 = l1; + xev.ClientMessageEvent.ptr3 = l2; + + Xlib.XSendEvent (display, root_hwnd.Handle, false, + new IntPtr ((int) (EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask)), ref xev); + } + + public void SendNetClientMessage (IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) + { + XEvent xev; + + xev = new XEvent(); + xev.ClientMessageEvent.type = XEventName.ClientMessage; + xev.ClientMessageEvent.send_event = true; + xev.ClientMessageEvent.window = window; + xev.ClientMessageEvent.message_type = message_type; + xev.ClientMessageEvent.format = 32; + xev.ClientMessageEvent.ptr1 = l0; + xev.ClientMessageEvent.ptr2 = l1; + xev.ClientMessageEvent.ptr3 = l2; + + Xlib.XSendEvent (display, window, false, new IntPtr ((int)EventMask.NoEventMask), ref xev); + } + + public bool TranslateMessage (ref MSG msg) + { + return Keyboard.TranslateMessage (ref msg); + } + + public IntPtr DispatchMessage (ref MSG msg) + { + return NativeWindow.WndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam); + } + + private void QueryPointer (IntPtr w, out IntPtr root, out IntPtr child, + out int root_x, out int root_y, out int child_x, out int child_y, + out int mask) + { + /* this code was written with the help of + glance at gdk. I never would have realized we + needed a loop in order to traverse down in the + hierarchy. I would have assumed you'd get the + most deeply nested child and have to do + XQueryTree to move back up the hierarchy.. + stupid me, of course. */ + IntPtr c; + + // Xlib.XGrabServer (display); + + Xlib.XQueryPointer (display, w, out root, out c, + out root_x, out root_y, out child_x, out child_y, + out mask); + + if (root != w) + c = root; + + IntPtr child_last = IntPtr.Zero; + while (c != IntPtr.Zero) { + child_last = c; + Xlib.XQueryPointer (display, c, out root, out c, + out root_x, out root_y, out child_x, out child_y, + out mask); + } + + // Xlib.XUngrabServer (display); + + child = child_last; + } + + public void SetCursorPos (int x, int y) + { + IntPtr root, child; + int root_x, root_y, child_x, child_y, mask; + + /* we need to do a + * QueryPointer before warping + * because if the warp is on + * the RootWindow, the x/y are + * relative to the current + * mouse position + */ + QueryPointer (RootWindow.Handle, + out root, + out child, + out root_x, out root_y, + out child_x, out child_y, + out mask); + + Xlib.XWarpPointer (display, IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, x - root_x, y - root_y); + + Xlib.XFlush (display); + + /* then we need to a + * QueryPointer after warping + * to manually generate a + * motion event for the window + * we move into. + */ + QueryPointer (RootWindow.Handle, + out root, + out child, + out root_x, out root_y, + out child_x, out child_y, + out mask); + + X11Hwnd child_hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(child); + if (child_hwnd == null) + return; + + XEvent xevent = new XEvent (); + + xevent.type = XEventName.MotionNotify; + xevent.MotionEvent.display = display; + xevent.MotionEvent.window = child_hwnd.Handle; + xevent.MotionEvent.root = RootWindow.Handle; + xevent.MotionEvent.x = child_x; + xevent.MotionEvent.y = child_y; + xevent.MotionEvent.x_root = root_x; + xevent.MotionEvent.y_root = root_y; + xevent.MotionEvent.state = mask; + + child_hwnd.Queue.Enqueue (xevent); + } + + public void SetFocus (X11Hwnd new_focus) + { + if (new_focus == FocusWindow) + return; + + X11Hwnd prev_focus = FocusWindow; + FocusWindow = new_focus; + + if (prev_focus != null) + SendMessage (prev_focus.Handle, Msg.WM_KILLFOCUS, + FocusWindow == null ? IntPtr.Zero : FocusWindow.Handle, IntPtr.Zero); + if (FocusWindow != null) + SendMessage (FocusWindow.Handle, Msg.WM_SETFOCUS, + prev_focus == null ? IntPtr.Zero : prev_focus.Handle, IntPtr.Zero); + + //XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).ClientWindow, RevertTo.None, IntPtr.Zero); + } + + public IntPtr DefineCursor (Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) + { + IntPtr cursor; + Bitmap cursor_bitmap; + Bitmap cursor_mask; + Byte[] cursor_bits; + Byte[] mask_bits; + Color c_pixel; + Color m_pixel; + int width; + int height; + IntPtr cursor_pixmap; + IntPtr mask_pixmap; + XColor fg; + XColor bg; + bool and; + bool xor; + + if (Xlib.XQueryBestCursor (display, RootWindow.Handle, bitmap.Width, bitmap.Height, out width, out height) == 0) { + return IntPtr.Zero; + } + + // Win32 only allows creation cursors of a certain size + if ((bitmap.Width != width) || (bitmap.Width != height)) { + cursor_bitmap = new Bitmap(bitmap, new Size(width, height)); + cursor_mask = new Bitmap(mask, new Size(width, height)); + } else { + cursor_bitmap = bitmap; + cursor_mask = mask; + } + + width = cursor_bitmap.Width; + height = cursor_bitmap.Height; + + cursor_bits = new Byte[(width / 8) * height]; + mask_bits = new Byte[(width / 8) * height]; + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + c_pixel = cursor_bitmap.GetPixel(x, y); + m_pixel = cursor_mask.GetPixel(x, y); + + and = c_pixel == cursor_pixel; + xor = m_pixel == mask_pixel; + + if (!and && !xor) { + // Black + // cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8))); // The bit already is 0 + mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8)); + } else if (and && !xor) { + // White + cursor_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8)); + mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8)); +#if notneeded + } else if (and && !xor) { + // Screen + } else if (and && xor) { + // Inverse Screen + + // X11 doesn't know the 'reverse screen' concept, so we'll treat them the same + // we want both to be 0 so nothing to be done + //cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8))); + //mask_bits[y * width / 8 + x / 8] |= (byte)(01 << (x % 8)); +#endif + } + } + } + + cursor_pixmap = Xlib.XCreatePixmapFromBitmapData (display, RootWindow.Handle, + cursor_bits, width, height, (IntPtr)1, (IntPtr)0, 1); + mask_pixmap = Xlib.XCreatePixmapFromBitmapData (display, RootWindow.Handle, + mask_bits, width, height, (IntPtr)1, (IntPtr)0, 1); + fg = new XColor(); + bg = new XColor(); + + fg.pixel = Xlib.XWhitePixel (display, DefaultScreen); + fg.red = (ushort)65535; + fg.green = (ushort)65535; + fg.blue = (ushort)65535; + + bg.pixel = Xlib.XBlackPixel (display, DefaultScreen); + + cursor = Xlib.XCreatePixmapCursor (display, cursor_pixmap, mask_pixmap, ref fg, ref bg, xHotSpot, yHotSpot); + + Xlib.XFreePixmap (display, cursor_pixmap); + Xlib.XFreePixmap (display, mask_pixmap); + + return cursor; + } + + public Bitmap DefineStdCursorBitmap (StdCursor id) + { + CursorFontShape shape; + string name; + IntPtr theme; + int size; + Bitmap bmp = null; + + try { + shape = XplatUIX11.StdCursorToFontShape (id); + name = shape.ToString ().Replace ("XC_", string.Empty); + size = XplatUIX11.XcursorGetDefaultSize (Handle); + theme = XplatUIX11.XcursorGetTheme (Handle); + IntPtr images_ptr = XplatUIX11.XcursorLibraryLoadImages (name, theme, size); +#if debug + Console.WriteLine ("DefineStdCursorBitmap, id={0}, #id={1}, name{2}, size={3}, theme: {4}, images_ptr={5}", id, (int) id, name, size, Marshal.PtrToStringAnsi (theme), images_ptr); +#endif + + if (images_ptr == IntPtr.Zero) { + return null; + } + + XcursorImages images = (XcursorImages)Marshal.PtrToStructure (images_ptr, typeof (XcursorImages)); +#if debug + Console.WriteLine ("DefineStdCursorBitmap, cursor has {0} images", images.nimage); +#endif + + if (images.nimage > 0) { + // We only care about the first image. + XcursorImage image = (XcursorImage)Marshal.PtrToStructure (Marshal.ReadIntPtr (images.images), typeof (XcursorImage)); + +#if debug + Console.WriteLine ("DefineStdCursorBitmap, loaded image 0) && (prop != IntPtr.Zero)) { + active = (IntPtr)Marshal.ReadInt32(prop); + Xlib.XFree(prop); + } + + return (X11Hwnd)Hwnd.GetObjectFromWindow(active); + } + + public void SetActiveWindow (X11Hwnd new_active_window) + { + if (new_active_window != ActiveWindow) { + if (ActiveWindow != null) + PostMessage (ActiveWindow.Handle, Msg.WM_ACTIVATE, + (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero); + + ActiveWindow = new_active_window; + + if (ActiveWindow != null) + PostMessage (ActiveWindow.Handle, Msg.WM_ACTIVATE, + (IntPtr)WindowActiveFlags.WA_ACTIVE, IntPtr.Zero); + } + + if (ModalWindows.Count > 0) { + // Modality handling, if we are modal and the new active window is one + // of ours but not the modal one, switch back to the modal window + + if (ActiveWindow != null && + NativeWindow.FromHandle (ActiveWindow.Handle) != null) { + if (ActiveWindow != (X11Hwnd)ModalWindows.Peek()) + ((X11Hwnd)ModalWindows.Peek()).Activate (); + } + } + } + + public void GetDisplaySize (out Size size) + { + XWindowAttributes attributes = new XWindowAttributes(); + + // FIXME - use _NET_WM messages instead? + Xlib.XGetWindowAttributes (display, RootWindow.Handle, ref attributes); + + size = new Size(attributes.width, attributes.height); + } + + // XXX this method doesn't really fit well anywhere in the backend + public SizeF GetAutoScaleSize (Font font) + { + Graphics g; + float width; + string magic_string = "The quick brown fox jumped over the lazy dog."; + double magic_number = 44.549996948242189; // XXX my god, where did this number come from? + + g = Graphics.FromHwnd (FosterParent.Handle); + + width = (float) (g.MeasureString (magic_string, font).Width / magic_number); + return new SizeF(width, font.Height); + } + + public void GetCursorPos (X11Hwnd hwnd, out int x, out int y) + { + IntPtr use_handle; + IntPtr root; + IntPtr child; + int root_x; + int root_y; + int win_x; + int win_y; + int keys_buttons; + + if (hwnd != null) + use_handle = hwnd.Handle; + else + use_handle = RootWindow.Handle; + + QueryPointer (use_handle, out root, out child, out root_x, out root_y, out win_x, out win_y, out keys_buttons); + + if (hwnd != null) { + x = win_x; + y = win_y; + } else { + x = root_x; + y = root_y; + } + } + + public IntPtr GetFocus () + { + return FocusWindow.Handle; + } + + public IntPtr GetMousewParam (int Delta) + { + int result = 0; + + if ((MouseState & MouseButtons.Left) != 0) { + result |= (int)MsgButtons.MK_LBUTTON; + } + + if ((MouseState & MouseButtons.Middle) != 0) { + result |= (int)MsgButtons.MK_MBUTTON; + } + + if ((MouseState & MouseButtons.Right) != 0) { + result |= (int)MsgButtons.MK_RBUTTON; + } + + Keys mods = ModifierKeys; + if ((mods & Keys.Widget) != 0) { + result |= (int)MsgButtons.MK_CONTROL; + } + + if ((mods & Keys.Shift) != 0) { + result |= (int)MsgButtons.MK_SHIFT; + } + + result |= Delta << 16; + + return (IntPtr)result; + } + + public void GrabInfo (out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea) + { + handle = Grab.Hwnd; + GrabConfined = Grab.Confined; + GrabArea = Grab.Area; + } + + public void GrabWindow (X11Hwnd hwnd, X11Hwnd confine_to) + { + IntPtr confine_to_window; + + confine_to_window = IntPtr.Zero; + + if (confine_to != null) { + Console.WriteLine (Environment.StackTrace); + + XWindowAttributes attributes = new XWindowAttributes(); + + Xlib.XGetWindowAttributes (display, confine_to.ClientWindow, ref attributes); + + Grab.Area.X = attributes.x; + Grab.Area.Y = attributes.y; + Grab.Area.Width = attributes.width; + Grab.Area.Height = attributes.height; + Grab.Confined = true; + confine_to_window = confine_to.ClientWindow; + } + + Grab.Hwnd = hwnd.ClientWindow; + + Xlib.XGrabPointer (display, hwnd.ClientWindow, false, + EventMask.ButtonPressMask | EventMask.ButtonMotionMask | + EventMask.ButtonReleaseMask | EventMask.PointerMotionMask, + GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, IntPtr.Zero, IntPtr.Zero); + } + + public void UngrabWindow (X11Hwnd hwnd) + { + Xlib.XUngrabPointer (display, IntPtr.Zero); + Xlib.XFlush (display); + + // XXX make sure hwnd is what should have the grab and throw if not + Grab.Hwnd = IntPtr.Zero; + Grab.Confined = false; + } + +#if notyet + private void TranslatePropertyToClipboard (IntPtr property) + { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + + Clipboard.Item = null; + + Xlib.XGetWindowProperty (display, FosterParent.Handle, + property, IntPtr.Zero, new IntPtr (0x7fffffff), true, + Atoms.AnyPropertyType, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + + if ((long)nitems > 0) { + if (property == Atoms.XA_STRING) { + Clipboard.Item = Marshal.PtrToStringAnsi(prop); + } else if (property == Atoms.XA_BITMAP) { + // FIXME - convert bitmap to image + } else if (property == Atoms.XA_PIXMAP) { + // FIXME - convert pixmap to image + } else if (property == Atoms.OEMTEXT) { + Clipboard.Item = Marshal.PtrToStringAnsi(prop); + } else if (property == Atoms.UNICODETEXT) { + Clipboard.Item = Marshal.PtrToStringAnsi(prop); + } + + Xlib.XFree(prop); + } + } +#endif + + // XXX should we be using @handle instead of Atoms.CLIPBOARD here? + public int[] ClipboardAvailableFormats (IntPtr handle) + { + // XXX deal with the updatemessagequeue stuff +#if true + return new int[0]; +#else + DataFormats.Format f; + int[] result; + + f = DataFormats.Format.List; + + if (Xlib.XGetSelectionOwner (display, Atoms.CLIPBOARD) == IntPtr.Zero) { + return null; + } + + Clipboard.Formats = new ArrayList(); + + while (f != null) { + Xlib.XConvertSelection (display, Atoms.CLIPBOARD, (IntPtr)f.Id, (IntPtr)f.Id, FosterParent.Handle, IntPtr.Zero); + + Clipboard.Enumerating = true; + while (Clipboard.Enumerating) { + UpdateMessageQueue(null); + } + f = f.Next; + } + + result = new int[Clipboard.Formats.Count]; + + for (int i = 0; i < Clipboard.Formats.Count; i++) { + result[i] = ((IntPtr)Clipboard.Formats[i]).ToInt32 (); + } + + Clipboard.Formats = null; + return result; +#endif + } + + public void ClipboardClose (IntPtr handle) + { + if (handle != ClipMagic) { + throw new ArgumentException("handle is not a valid clipboard handle"); + } + return; + } + + public int ClipboardGetID (IntPtr handle, string format) + { + if (handle != ClipMagic) { + throw new ArgumentException("handle is not a valid clipboard handle"); + } + + if (format == "Text" ) return Atoms.XA_STRING.ToInt32(); + else if (format == "Bitmap" ) return Atoms.XA_BITMAP.ToInt32(); + //else if (format == "MetaFilePict" ) return 3; + //else if (format == "SymbolicLink" ) return 4; + //else if (format == "DataInterchangeFormat" ) return 5; + //else if (format == "Tiff" ) return 6; + else if (format == "OEMText" ) return Atoms.OEMTEXT.ToInt32(); + else if (format == "DeviceIndependentBitmap" ) return Atoms.XA_PIXMAP.ToInt32(); + else if (format == "Palette" ) return Atoms.XA_COLORMAP.ToInt32(); // Useless + //else if (format == "PenData" ) return 10; + //else if (format == "RiffAudio" ) return 11; + //else if (format == "WaveAudio" ) return 12; + else if (format == "UnicodeText" ) return Atoms.UNICODETEXT.ToInt32(); + //else if (format == "EnhancedMetafile" ) return 14; + //else if (format == "FileDrop" ) return 15; + //else if (format == "Locale" ) return 16; + + return Xlib.XInternAtom (display, format, false).ToInt32(); + } + + public IntPtr ClipboardOpen (bool primary_selection) + { + if (!primary_selection) + ClipMagic = Atoms.CLIPBOARD; + else + ClipMagic = Atoms.PRIMARY; + + return ClipMagic; + } + + // XXX @converter? + public object ClipboardRetrieve (IntPtr handle, int type, XplatUI.ClipboardToObject converter) + { + // XXX deal with the UpdateMessageQueue stuff +#if true + return null; +#else + Xlib.XConvertSelection (display, handle, (IntPtr)type, (IntPtr)type, FosterParent, IntPtr.Zero); + + Clipboard.Retrieving = true; + while (Clipboard.Retrieving) { + UpdateMessageQueue(null); + } + + return Clipboard.Item; +#endif + } + + public PaintEventArgs PaintEventStart (ref Message m, IntPtr handle, bool client) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (Caret.Visible == true) { + Caret.Paused = true; + HideCaret(); + } + + return hwnd.PaintEventStart (ref m, client); + } + + public void PaintEventEnd (ref Message m, IntPtr handle, bool client) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + hwnd.PaintEventEnd (ref m, client); + + if (Caret.Visible == true) { + ShowCaret(); + Caret.Paused = false; + } + } + + public void SetCursor (IntPtr handle, IntPtr cursor) + { + Hwnd hwnd; + + if (OverrideCursorHandle == IntPtr.Zero) { + if ((LastCursorWindow == handle) && (LastCursorHandle == cursor)) + return; + + LastCursorHandle = cursor; + LastCursorWindow = handle; + + hwnd = Hwnd.ObjectFromHandle(handle); + if (cursor != IntPtr.Zero) + Xlib.XDefineCursor (display, hwnd.whole_window, cursor); + else + Xlib.XUndefineCursor (display, hwnd.whole_window); + Xlib.XFlush (display); + } + else { + hwnd = Hwnd.ObjectFromHandle(handle); + Xlib.XDefineCursor (display, hwnd.whole_window, OverrideCursorHandle); + } + } + + public DragDropEffects StartDrag (IntPtr handle, object data, + DragDropEffects allowed_effects) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle (handle); + + if (hwnd == null) + throw new ArgumentException ("Attempt to begin drag from invalid window handle (" + handle.ToInt32 () + ")."); + + return Dnd.StartDrag (hwnd.ClientWindow, data, allowed_effects); + } + + public X11Atoms Atoms { + get { return atoms; } + } + + public int CurrentTimestamp { + get { + TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1)); + + return (int) t.TotalSeconds; + } + } + + public Size CursorSize { + get { + int x; + int y; + + if (Xlib.XQueryBestCursor (display, RootWindow.Handle, 32, 32, out x, out y) != 0) { + return new Size (x, y); + } else { + return new Size (16, 16); + } + } + } + + public IntPtr Handle { + get { return display; } + } + + public Size IconSize { + get { + IntPtr list; + XIconSize size; + int count; + + if (Xlib.XGetIconSizes (display, RootWindow.Handle, out list, out count) != 0) { + long current; + int largest; + + current = (long)list; + largest = 0; + + size = new XIconSize(); + + for (int i = 0; i < count; i++) { + size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType()); + current += Marshal.SizeOf(size); + + // Look for our preferred size + if (size.min_width == 32) { + Xlib.XFree(list); + return new Size(32, 32); + } + + if (size.max_width == 32) { + Xlib.XFree(list); + return new Size(32, 32); + } + + if (size.min_width < 32 && size.max_width > 32) { + int x; + + // check if we can fit one + x = size.min_width; + while (x < size.max_width) { + x += size.width_inc; + if (x == 32) { + Xlib.XFree(list); + return new Size(32, 32); + } + } + } + + if (largest < size.max_width) { + largest = size.max_width; + } + } + + // We didn't find a match or we wouldn't be here + return new Size(largest, largest); + + } else { + return new Size(32, 32); + } + } + } + + public int KeyboardSpeed { + get { + // + // A lot harder: need to do: + // XkbQueryExtension(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 1 + // XkbAllocKeyboard(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 0x080517a8 + // XkbGetWidgets(0x08051008, 1, 0x080517a8, 0xbfffdf54, 0xbfffdf58) = 0 + // + // And from that we can tell the repetition rate + // + // Notice, the values must map to: + // [0, 31] which maps to 2.5 to 30 repetitions per second. + // + return 0; + } + } + + public int KeyboardDelay { + get { + // + // Return values must range from 0 to 4, 0 meaning 250ms, + // and 4 meaning 1000 ms. + // + return 1; // ie, 500 ms + } + } + + public int DefaultScreen { + get { return Xlib.XDefaultScreen (display); } + } + + public IntPtr DefaultColormap { + // XXX multiscreen + get { return Xlib.XDefaultColormap (display, DefaultScreen); } + } + + public Keys ModifierKeys { + get { return Keyboard.ModifierKeys; } + } + + public IntPtr OverrideCursor { + get { return OverrideCursorHandle; } + set { + if (Grab.Hwnd != IntPtr.Zero) { + Xlib.XChangeActivePointerGrab (display, + EventMask.ButtonMotionMask | + EventMask.PointerMotionMask | + EventMask.ButtonPressMask | + EventMask.ButtonReleaseMask, + value, IntPtr.Zero); + return; + } + + OverrideCursorHandle = value; + } + } + + public X11RootHwnd RootWindow { + get { return root_hwnd; } + } + + public Size SmallIconSize { + get { + IntPtr list; + XIconSize size; + int count; + + if (Xlib.XGetIconSizes (display, RootWindow.Handle, out list, out count) != 0) { + long current; + int smallest; + + current = (long)list; + smallest = 0; + + size = new XIconSize(); + + for (int i = 0; i < count; i++) { + size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType()); + current += Marshal.SizeOf(size); + + // Look for our preferred size + if (size.min_width == 16) { + Xlib.XFree(list); + return new Size(16, 16); + } + + if (size.max_width == 16) { + Xlib.XFree(list); + return new Size(16, 16); + } + + if (size.min_width < 16 && size.max_width > 16) { + int x; + + // check if we can fit one + x = size.min_width; + while (x < size.max_width) { + x += size.width_inc; + if (x == 16) { + Xlib.XFree(list); + return new Size(16, 16); + } + } + } + + if (smallest == 0 || smallest > size.min_width) { + smallest = size.min_width; + } + } + + // We didn't find a match or we wouldn't be here + return new Size(smallest, smallest); + + } else { + return new Size(16, 16); + } + } + } + + public X11Hwnd FosterParent { + get { return foster_hwnd; } + } + + public int MouseHoverTime { + get { return HoverState.Interval; } + } + + public Rectangle VirtualScreen { + get { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + int width; + int height; + + Xlib.XGetWindowProperty (display, RootWindow.Handle, + Atoms._NET_DESKTOP_GEOMETRY, IntPtr.Zero, new IntPtr (256), false, Atoms.XA_CARDINAL, + out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + + if ((long)nitems < 2) + goto failsafe; + + width = Marshal.ReadIntPtr(prop, 0).ToInt32(); + height = Marshal.ReadIntPtr(prop, IntPtr.Size).ToInt32(); + Xlib.XFree(prop); + + return new Rectangle(0, 0, width, height); + + failsafe: + XWindowAttributes attributes = new XWindowAttributes(); + + Xlib.XGetWindowAttributes (display, RootWindow.Handle, ref attributes); + + return new Rectangle(0, 0, attributes.width, attributes.height); + } + } + + public Rectangle WorkingArea { + get { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + int width; + int height; + int current_desktop; + int x; + int y; + + Xlib.XGetWindowProperty (display, RootWindow.Handle, + Atoms._NET_CURRENT_DESKTOP, IntPtr.Zero, new IntPtr(1), false, Atoms.XA_CARDINAL, + out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + + if ((long)nitems < 1) { + goto failsafe; + } + + current_desktop = Marshal.ReadIntPtr(prop, 0).ToInt32(); + Xlib.XFree(prop); + + Xlib.XGetWindowProperty (display, RootWindow.Handle, + Atoms._NET_WORKAREA, IntPtr.Zero, new IntPtr (256), false, Atoms.XA_CARDINAL, + out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + + if ((long)nitems < 4 * current_desktop) { + goto failsafe; + } + + x = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop).ToInt32(); + y = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size).ToInt32(); + width = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 2).ToInt32(); + height = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 3).ToInt32(); + Xlib.XFree(prop); + + return new Rectangle(x, y, width, height); + + failsafe: + XWindowAttributes attributes = new XWindowAttributes(); + + Xlib.XGetWindowAttributes (display, RootWindow.Handle, ref attributes); + + return new Rectangle(0, 0, attributes.width, attributes.height); + } + } + + private void XEventThread () + { + while (true) { +#if __MonoCS__ + Syscall.poll (pollfds, 1U, -1); + + while (Xlib.XPending (display) > 0) { +#endif + XEvent xevent = new XEvent (); + Xlib.XNextEvent (display, ref xevent); + + // this is kind of a gross place to put this, but we don't know about the + // key repeat state in X11ThreadQueue, nor to we want the queue code calling + // XPeekEvent. + if (!detectable_key_auto_repeat && + xevent.type == XEventName.KeyRelease && + Xlib.XPending (display) > 0) { + + XEvent nextevent = new XEvent (); + Xlib.XPeekEvent (display, ref nextevent); + + if (nextevent.type == XEventName.KeyPress && + nextevent.KeyEvent.keycode == xevent.KeyEvent.keycode && + nextevent.KeyEvent.time == xevent.KeyEvent.time) { + continue; + } + } + + X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow(xevent.AnyEvent.window); + if (hwnd != null) + hwnd.Queue.Enqueue (xevent); +#if __MonoCS__ + } +#endif + } + } + + private void RedirectMsgToEnabledAncestor (X11Hwnd hwnd, MSG msg, IntPtr window, + ref int event_x, ref int event_y) + { + int x, y; + + IntPtr dummy; + msg.hwnd = hwnd.EnabledHwnd; + Xlib.XTranslateCoordinates (display, window, + Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, + event_x, event_y, + out x, out y, out dummy); + event_x = x; + event_y = y; + msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X); + } + + + // This is called from the thread owning the corresponding X11ThreadQueue + [MonoTODO("Implement filtering")] + public bool GetMessage (object queue_id, ref MSG msg, IntPtr handle, int wFilterMin, int wFilterMax) + { + X11ThreadQueue queue = (X11ThreadQueue)queue_id; + XEvent xevent; + bool client; + bool got_xevent = false; + + X11Hwnd hwnd; + + ProcessNextMessage: + do { + got_xevent = queue.Dequeue (out xevent); + + if (!got_xevent) { +#if spew + Console.WriteLine (">"); + Console.Out.Flush (); +#endif + break; + } + +#if spew + Console.Write ("-"); + Console.Out.Flush (); +#endif + + hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow (xevent.AnyEvent.window); + + // Handle messages for windows that are already or are about to be destroyed. + + // we need a special block for this because unless we remove the hwnd from the paint + // queue it will always stay there (since we don't handle the expose), and we'll + // effectively loop infinitely trying to repaint a non-existant window. + if (hwnd != null && hwnd.zombie && xevent.type == XEventName.Expose) { + hwnd.PendingExpose = hwnd.PendingNCExpose = false; + goto ProcessNextMessage; + } + + // We need to make sure we only allow DestroyNotify events through for zombie + // hwnds, since much of the event handling code makes requests using the hwnd's + // ClientWindow, and that'll result in BadWindow errors if there's some lag + // between the XDestroyWindow call and the DestroyNotify event. + if (hwnd == null || hwnd.zombie) { +#if DriverDebug || DriverDebugDestroy + Console.WriteLine("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}", + xevent.type, xevent.AnyEvent.window.ToInt32()); +#endif + goto ProcessNextMessage; + } + + client = hwnd.ClientWindow == xevent.AnyEvent.window; + + msg.hwnd = hwnd.Handle; + + switch (xevent.type) { + case XEventName.KeyPress: + Keyboard.KeyEvent (FocusWindow.Handle, xevent, ref msg); + return true; + + case XEventName.KeyRelease: + Keyboard.KeyEvent (FocusWindow.Handle, xevent, ref msg); + return true; + + case XEventName.ButtonPress: { + switch(xevent.ButtonEvent.button) { + case 1: + MouseState |= MouseButtons.Left; + if (client) { + msg.message = Msg.WM_LBUTTONDOWN; + } else { + msg.message = Msg.WM_NCLBUTTONDOWN; + hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + // TODO: For WM_NCLBUTTONDOWN wParam specifies a hit-test value not the virtual keys down + msg.wParam=GetMousewParam(0); + break; + + case 2: + MouseState |= MouseButtons.Middle; + if (client) { + msg.message = Msg.WM_MBUTTONDOWN; + } else { + msg.message = Msg.WM_NCMBUTTONDOWN; + hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + msg.wParam=GetMousewParam(0); + break; + + case 3: + MouseState |= MouseButtons.Right; + if (client) { + msg.message = Msg.WM_RBUTTONDOWN; + } else { + msg.message = Msg.WM_NCRBUTTONDOWN; + hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + msg.wParam=GetMousewParam(0); + break; + + case 4: + msg.hwnd = FocusWindow.Handle; + msg.message=Msg.WM_MOUSEWHEEL; + msg.wParam=GetMousewParam(120); + break; + + case 5: + msg.hwnd = FocusWindow.Handle; + msg.message=Msg.WM_MOUSEWHEEL; + msg.wParam=GetMousewParam(-120); + break; + } + + msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x); + MousePosition.X = xevent.ButtonEvent.x; + MousePosition.Y = xevent.ButtonEvent.y; + + if (!hwnd.Enabled) { + RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window, + ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + + if (Grab.Hwnd != IntPtr.Zero) + msg.hwnd = Grab.Hwnd; + + if (ClickPending.Pending && + ((((long)xevent.ButtonEvent.time - ClickPending.Time) < DoubleClickInterval) && + (msg.wParam == ClickPending.wParam) && + (msg.lParam == ClickPending.lParam) && + (msg.message == ClickPending.Message))) { + // Looks like a genuine double click, clicked twice on the same spot with the same keys + switch(xevent.ButtonEvent.button) { + case 1: + msg.message = client ? Msg.WM_LBUTTONDBLCLK : Msg.WM_NCLBUTTONDBLCLK; + break; + + case 2: + msg.message = client ? Msg.WM_MBUTTONDBLCLK : Msg.WM_NCMBUTTONDBLCLK; + break; + + case 3: + msg.message = client ? Msg.WM_RBUTTONDBLCLK : Msg.WM_NCRBUTTONDBLCLK; + break; + } + + ClickPending.Pending = false; + + } + else { + ClickPending.Pending = true; + ClickPending.Hwnd = msg.hwnd; + ClickPending.Message = msg.message; + ClickPending.wParam = msg.wParam; + ClickPending.lParam = msg.lParam; + ClickPending.Time = (long)xevent.ButtonEvent.time; + } + + if (msg.message == Msg.WM_LBUTTONDOWN || msg.message == Msg.WM_MBUTTONDOWN || msg.message == Msg.WM_RBUTTONDOWN) { + hwnd.SendParentNotify (msg.message, MousePosition.X, MousePosition.Y); + + // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or + // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after + // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh* + XEvent motionEvent = new XEvent (); + motionEvent.type = XEventName.MotionNotify; + motionEvent.MotionEvent.display = display; + motionEvent.MotionEvent.window = xevent.ButtonEvent.window; + motionEvent.MotionEvent.x = xevent.ButtonEvent.x; + motionEvent.MotionEvent.y = xevent.ButtonEvent.y; + hwnd.Queue.Enqueue (motionEvent); + } + + return true; + } + + case XEventName.ButtonRelease: + switch(xevent.ButtonEvent.button) { + case 1: + if (client) { + msg.message = Msg.WM_LBUTTONUP; + } else { + msg.message = Msg.WM_NCLBUTTONUP; + hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + MouseState &= ~MouseButtons.Left; + msg.wParam=GetMousewParam(0); + break; + + case 2: + if (client) { + msg.message = Msg.WM_MBUTTONUP; + } else { + msg.message = Msg.WM_NCMBUTTONUP; + hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + MouseState &= ~MouseButtons.Middle; + msg.wParam=GetMousewParam(0); + break; + + case 3: + if (client) { + msg.message = Msg.WM_RBUTTONUP; + } else { + msg.message = Msg.WM_NCRBUTTONUP; + hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + MouseState &= ~MouseButtons.Right; + msg.wParam=GetMousewParam(0); + break; + + case 4: + goto ProcessNextMessage; + + case 5: + goto ProcessNextMessage; + } + + if (!hwnd.Enabled) { + RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window, + ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + + if (Grab.Hwnd != IntPtr.Zero) + msg.hwnd = Grab.Hwnd; + + msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x); + MousePosition.X = xevent.ButtonEvent.x; + MousePosition.Y = xevent.ButtonEvent.y; + + // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or + // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after + // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh* + if (msg.message == Msg.WM_LBUTTONUP || msg.message == Msg.WM_MBUTTONUP || msg.message == Msg.WM_RBUTTONUP) { + XEvent motionEvent = new XEvent (); + motionEvent.type = XEventName.MotionNotify; + motionEvent.MotionEvent.display = display; + motionEvent.MotionEvent.window = xevent.ButtonEvent.window; + motionEvent.MotionEvent.x = xevent.ButtonEvent.x; + motionEvent.MotionEvent.y = xevent.ButtonEvent.y; + hwnd.Queue.Enqueue (motionEvent); + } + return true; + + case XEventName.MotionNotify: + /* XXX move the compression stuff here */ + + if (client) { +#if DriverDebugExtra + Console.WriteLine("GetMessage(): Window {0:X} MotionNotify x={1} y={2}", + client ? hwnd.ClientWindow.ToInt32() : hwnd.WholeWindow.ToInt32(), + xevent.MotionEvent.x, xevent.MotionEvent.y); +#endif + + if (Grab.Hwnd != IntPtr.Zero) + msg.hwnd = Grab.Hwnd; + else + NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT); + + msg.message = Msg.WM_MOUSEMOVE; + msg.wParam = GetMousewParam(0); + msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF); + + if (!hwnd.Enabled) { + RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window, + ref xevent.MotionEvent.x, ref xevent.MotionEvent.y); + } + + MousePosition.X = xevent.MotionEvent.x; + MousePosition.Y = xevent.MotionEvent.y; + + if ((HoverState.Timer.Enabled) && + (((MousePosition.X + HoverState.Size.Width) < HoverState.X) || + ((MousePosition.X - HoverState.Size.Width) > HoverState.X) || + ((MousePosition.Y + HoverState.Size.Height) < HoverState.Y) || + ((MousePosition.Y - HoverState.Size.Height) > HoverState.Y))) { + + HoverState.Timer.Stop(); + HoverState.Timer.Start(); + HoverState.X = MousePosition.X; + HoverState.Y = MousePosition.Y; + } + } + else { + HitTest ht; + IntPtr dummy; + int screen_x; + int screen_y; + + #if DriverDebugExtra + Console.WriteLine("GetMessage(): non-client area {0:X} MotionNotify x={1} y={2}", + client ? hwnd.ClientWindow.ToInt32() : hwnd.WholeWindow.ToInt32(), + xevent.MotionEvent.x, xevent.MotionEvent.y); + #endif + msg.message = Msg.WM_NCMOUSEMOVE; + + if (!hwnd.Enabled) { + RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window, + ref xevent.MotionEvent.x, ref xevent.MotionEvent.y); + } + + // The hit test is sent in screen coordinates + Xlib.XTranslateCoordinates (display, xevent.AnyEvent.window, RootWindow.Handle, + xevent.MotionEvent.x, xevent.MotionEvent.y, + out screen_x, out screen_y, out dummy); + + msg.lParam = (IntPtr) (screen_y << 16 | screen_x & 0xFFFF); + ht = (HitTest)NativeWindow.WndProc (hwnd.ClientWindow, Msg.WM_NCHITTEST, + IntPtr.Zero, msg.lParam).ToInt32 (); + NativeWindow.WndProc(hwnd.ClientWindow, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)ht); + + MousePosition.X = xevent.MotionEvent.x; + MousePosition.Y = xevent.MotionEvent.y; + } + + return true; + + case XEventName.EnterNotify: + if (!hwnd.Enabled) + goto ProcessNextMessage; + + if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) + goto ProcessNextMessage; + + msg.message = Msg.WM_MOUSE_ENTER; + HoverState.X = xevent.CrossingEvent.x; + HoverState.Y = xevent.CrossingEvent.y; + HoverState.Timer.Enabled = true; + HoverState.Window = xevent.CrossingEvent.window; + + return true; + + case XEventName.LeaveNotify: + if (!hwnd.Enabled) + goto ProcessNextMessage; + + if ((xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) || + (xevent.CrossingEvent.window != hwnd.ClientWindow)) + goto ProcessNextMessage; + + msg.message=Msg.WM_MOUSELEAVE; + HoverState.Timer.Enabled = false; + HoverState.Window = IntPtr.Zero; + + return true; + + case XEventName.ReparentNotify: + if (hwnd.parent == null) { // Toplevel + if ((xevent.ReparentEvent.parent != IntPtr.Zero) && (xevent.ReparentEvent.window == hwnd.WholeWindow)) { + // We need to adjust x/y + // This sucks ass, part 2 + // Every WM does the reparenting of toplevel windows different, so there's + // no standard way of getting our adjustment considering frames/decorations + // The code below is needed for metacity. KDE doesn't works just fine without this + int dummy_int; + IntPtr dummy_ptr; + int new_x; + int new_y; + int frame_left; + int frame_top; + + hwnd.Reparented = true; + + Xlib.XGetGeometry(display, XGetParent(hwnd.WholeWindow), + out dummy_ptr, out new_x, out new_y, + out dummy_int, out dummy_int, out dummy_int, out dummy_int); + hwnd.FrameExtents(out frame_left, out frame_top); + if ((frame_left != 0) && (frame_top != 0) && (new_x != frame_left) && (new_y != frame_top)) { + hwnd.x = new_x; + hwnd.y = new_y; + hwnd.whacky_wm = true; + } + + if (hwnd.opacity != 0xffffffff) { + IntPtr opacity; + + opacity = (IntPtr)(Int32)hwnd.opacity; + Xlib.XChangeProperty (display, XGetParent(hwnd.WholeWindow), + Atoms._NET_WM_WINDOW_OPACITY, Atoms.XA_CARDINAL, 32, + PropertyMode.Replace, ref opacity, 1); + } + SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, msg.wParam, msg.lParam); + goto ProcessNextMessage; + } else { + hwnd.Reparented = false; + goto ProcessNextMessage; + } + } + goto ProcessNextMessage; + + case XEventName.ConfigureNotify: + hwnd.HandleConfigureNotify (xevent); + goto ProcessNextMessage; + + case XEventName.MapNotify: { + if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas + hwnd.Mapped = true; + msg.message = Msg.WM_SHOWWINDOW; + msg.wParam = (IntPtr) 1; + // XXX we're missing the lParam.. + break; + } + goto ProcessNextMessage; + } + + case XEventName.UnmapNotify: { + if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas + hwnd.Mapped = false; + msg.message = Msg.WM_SHOWWINDOW; + msg.wParam = (IntPtr) 0; + // XXX we're missing the lParam.. + break; + } + goto ProcessNextMessage; + } + + case XEventName.FocusIn: + // We received focus. We use X11 focus only to know if the app window does or does not have focus + // We do not track the actual focussed window via it. Instead, this is done via FocusWindow internally + // Receiving focus means we've gotten activated and therefore we need to let the actual FocusWindow know + // about it having focus again + if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) + goto ProcessNextMessage; + + if (FocusWindow == null) { + Widget c = Widget.FromHandle (hwnd.ClientWindow); + if (c == null) + goto ProcessNextMessage; + Form form = c.FindForm (); + if (form == null) + goto ProcessNextMessage; + X11Hwnd new_active = (X11Hwnd)Hwnd.ObjectFromHandle (form.Handle); + if (ActiveWindow != new_active) { + ActiveWindow = new_active; + SendMessage (ActiveWindow.Handle, Msg.WM_ACTIVATE, (IntPtr) WindowActiveFlags.WA_ACTIVE, IntPtr.Zero); + } + goto ProcessNextMessage; + } + Keyboard.FocusIn(FocusWindow.Handle); + SendMessage(FocusWindow.Handle, Msg.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero); + goto ProcessNextMessage; + + case XEventName.FocusOut: + // Se the comment for our FocusIn handler + if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) + goto ProcessNextMessage; + + if (FocusWindow == null) + goto ProcessNextMessage; + + Keyboard.FocusOut(FocusWindow.Handle); + + while (Keyboard.ResetKeyState(FocusWindow.Handle, ref msg)) + SendMessage(FocusWindow.Handle, msg.message, msg.wParam, msg.lParam); + + SendMessage(FocusWindow.Handle, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero); + goto ProcessNextMessage; + + case XEventName.Expose: + if (!hwnd.Mapped) { + hwnd.PendingExpose = hwnd.PendingNCExpose = false; + continue; + } + + msg.hwnd = hwnd.Handle; + + if (client) { +#if DriverDebugExtra + Console.WriteLine("GetMessage(): Window {0:X} Exposed area {1},{2} {3}x{4}", + hwnd.client_window.ToInt32(), + xevent.ExposeEvent.x, xevent.ExposeEvent.y, + xevent.ExposeEvent.width, xevent.ExposeEvent.height); +#endif + msg.message = Msg.WM_PAINT; + } + else { + Graphics g; + + switch (hwnd.border_style) { + case FormBorderStyle.Fixed3D: + g = Graphics.FromHwnd(hwnd.WholeWindow); + WidgetPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), + Border3DStyle.Sunken); + g.Dispose(); + break; + + case FormBorderStyle.FixedSingle: + g = Graphics.FromHwnd(hwnd.WholeWindow); + WidgetPaint.DrawBorder(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), + Color.Black, ButtonBorderStyle.Solid); + g.Dispose(); + break; + } +#if DriverDebugExtra + Console.WriteLine("GetMessage(): Window {0:X} Exposed non-client area {1},{2} {3}x{4}", + hwnd.ClientWindow.ToInt32(), + xevent.ExposeEvent.x, xevent.ExposeEvent.y, + xevent.ExposeEvent.width, xevent.ExposeEvent.height); +#endif + + Rectangle rect = new Rectangle (xevent.ExposeEvent.x, xevent.ExposeEvent.y, + xevent.ExposeEvent.width, xevent.ExposeEvent.height); + Region region = new Region (rect); + IntPtr hrgn = region.GetHrgn (null); // Graphics object isn't needed + msg.message = Msg.WM_NCPAINT; + msg.wParam = hrgn == IntPtr.Zero ? (IntPtr)1 : hrgn; + msg.refobject = region; + } + + return true; + + case XEventName.DestroyNotify: + + // This is a bit tricky, we don't receive our own DestroyNotify, we only get those for our children + hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(xevent.DestroyWindowEvent.window); + + // We may get multiple for the same window, act only one the first (when Hwnd still knows about it) + if ((hwnd != null) && (hwnd.ClientWindow == xevent.DestroyWindowEvent.window)) { + CleanupCachedWindows (hwnd); + + #if DriverDebugDestroy + Console.WriteLine("Received X11 Destroy Notification for {0}", XplatUI.Window(hwnd.ClientWindow)); + #endif + + msg.hwnd = hwnd.ClientWindow; + msg.message=Msg.WM_DESTROY; + hwnd.Dispose(); + } + else + goto ProcessNextMessage; + + return true; + + case XEventName.ClientMessage: + if (Dnd.HandleClientMessage (ref xevent)) + goto ProcessNextMessage; + + if (xevent.ClientMessageEvent.message_type == Atoms.AsyncAtom) { + XplatUIDriverSupport.ExecuteClientMessage((GCHandle)xevent.ClientMessageEvent.ptr1); + goto ProcessNextMessage; + } + + if (xevent.ClientMessageEvent.message_type == HoverState.Atom) { + msg.message = Msg.WM_MOUSEHOVER; + msg.wParam = GetMousewParam(0); + msg.lParam = (IntPtr) (xevent.ClientMessageEvent.ptr1); + return true; + } + + if (xevent.ClientMessageEvent.message_type == Atoms.PostAtom) { + msg.hwnd = xevent.ClientMessageEvent.ptr1; + msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 (); + msg.wParam = xevent.ClientMessageEvent.ptr3; + msg.lParam = xevent.ClientMessageEvent.ptr4; + + // if we posted a WM_QUIT message, make sure we return + // false here as well. + if (msg.message == (Msg)Msg.WM_QUIT) + return false; + else + return true; + } + + if (xevent.ClientMessageEvent.message_type == Atoms._XEMBED) { +#if DriverDebugXEmbed + Console.WriteLine("GOT EMBED MESSAGE {0:X}, detail {1:X}", + xevent.ClientMessageEvent.ptr2.ToInt32(), xevent.ClientMessageEvent.ptr3.ToInt32()); +#endif + + if (xevent.ClientMessageEvent.ptr2.ToInt32() == (int)XEmbedMessage.EmbeddedNotify) { + XSizeHints hints = new XSizeHints(); + IntPtr dummy; + + Xlib.XGetWMNormalHints (display, hwnd.WholeWindow, ref hints, out dummy); + + hwnd.width = hints.max_width; + hwnd.height = hints.max_height; + hwnd.ClientRect = Rectangle.Empty; + SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + } + } + + if (xevent.ClientMessageEvent.message_type == Atoms.WM_PROTOCOLS) { + if (xevent.ClientMessageEvent.ptr1 == Atoms.WM_DELETE_WINDOW) { + msg.message = Msg.WM_CLOSE; + return true; + } + + // We should not get this, but I'll leave the code in case we need it in the future + if (xevent.ClientMessageEvent.ptr1 == Atoms.WM_TAKE_FOCUS) { + goto ProcessNextMessage; + } + } + + goto ProcessNextMessage; + + case XEventName.PropertyNotify: + // The Hwnd's themselves handle this + hwnd.PropertyChanged (xevent); + goto ProcessNextMessage; + } + } while (true); + + msg.hwnd= IntPtr.Zero; + msg.message = Msg.WM_ENTERIDLE; + return true; + } + + [MonoTODO("Implement filtering and PM_NOREMOVE")] + public bool PeekMessage (object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) + { + X11ThreadQueue queue = (X11ThreadQueue) queue_id; + bool pending; + + if ((flags & (uint)PeekMessageFlags.PM_REMOVE) == 0) { + throw new NotImplementedException("PeekMessage PM_NOREMOVE is not implemented yet"); // FIXME - Implement PM_NOREMOVE flag + } + + try { + queue.Lock (); + pending = false; + if (queue.CountUnlocked > 0) + pending = true; + } + catch { + return false; + } + finally { + queue.Unlock (); + } + + queue.CheckTimers (); + + if (!pending) + return false; + + return GetMessage(queue_id, ref msg, hWnd, wFilterMin, wFilterMax); + } + + public void DoEvents (X11ThreadQueue queue) + { + MSG msg = new MSG (); + + if (OverrideCursorHandle != IntPtr.Zero) + OverrideCursorHandle = IntPtr.Zero; + + queue.DispatchIdle = false; + + while (PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) { + TranslateMessage (ref msg); + DispatchMessage (ref msg); + } + + queue.DispatchIdle = true; + } + + // double buffering support + public void CreateOffscreenDrawable (IntPtr handle, + int width, int height, + out object offscreen_drawable) + { + IntPtr root_out; + int x_out, y_out, width_out, height_out, border_width_out, depth_out; + + Xlib.XGetGeometry (display, handle, + out root_out, + out x_out, out y_out, + out width_out, out height_out, + out border_width_out, out depth_out); + + IntPtr pixmap = Xlib.XCreatePixmap (display, handle, width, height, depth_out); + + offscreen_drawable = pixmap; + } + + public void DestroyOffscreenDrawable (object offscreen_drawable) + { + Xlib.XFreePixmap (display, (IntPtr)offscreen_drawable); + } + + public Graphics GetOffscreenGraphics (object offscreen_drawable) + { + return Graphics.FromHwnd ((IntPtr) offscreen_drawable); + } + + public void BlitFromOffscreen (IntPtr dest_handle, + Graphics dest_dc, + object offscreen_drawable, + Graphics offscreen_dc, + Rectangle r) + { + XGCValues gc_values; + IntPtr gc; + + gc_values = new XGCValues(); + + gc = Xlib.XCreateGC (display, dest_handle, IntPtr.Zero, ref gc_values); + + Xlib.XCopyArea (display, (IntPtr)offscreen_drawable, dest_handle, + gc, r.X, r.Y, r.Width, r.Height, r.X, r.Y); + + Xlib.XFreeGC (display, gc); + } + + + // reversible screen-level drawing + IntPtr GetReversibleScreenGC (Color backColor) + { + XGCValues gc_values; + IntPtr gc; + uint pixel; + + XColor xcolor = new XColor(); + xcolor.red = (ushort)(backColor.R * 257); + xcolor.green = (ushort)(backColor.G * 257); + xcolor.blue = (ushort)(backColor.B * 257); + Xlib.XAllocColor (display, DefaultColormap, ref xcolor); + pixel = (uint)xcolor.pixel.ToInt32(); + + + gc_values = new XGCValues(); + + gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors; + gc_values.foreground = (IntPtr)pixel; + + gc = Xlib.XCreateGC (display, RootWindow.Handle, new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCForeground)), ref gc_values); + Xlib.XSetForeground (display, gc, (UIntPtr)pixel); + Xlib.XSetFunction (display, gc, GXFunction.GXxor); + + return gc; + } + + public void DrawReversibleLine (Point start, Point end, Color backColor) + { + if (backColor.GetBrightness() < 0.5) + backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B); + + IntPtr gc = GetReversibleScreenGC (backColor); + + Xlib.XDrawLine (display, RootWindow.Handle, gc, start.X, start.Y, end.X, end.Y); + + Xlib.XFreeGC (display, gc); + } + + public void FillReversibleRectangle (Rectangle rectangle, Color backColor) + { + if (backColor.GetBrightness() < 0.5) + backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B); + + IntPtr gc = GetReversibleScreenGC (backColor); + + if (rectangle.Width < 0) { + rectangle.X += rectangle.Width; + rectangle.Width = -rectangle.Width; + } + if (rectangle.Height < 0) { + rectangle.Y += rectangle.Height; + rectangle.Height = -rectangle.Height; + } + + Xlib.XFillRectangle (display, RootWindow.Handle, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height); + + Xlib.XFreeGC (display, gc); + } + + public void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style) + { + if (backColor.GetBrightness() < 0.5) + backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B); + + IntPtr gc = GetReversibleScreenGC (backColor); + + if (rectangle.Width < 0) { + rectangle.X += rectangle.Width; + rectangle.Width = -rectangle.Width; + } + if (rectangle.Height < 0) { + rectangle.Y += rectangle.Height; + rectangle.Height = -rectangle.Height; + } + + int line_width = 1; + GCLineStyle line_style = GCLineStyle.LineSolid; + GCCapStyle cap_style = GCCapStyle.CapButt; + GCJoinStyle join_style = GCJoinStyle.JoinMiter; + + switch (style) { + case FrameStyle.Dashed: + line_style = GCLineStyle.LineOnOffDash; + break; + case FrameStyle.Thick: + line_width = 2; + break; + } + + Xlib.XSetLineAttributes (display, gc, line_width, line_style, cap_style, join_style); + + Xlib.XDrawRectangle (display, RootWindow.Handle, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height); + + Xlib.XFreeGC (display, gc); + } + } +} diff --git a/source/ShiftUI/Internal/X11Dnd.cs b/source/ShiftUI/Internal/X11Dnd.cs new file mode 100644 index 0000000..82f6568 --- /dev/null +++ b/source/ShiftUI/Internal/X11Dnd.cs @@ -0,0 +1,1421 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// +// NOTE: We have some tests in Test/ShiftUI/DragAndDropTest.cs, which I *highly* recommend +// to run after any change made here, since those tests are interactive, and thus are not part of +// the common tests. +// + + +using System; +using System.IO; +using System.Text; +using System.Drawing; +using System.Threading; +using System.Collections; +using System.Runtime.Serialization; +using System.Runtime.InteropServices; +using System.Runtime.Serialization.Formatters.Binary; + +namespace ShiftUI { + + internal class X11Dnd { + + private enum State { + Accepting, + Dragging + } + + private enum DragState { + None, + Beginning, + Dragging, + Entered + } + + private interface IDataConverter { + void GetData (X11Dnd dnd, IDataObject data, ref XEvent xevent); + void SetData (X11Dnd dnd, object data, ref XEvent xevent); + } + + private delegate void MimeConverter (IntPtr dsp, + IDataObject data, ref XEvent xevent); + + private class MimeHandler { + public string Name; + public string [] Aliases; + public IntPtr Type; + public IntPtr NonProtocol; + public IDataConverter Converter; + + public MimeHandler (string name, IDataConverter converter) : this (name, converter, name) + { + } + + public MimeHandler (string name, IDataConverter converter, params string [] aliases) + { + Name = name; + Converter = converter; + Aliases = aliases; + } + + public override string ToString () + { + return "MimeHandler {" + Name + "}"; + } + } + + private MimeHandler [] MimeHandlers = { +// new MimeHandler ("WCF_DIB"), +// new MimeHandler ("image/gif", new MimeConverter (ImageConverter)), +// new MimeHandler ("text/rtf", new MimeConverter (RtfConverter)), +// new MimeHandler ("text/richtext", new MimeConverter (RtfConverter)), + + new MimeHandler ("text/plain", new TextConverter ()), + new MimeHandler ("text/plain", new TextConverter (), "System.String", DataFormats.Text), + new MimeHandler ("text/html", new HtmlConverter (), DataFormats.Html), + new MimeHandler ("text/uri-list", new UriListConverter (), DataFormats.FileDrop), + new MimeHandler ("application/x-mono-serialized-object", + new SerializedObjectConverter ()) + }; + + private class SerializedObjectConverter : IDataConverter { + + public void GetData (X11Dnd dnd, IDataObject data, ref XEvent xevent) + { + MemoryStream stream = dnd.GetData (ref xevent); + BinaryFormatter bf = new BinaryFormatter (); + + if (stream.Length == 0) + return; + + stream.Seek (0, 0); + object obj = bf.Deserialize (stream); + data.SetData (obj); + } + + public void SetData (X11Dnd dnd, object data, ref XEvent xevent) + { + if (data == null) + return; + + MemoryStream stream = new MemoryStream (); + BinaryFormatter bf = new BinaryFormatter (); + + bf.Serialize (stream, data); + + IntPtr buffer = Marshal.AllocHGlobal ((int) stream.Length); + stream.Seek (0, 0); + + for (int i = 0; i < stream.Length; i++) { + Marshal.WriteByte (buffer, i, (byte) stream.ReadByte ()); + } + + dnd.SetProperty (ref xevent, buffer, (int) stream.Length); + } + } + + private class HtmlConverter : IDataConverter { + + public void GetData (X11Dnd dnd, IDataObject data, ref XEvent xevent) + { + string text = dnd.GetText (ref xevent, false); + if (text == null) + return; + data.SetData (DataFormats.Text, text); + data.SetData (DataFormats.UnicodeText, text); + } + + public void SetData (X11Dnd dnd, object data, ref XEvent xevent) + { + IntPtr buffer; + int len; + string str = data as string; + + if (str == null) + return; + + if (xevent.SelectionRequestEvent.target == (IntPtr)Atom.XA_STRING) { + byte [] bytes = Encoding.ASCII.GetBytes (str); + buffer = Marshal.AllocHGlobal (bytes.Length); + len = bytes.Length; + for (int i = 0; i < len; i++) + Marshal.WriteByte (buffer, i, bytes [i]); + } else { + buffer = Marshal.StringToHGlobalAnsi (str); + len = 0; + while (Marshal.ReadByte (buffer, len) != 0) + len++; + } + + dnd.SetProperty (ref xevent, buffer, len); + + Marshal.FreeHGlobal (buffer); + } + } + + private class TextConverter : IDataConverter { + + public void GetData (X11Dnd dnd, IDataObject data, ref XEvent xevent) + { + string text = dnd.GetText (ref xevent, true); + if (text == null) + return; + data.SetData (DataFormats.Text, text); + data.SetData (DataFormats.UnicodeText, text); + } + + public void SetData (X11Dnd dnd, object data, ref XEvent xevent) + { + IntPtr buffer; + int len; + string str = data as string; + + if (str == null) { + IDataObject dobj = data as IDataObject; + if (dobj == null) + return; + str = (string) dobj.GetData ("System.String", true); + } + + if (xevent.SelectionRequestEvent.target == (IntPtr)Atom.XA_STRING) { + byte [] bytes = Encoding.ASCII.GetBytes (str); + buffer = Marshal.AllocHGlobal (bytes.Length); + len = bytes.Length; + for (int i = 0; i < len; i++) + Marshal.WriteByte (buffer, i, bytes [i]); + } else { + buffer = Marshal.StringToHGlobalAnsi (str); + len = 0; + while (Marshal.ReadByte (buffer, len) != 0) + len++; + } + + dnd.SetProperty (ref xevent, buffer, len); + + Marshal.FreeHGlobal (buffer); + } + } + + private class UriListConverter : IDataConverter { + + public void GetData (X11Dnd dnd, IDataObject data, ref XEvent xevent) + { + string text = dnd.GetText (ref xevent, false); + if (text == null) + return; + + // TODO: Do this in a loop instead of just splitting + ArrayList uri_list = new ArrayList (); + string [] lines = text.Split (new char [] { '\r', '\n' }); + foreach (string line in lines) { + // # is a comment line (see RFC 2483) + if (line.StartsWith ("#")) + continue; + try { + Uri uri = new Uri (line); + uri_list.Add (uri.LocalPath); + } catch { } + } + + string [] l = (string []) uri_list.ToArray (typeof (string)); + if (l.Length < 1) + return; + data.SetData (DataFormats.FileDrop, l); + data.SetData ("FileName", l [0]); + data.SetData ("FileNameW", l [0]); + } + + public void SetData (X11Dnd dnd, object data, ref XEvent xevent) + { + string [] uri_list = data as string []; + + if (uri_list == null) { + IDataObject dobj = data as IDataObject; + if (dobj == null) + return; + uri_list = dobj.GetData (DataFormats.FileDrop, true) as string []; + } + + if (uri_list == null) + return; + + StringBuilder res = new StringBuilder (); + foreach (string uri_str in uri_list) { + Uri uri = new Uri (uri_str); + res.Append (uri.ToString ()); + res.Append ("\r\n"); + } + + IntPtr buffer = Marshal.StringToHGlobalAnsi ((string) res.ToString ()); + int len = 0; + while (Marshal.ReadByte (buffer, len) != 0) + len++; + + dnd.SetProperty (ref xevent, buffer, len); + } + } + + private class DragData { + public IntPtr Window; + public DragState State; + public object Data; + public IntPtr Action; + public IntPtr [] SupportedTypes; + public MouseButtons MouseState; + public DragDropEffects AllowedEffects; + public Point CurMousePos; + + public IntPtr LastWindow; + public IntPtr LastTopLevel; + + public bool WillAccept; + + public void Reset () + { + State = DragState.None; + Data = null; + SupportedTypes = null; + WillAccept = false; + } + } + + // This version seems to be the most common + private static readonly IntPtr [] XdndVersion = new IntPtr [] { new IntPtr (4) }; + + private IntPtr display; + private DragData drag_data; + + private IntPtr XdndAware; + private IntPtr XdndSelection; + private IntPtr XdndEnter; + private IntPtr XdndLeave; + private IntPtr XdndPosition; + private IntPtr XdndDrop; + private IntPtr XdndFinished; + private IntPtr XdndStatus; + private IntPtr XdndTypeList; + private IntPtr XdndActionCopy; + private IntPtr XdndActionMove; + private IntPtr XdndActionLink; + //private IntPtr XdndActionPrivate; + private IntPtr XdndActionList; + //private IntPtr XdndActionDescription; + //private IntPtr XdndActionAsk; + + //private State state; + + private int converts_pending; + private bool position_recieved; + private bool status_sent; + private IntPtr target; + private IntPtr source; + private IntPtr toplevel; + private IDataObject data; + + private Widget Widget; + private int pos_x, pos_y; + private DragDropEffects allowed; + private DragEventArgs drag_event; + + private Cursor CursorNo; + private Cursor CursorCopy; + private Cursor CursorMove; + private Cursor CursorLink; + // check out the TODO below + //private IntPtr CurrentCursorHandle; + + private bool tracking = false; + private bool dropped = false; + private int motion_poll; + //private X11Keyboard keyboard; + + public X11Dnd (IntPtr display, X11Keyboard keyboard) + { + this.display = display; + //this.keyboard = keyboard; + + Init (); + } + + public bool InDrag() + { + if (drag_data == null) + return false; + return drag_data.State != DragState.None; + } + + public void SetAllowDrop (Hwnd hwnd, bool allow) + { + int[] atoms; + + if (hwnd.allow_drop == allow) + return; + + atoms = new int[XdndVersion.Length]; + for (int i = 0; i < XdndVersion.Length; i++) { + atoms[i] = XdndVersion[i].ToInt32(); + } + + XplatUIX11.XChangeProperty (display, hwnd.whole_window, XdndAware, + (IntPtr) Atom.XA_ATOM, 32, + PropertyMode.Replace, atoms, allow ? 1 : 0); + hwnd.allow_drop = allow; + } + + public DragDropEffects StartDrag (IntPtr handle, object data, + DragDropEffects allowed_effects) + { + drag_data = new DragData (); + drag_data.Window = handle; + drag_data.State = DragState.Beginning; + drag_data.MouseState = XplatUIX11.MouseState; + drag_data.Data = data; + drag_data.SupportedTypes = DetermineSupportedTypes (data); + drag_data.AllowedEffects = allowed_effects; + drag_data.Action = ActionFromEffect (allowed_effects); + + if (CursorNo == null) { + // Make sure the cursors are created + CursorNo = new Cursor (Properties.Resources.DnDNo); + CursorCopy = new Cursor (Properties.Resources.DnDCopy); + CursorMove = new Cursor (Properties.Resources.DnDMove); + CursorLink = new Cursor (Properties.Resources.DnDLink); + } + + drag_data.LastTopLevel = IntPtr.Zero; + Widget = null; + + ShiftUI.MSG msg = new MSG(); + object queue_id = XplatUI.StartLoop (Thread.CurrentThread); + + Timer timer = new Timer (); + timer.Tick += new EventHandler (DndTickHandler); + timer.Interval = 100; + + int suc; + drag_data.State = DragState.Dragging; + + suc = XplatUIX11.XSetSelectionOwner (display, XdndSelection, + drag_data.Window, IntPtr.Zero); + + if (suc == 0) { + Console.Error.WriteLine ("Could not take ownership of XdndSelection aborting drag."); + drag_data.Reset (); + return DragDropEffects.None; + } + + drag_data.State = DragState.Dragging; + drag_data.CurMousePos = new Point (); + source = toplevel = target = IntPtr.Zero; + dropped = false; + tracking = true; + motion_poll = -1; + timer.Start (); + + // Send Enter to the window initializing the dnd operation - which initializes the data + SendEnter (drag_data.Window, drag_data.Window, drag_data.SupportedTypes); + drag_data.LastTopLevel = toplevel; + + while (tracking && XplatUI.GetMessage (queue_id, ref msg, IntPtr.Zero, 0, 0)) { + + if (msg.message >= Msg.WM_KEYFIRST && msg.message <= Msg.WM_KEYLAST) { + HandleKeyMessage (msg); + } else { + switch (msg.message) { + case Msg.WM_LBUTTONUP: + case Msg.WM_RBUTTONUP: + case Msg.WM_MBUTTONUP: + if (msg.message == Msg.WM_LBUTTONDOWN && drag_data.MouseState != MouseButtons.Left) + break;; + if (msg.message == Msg.WM_RBUTTONDOWN && drag_data.MouseState != MouseButtons.Right) + break; + if (msg.message == Msg.WM_MBUTTONDOWN && drag_data.MouseState != MouseButtons.Middle) + break; + + HandleButtonUpMsg (); + + // We don't want to dispatch button up neither (Match .Net) + // Thus we have to remove capture by ourselves + RemoveCapture (msg.hwnd); + continue; + case Msg.WM_MOUSEMOVE: + motion_poll = 0; + + drag_data.CurMousePos.X = Widget.LowOrder ((int) msg.lParam.ToInt32 ()); + drag_data.CurMousePos.Y = Widget.HighOrder ((int) msg.lParam.ToInt32 ()); + + HandleMouseOver (); + // We don't want to dispatch mouse move + continue; + } + + XplatUI.DispatchMessage (ref msg); + } + } + + timer.Stop (); + + // If the target is a mwf Widget, return until DragEnter/DragLeave has been fired, + // which means the respective -already sent- dnd ClientMessages have been received and handled. + if (Widget != null) + Application.DoEvents (); + + if (!dropped) + return DragDropEffects.None; + if (drag_event != null) + return drag_event.Effect; + + // Fallback. + return DragDropEffects.None; + } + + private void DndTickHandler (object sender, EventArgs e) + { + // This is to make sure we don't get stuck in a loop if another + // app doesn't finish the DND operation + if (dropped) { + Timer t = (Timer) sender; + if (t.Interval == 500) + tracking = false; + else + t.Interval = 500; + } + + + // If motion_poll is -1, there hasn't been motion at all, so don't simulate motion yet. + // Otherwise if more than 100 milliseconds have lapsed, we assume the pointer is not + // in motion anymore, and we simulate the mouse over operation, like .Net does. + if (motion_poll > 1) + HandleMouseOver (); + else if (motion_poll > -1) + motion_poll++; + } + + // This routines helps us to have a DndEnter/DndLeave fallback when there wasn't any mouse movement + // as .Net does + private void DefaultEnterLeave (object user_data) + { + IntPtr toplevel, window; + int x_root, y_root; + + // The window generating the operation could be a different than the one under pointer + GetWindowsUnderPointer (out window, out toplevel, out x_root, out y_root); + Widget source_Widget = Widget.FromHandle (window); + if (source_Widget == null || !source_Widget.AllowDrop) + return; + + // `data' and other members are already available + Point pos = Widget.MousePosition; + DragEventArgs drag_args = new DragEventArgs (data, 0, pos.X, pos.Y, drag_data.AllowedEffects, DragDropEffects.None); + + source_Widget.DndEnter (drag_args); + if ((drag_args.Effect & drag_data.AllowedEffects) != 0) + source_Widget.DndDrop (drag_args); + else + source_Widget.DndLeave (EventArgs.Empty); + } + + public void HandleButtonUpMsg () + { + if (drag_data.State == DragState.Beginning) { + //state = State.Accepting; + } else if (drag_data.State != DragState.None) { + + if (drag_data.WillAccept) { + + if (QueryContinue (false, DragAction.Drop)) + return; + } else { + + if (QueryContinue (false, DragAction.Cancel)) + return; + + // fallback if no movement was detected, as .net does. + if (motion_poll == -1) + DefaultEnterLeave (drag_data.Data); + } + + drag_data.State = DragState.None; + // WE can't reset the drag data yet as it is still + // most likely going to be used by the SelectionRequest + // handlers + } + + return; + } + + private void RemoveCapture (IntPtr handle) + { + Widget c = MwfWindow (handle); + if (c.InternalCapture) + c.InternalCapture = false; + } + + public bool HandleMouseOver () + { + IntPtr toplevel, window; + int x_root, y_root; + + GetWindowsUnderPointer (out window, out toplevel, out x_root, out y_root); + + if (window != drag_data.LastWindow && drag_data.State == DragState.Entered) { + drag_data.State = DragState.Dragging; + + // TODO: Send a Leave if this is an MWF window + + if (toplevel != drag_data.LastTopLevel) + SendLeave (drag_data.LastTopLevel, toplevel); + } + + drag_data.State = DragState.Entered; + if (toplevel != drag_data.LastTopLevel) { + // Entering a new toplevel window + SendEnter (toplevel, drag_data.Window, drag_data.SupportedTypes); + } else { + // Already in a toplevel window, so send a position + SendPosition (toplevel, drag_data.Window, + drag_data.Action, + x_root, y_root, + IntPtr.Zero); + } + + drag_data.LastTopLevel = toplevel; + drag_data.LastWindow = window; + return true; + } + + void GetWindowsUnderPointer (out IntPtr window, out IntPtr toplevel, out int x_root, out int y_root) + { + toplevel = IntPtr.Zero; + window = XplatUIX11.RootWindowHandle; + + IntPtr root, child; + bool dnd_aware = false; + int x_temp, y_temp; + int mask_return; + int x = x_root = drag_data.CurMousePos.X; + int y = y_root = drag_data.CurMousePos.Y; + + while (XplatUIX11.XQueryPointer (display, window, out root, out child, + out x_temp, out y_temp, out x, out y, out mask_return)) { + + if (!dnd_aware) { + dnd_aware = IsWindowDndAware (window); + if (dnd_aware) { + toplevel = window; + x_root = x_temp; + y_root = y_temp; + } + } + + if (child == IntPtr.Zero) + break; + + window = child; + } + } + + public void HandleKeyMessage (MSG msg) + { + if (VirtualKeys.VK_ESCAPE == (VirtualKeys) msg.wParam.ToInt32()) { + QueryContinue (true, DragAction.Cancel); + } + } + + // return true if the event is handled here + public bool HandleClientMessage (ref XEvent xevent) + { + // most common so we check it first + if (xevent.ClientMessageEvent.message_type == XdndPosition) + return Accepting_HandlePositionEvent (ref xevent); + if (xevent.ClientMessageEvent.message_type == XdndEnter) + return Accepting_HandleEnterEvent (ref xevent); + if (xevent.ClientMessageEvent.message_type == XdndDrop) + return Accepting_HandleDropEvent (ref xevent); + if (xevent.ClientMessageEvent.message_type == XdndLeave) + return Accepting_HandleLeaveEvent (ref xevent); + if (xevent.ClientMessageEvent.message_type == XdndStatus) + return HandleStatusEvent (ref xevent); + if (xevent.ClientMessageEvent.message_type == XdndFinished) + return HandleFinishedEvent (ref xevent); + + return false; + } + + public bool HandleSelectionNotifyEvent (ref XEvent xevent) + { + MimeHandler handler = FindHandler ((IntPtr) xevent.SelectionEvent.target); + if (handler == null) + return false; + if (data == null) + data = new DataObject (); + + handler.Converter.GetData (this, data, ref xevent); + + converts_pending--; + if (converts_pending <= 0 && position_recieved) { + drag_event = new DragEventArgs (data, 0, pos_x, pos_y, + allowed, DragDropEffects.None); + Widget.DndEnter (drag_event); + SendStatus (source, drag_event.Effect); + status_sent = true; + } + return true; + } + + public bool HandleSelectionRequestEvent (ref XEvent xevent) + { + if (xevent.SelectionRequestEvent.selection != XdndSelection) + return false; + + MimeHandler handler = FindHandler (xevent.SelectionRequestEvent.target); + if (handler == null) + return false; + + handler.Converter.SetData (this, drag_data.Data, ref xevent); + + return true; + } + + private bool QueryContinue (bool escape, DragAction action) + { + QueryContinueDragEventArgs qce = new QueryContinueDragEventArgs ((int) XplatUI.State.ModifierKeys, + escape, action); + + Widget c = MwfWindow (source); + + if (c == null) { + tracking = false; + return false; + } + + c.DndContinueDrag (qce); + + switch (qce.Action) { + case DragAction.Continue: + return true; + case DragAction.Drop: + SendDrop (drag_data.LastTopLevel, source, IntPtr.Zero); + tracking = false; + return true; + case DragAction.Cancel: + drag_data.Reset (); + c.InternalCapture = false; + break; + } + + SendLeave (drag_data.LastTopLevel, toplevel); + + RestoreDefaultCursor (); + tracking = false; + return false; + } + + private void RestoreDefaultCursor () + { + // Releasing the mouse buttons should automatically restore the default cursor, + // but canceling the operation using QueryContinue should restore it even if the + // mouse buttons are not released yet. + XplatUIX11.XChangeActivePointerGrab (display, + EventMask.ButtonMotionMask | + EventMask.PointerMotionMask | + EventMask.ButtonPressMask | + EventMask.ButtonReleaseMask, + Cursors.Default.Handle, IntPtr.Zero); + + } + + private void GiveFeedback (IntPtr action) + { + GiveFeedbackEventArgs gfe = new GiveFeedbackEventArgs (EffectFromAction (drag_data.Action), true); + + Widget c = MwfWindow (source); + c.DndFeedback (gfe); + + if (gfe.UseDefaultCursors) { + Cursor cursor = CursorNo; + if (drag_data.WillAccept) { + // Same order as on MS + if (action == XdndActionCopy) + cursor = CursorCopy; + else if (action == XdndActionLink) + cursor = CursorLink; + else if (action == XdndActionMove) + cursor = CursorMove; + } + // TODO: Try not to set the cursor so much + //if (cursor.Handle != CurrentCursorHandle) { + XplatUIX11.XChangeActivePointerGrab (display, + EventMask.ButtonMotionMask | + EventMask.PointerMotionMask | + EventMask.ButtonPressMask | + EventMask.ButtonReleaseMask, + cursor.Handle, IntPtr.Zero); + //CurrentCursorHandle = cursor.Handle; + //} + } + } + + private void SetProperty (ref XEvent xevent, IntPtr data, int length) + { + XEvent sel = new XEvent(); + sel.SelectionEvent.type = XEventName.SelectionNotify; + sel.SelectionEvent.send_event = true; + sel.SelectionEvent.display = display; + sel.SelectionEvent.selection = xevent.SelectionRequestEvent.selection; + sel.SelectionEvent.target = xevent.SelectionRequestEvent.target; + sel.SelectionEvent.requestor = xevent.SelectionRequestEvent.requestor; + sel.SelectionEvent.time = xevent.SelectionRequestEvent.time; + sel.SelectionEvent.property = IntPtr.Zero; + + XplatUIX11.XChangeProperty (display, xevent.SelectionRequestEvent.requestor, + xevent.SelectionRequestEvent.property, + xevent.SelectionRequestEvent.target, + 8, PropertyMode.Replace, data, length); + sel.SelectionEvent.property = xevent.SelectionRequestEvent.property; + + XplatUIX11.XSendEvent (display, xevent.SelectionRequestEvent.requestor, false, + (IntPtr)EventMask.NoEventMask, ref sel); + return; + } + + private void Reset () + { + ResetSourceData (); + ResetTargetData (); + } + + private void ResetSourceData () + { + converts_pending = 0; + data = null; + } + + private void ResetTargetData () + { + position_recieved = false; + status_sent = false; + } + + private bool Accepting_HandleEnterEvent (ref XEvent xevent) + { + Reset (); + + source = xevent.ClientMessageEvent.ptr1; + toplevel = xevent.AnyEvent.window; + target = IntPtr.Zero; + + ConvertData (ref xevent); + + return true; + } + + private bool Accepting_HandlePositionEvent (ref XEvent xevent) + { + pos_x = (int) xevent.ClientMessageEvent.ptr3 >> 16; + pos_y = (int) xevent.ClientMessageEvent.ptr3 & 0xFFFF; + + // Copy is implicitly allowed + Widget source_Widget = MwfWindow (source); + if (source_Widget == null) + allowed = EffectsFromX11Source (source, xevent.ClientMessageEvent.ptr5) | DragDropEffects.Copy; + else + allowed = drag_data.AllowedEffects; + + IntPtr parent, child, new_child, last_drop_child; + parent = XplatUIX11.XRootWindow (display, 0); + child = toplevel; + last_drop_child = IntPtr.Zero; + while (true) { + int xd, yd; + new_child = IntPtr.Zero; + + if (!XplatUIX11.XTranslateCoordinates (display, + parent, child, pos_x, pos_y, + out xd, out yd, out new_child)) + break; + if (new_child == IntPtr.Zero) + break; + child = new_child; + + Hwnd h = Hwnd.ObjectFromHandle (child); + if (h != null) { + Widget d = Widget.FromHandle (h.client_window); + if (d != null && d.allow_drop) + last_drop_child = child; + } + } + + if (last_drop_child != IntPtr.Zero) + child = last_drop_child; + + if (target != child) { + // We have moved into a new Widget + // or into a Widget for the first time + Finish (); + } + target = child; + Hwnd hwnd = Hwnd.ObjectFromHandle (target); + if (hwnd == null) + return true; + + Widget c = Widget.FromHandle (hwnd.client_window); + + if (c == null) + return true; + if (!c.allow_drop) { + SendStatus (source, DragDropEffects.None); + Finish (); + return true; + } + + Widget = c; + position_recieved = true; + + if (converts_pending > 0) + return true; + + if (!status_sent) { + drag_event = new DragEventArgs (data, 0, pos_x, pos_y, + allowed, DragDropEffects.None); + Widget.DndEnter (drag_event); + + SendStatus (source, drag_event.Effect); + status_sent = true; + } else { + drag_event.x = pos_x; + drag_event.y = pos_y; + Widget.DndOver (drag_event); + + SendStatus (source, drag_event.Effect); + } + + return true; + } + + private void Finish () + { + if (Widget != null) { + if (drag_event == null) { + if (data == null) + data = new DataObject (); + drag_event = new DragEventArgs (data, + 0, pos_x, pos_y, + allowed, DragDropEffects.None); + } + Widget.DndLeave (drag_event); + Widget = null; + } + ResetTargetData (); + } + + private bool Accepting_HandleDropEvent (ref XEvent xevent) + { + if (Widget != null && drag_event != null) { + drag_event = new DragEventArgs (data, + 0, pos_x, pos_y, + allowed, drag_event.Effect); + Widget.DndDrop (drag_event); + } + SendFinished (); + return true; + } + + private bool Accepting_HandleLeaveEvent (ref XEvent xevent) + { + if (Widget != null && drag_event != null) + Widget.DndLeave (drag_event); + // Reset (); + return true; + } + + private bool HandleStatusEvent (ref XEvent xevent) + { + if (drag_data != null && drag_data.State == DragState.Entered) { + + if (!QueryContinue (false, DragAction.Continue)) + return true; + + drag_data.WillAccept = ((int) xevent.ClientMessageEvent.ptr2 & 0x1) != 0; + + GiveFeedback (xevent.ClientMessageEvent.ptr5); + } + return true; + } + + private bool HandleFinishedEvent (ref XEvent xevent) + { + return true; + } + + private DragDropEffects EffectsFromX11Source (IntPtr source, IntPtr action_atom) + { + DragDropEffects allowed = DragDropEffects.None; + IntPtr type, count, remaining, data = IntPtr.Zero; + int format; + + XplatUIX11.XGetWindowProperty (display, source, XdndActionList, + IntPtr.Zero, new IntPtr (32), false, (IntPtr) Atom.AnyPropertyType, + out type, out format, out count, out remaining, ref data); + + int intptr_size = Marshal.SizeOf (typeof (IntPtr)); + for (int i = 0; i < count.ToInt32 (); i++) { + IntPtr current_atom = Marshal.ReadIntPtr (data, i * intptr_size); + allowed |= EffectFromAction (current_atom); + } + + // if source is not providing the action list, use the + // default action passed in the x11 dnd position message + if (allowed == DragDropEffects.None) + allowed = EffectFromAction (action_atom); + + return allowed; + } + + private DragDropEffects EffectFromAction (IntPtr action) + { + if (action == XdndActionCopy) + return DragDropEffects.Copy; + else if (action == XdndActionMove) + return DragDropEffects.Move; + if (action == XdndActionLink) + return DragDropEffects.Link; + + return DragDropEffects.None; + } + + private IntPtr ActionFromEffect (DragDropEffects effect) + { + IntPtr action = IntPtr.Zero; + + // We can't OR together actions on XDND so sadly the primary + // is the only one shown here + if ((effect & DragDropEffects.Copy) != 0) + action = XdndActionCopy; + else if ((effect & DragDropEffects.Move) != 0) + action = XdndActionMove; + else if ((effect & DragDropEffects.Link) != 0) + action = XdndActionLink; + return action; + } + + private bool ConvertData (ref XEvent xevent) + { + bool match = false; + + Widget mwfWidget = MwfWindow (source); + + /* To take advantage of the mwfWidget, we have to be sure + that the dnd operation is still happening (since messages are asynchronous) */ + if (mwfWidget != null && drag_data != null) { + if (!tracking) + return false; + + IDataObject dragged = drag_data.Data as IDataObject; + if (dragged != null) { + data = dragged; + } else { + if (data == null) + data = new DataObject (); + SetDataWithFormats (drag_data.Data); + } + return true; + } + + foreach (IntPtr atom in SourceSupportedList (ref xevent)) { + MimeHandler handler = FindHandler (atom); + if (handler == null) + continue; + XplatUIX11.XConvertSelection (display, XdndSelection, handler.Type, + handler.NonProtocol, toplevel, IntPtr.Zero /* CurrentTime */); + converts_pending++; + match = true; + } + return match; + } + + private void SetDataWithFormats (object value) + { + if (value is string) { + data.SetData (DataFormats.Text, value); + data.SetData (DataFormats.UnicodeText, value); + } + + data.SetData (value); + } + + private MimeHandler FindHandler (IntPtr atom) + { + if (atom == IntPtr.Zero) + return null; + foreach (MimeHandler handler in MimeHandlers) { + if (handler.Type == atom) + return handler; + } + return null; + } + + private MimeHandler FindHandler (string name) + { + foreach (MimeHandler handler in MimeHandlers) { + foreach (string alias in handler.Aliases) { + if (alias == name) + return handler; + } + } + return null; + } + + private void SendStatus (IntPtr source, DragDropEffects effect) + { + XEvent xevent = new XEvent (); + + xevent.AnyEvent.type = XEventName.ClientMessage; + xevent.AnyEvent.display = display; + xevent.ClientMessageEvent.window = source; + xevent.ClientMessageEvent.message_type = XdndStatus; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = toplevel; + if (effect != DragDropEffects.None && (effect & allowed) != 0) + xevent.ClientMessageEvent.ptr2 = (IntPtr) 1; + + xevent.ClientMessageEvent.ptr5 = ActionFromEffect (effect); + XplatUIX11.XSendEvent (display, source, false, IntPtr.Zero, ref xevent); + } + + private void SendEnter (IntPtr handle, IntPtr from, IntPtr [] supported) + { + XEvent xevent = new XEvent (); + + xevent.AnyEvent.type = XEventName.ClientMessage; + xevent.AnyEvent.display = display; + xevent.ClientMessageEvent.window = handle; + xevent.ClientMessageEvent.message_type = XdndEnter; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = from; + + // (int) xevent.ClientMessageEvent.ptr2 & 0x1) + // int ptr2 = 0x1; + // xevent.ClientMessageEvent.ptr2 = (IntPtr) ptr2; + // (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~(0xFF << 24)) | ((v) << 24) + xevent.ClientMessageEvent.ptr2 = (IntPtr) ((long)XdndVersion [0] << 24); + + if (supported.Length > 0) + xevent.ClientMessageEvent.ptr3 = supported [0]; + if (supported.Length > 1) + xevent.ClientMessageEvent.ptr4 = supported [1]; + if (supported.Length > 2) + xevent.ClientMessageEvent.ptr5 = supported [2]; + + XplatUIX11.XSendEvent (display, handle, false, IntPtr.Zero, ref xevent); + } + + private void SendDrop (IntPtr handle, IntPtr from, IntPtr time) + { + XEvent xevent = new XEvent (); + + xevent.AnyEvent.type = XEventName.ClientMessage; + xevent.AnyEvent.display = display; + xevent.ClientMessageEvent.window = handle; + xevent.ClientMessageEvent.message_type = XdndDrop; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = from; + xevent.ClientMessageEvent.ptr3 = time; + + XplatUIX11.XSendEvent (display, handle, false, IntPtr.Zero, ref xevent); + dropped = true; + } + + private void SendPosition (IntPtr handle, IntPtr from, IntPtr action, int x, int y, IntPtr time) + { + XEvent xevent = new XEvent (); + + xevent.AnyEvent.type = XEventName.ClientMessage; + xevent.AnyEvent.display = display; + xevent.ClientMessageEvent.window = handle; + xevent.ClientMessageEvent.message_type = XdndPosition; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = from; + xevent.ClientMessageEvent.ptr3 = (IntPtr) ((x << 16) | (y & 0xFFFF)); + xevent.ClientMessageEvent.ptr4 = time; + xevent.ClientMessageEvent.ptr5 = action; + + XplatUIX11.XSendEvent (display, handle, false, IntPtr.Zero, ref xevent); + } + + private void SendLeave (IntPtr handle, IntPtr from) + { + XEvent xevent = new XEvent (); + + xevent.AnyEvent.type = XEventName.ClientMessage; + xevent.AnyEvent.display = display; + xevent.ClientMessageEvent.window = handle; + xevent.ClientMessageEvent.message_type = XdndLeave; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = from; + + XplatUIX11.XSendEvent (display, handle, false, IntPtr.Zero, ref xevent); + } + + private void SendFinished () + { + XEvent xevent = new XEvent (); + + xevent.AnyEvent.type = XEventName.ClientMessage; + xevent.AnyEvent.display = display; + xevent.ClientMessageEvent.window = source; + xevent.ClientMessageEvent.message_type = XdndFinished; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = toplevel; + + XplatUIX11.XSendEvent (display, source, false, IntPtr.Zero, ref xevent); + } + + // There is a somewhat decent amount of overhead + // involved in setting up dnd so we do it lazily + // as a lot of applications do not even use it. + private void Init () + { + XdndAware = XplatUIX11.XInternAtom (display, "XdndAware", false); + XdndEnter = XplatUIX11.XInternAtom (display, "XdndEnter", false); + XdndLeave = XplatUIX11.XInternAtom (display, "XdndLeave", false); + XdndPosition = XplatUIX11.XInternAtom (display, "XdndPosition", false); + XdndStatus = XplatUIX11.XInternAtom (display, "XdndStatus", false); + XdndDrop = XplatUIX11.XInternAtom (display, "XdndDrop", false); + XdndSelection = XplatUIX11.XInternAtom (display, "XdndSelection", false); + XdndFinished = XplatUIX11.XInternAtom (display, "XdndFinished", false); + XdndTypeList = XplatUIX11.XInternAtom (display, "XdndTypeList", false); + XdndActionCopy = XplatUIX11.XInternAtom (display, "XdndActionCopy", false); + XdndActionMove = XplatUIX11.XInternAtom (display, "XdndActionMove", false); + XdndActionLink = XplatUIX11.XInternAtom (display, "XdndActionLink", false); + //XdndActionPrivate = XplatUIX11.XInternAtom (display, "XdndActionPrivate", false); + XdndActionList = XplatUIX11.XInternAtom (display, "XdndActionList", false); + //XdndActionDescription = XplatUIX11.XInternAtom (display, "XdndActionDescription", false); + //XdndActionAsk = XplatUIX11.XInternAtom (display, "XdndActionAsk", false); + + foreach (MimeHandler handler in MimeHandlers) { + handler.Type = XplatUIX11.XInternAtom (display, handler.Name, false); + handler.NonProtocol = XplatUIX11.XInternAtom (display, + String.Concat ("MWFNonP+", handler.Name), false); + } + + } + + private IntPtr [] SourceSupportedList (ref XEvent xevent) + { + IntPtr [] res; + + + if (((int) xevent.ClientMessageEvent.ptr2 & 0x1) == 0) { + res = new IntPtr [3]; + res [0] = xevent.ClientMessageEvent.ptr3; + res [1] = xevent.ClientMessageEvent.ptr4; + res [2] = xevent.ClientMessageEvent.ptr5; + } else { + IntPtr type; + int format; + IntPtr count; + IntPtr remaining; + IntPtr data = IntPtr.Zero; + + XplatUIX11.XGetWindowProperty (display, source, XdndTypeList, + IntPtr.Zero, new IntPtr(32), false, (IntPtr) Atom.XA_ATOM, + out type, out format, out count, + out remaining, ref data); + + res = new IntPtr [count.ToInt32()]; + for (int i = 0; i < count.ToInt32(); i++) { + res [i] = (IntPtr) Marshal.ReadInt32 (data, i * + Marshal.SizeOf (typeof (int))); + } + + XplatUIX11.XFree (data); + } + + return res; + } + + private string GetText (ref XEvent xevent, bool unicode) + { + int nread = 0; + IntPtr nitems; + IntPtr bytes_after; + + StringBuilder builder = new StringBuilder (); + do { + IntPtr actual_type; + int actual_fmt; + IntPtr data = IntPtr.Zero; + + if (0 != XplatUIX11.XGetWindowProperty (display, + xevent.AnyEvent.window, + (IntPtr) xevent.SelectionEvent.property, + IntPtr.Zero, new IntPtr(0xffffff), false, + (IntPtr) Atom.AnyPropertyType, out actual_type, + out actual_fmt, out nitems, out bytes_after, + ref data)) { + XplatUIX11.XFree (data); + break; + } + + if (unicode) + builder.Append (Marshal.PtrToStringUni (data)); + else + builder.Append (Marshal.PtrToStringAnsi (data)); + nread += nitems.ToInt32(); + + XplatUIX11.XFree (data); + } while (bytes_after.ToInt32() > 0); + if (nread == 0) + return null; + return builder.ToString (); + } + + private MemoryStream GetData (ref XEvent xevent) + { + int nread = 0; + IntPtr nitems; + IntPtr bytes_after; + + MemoryStream res = new MemoryStream (); + do { + IntPtr actual_type; + int actual_fmt; + IntPtr data = IntPtr.Zero; + + if (0 != XplatUIX11.XGetWindowProperty (display, + xevent.AnyEvent.window, + (IntPtr) xevent.SelectionEvent.property, + IntPtr.Zero, new IntPtr(0xffffff), false, + (IntPtr) Atom.AnyPropertyType, out actual_type, + out actual_fmt, out nitems, out bytes_after, + ref data)) { + XplatUIX11.XFree (data); + break; + } + + for (int i = 0; i < nitems.ToInt32(); i++) + res.WriteByte (Marshal.ReadByte (data, i)); + nread += nitems.ToInt32(); + + XplatUIX11.XFree (data); + } while (bytes_after.ToInt32() > 0); + return res; + } + + private Widget MwfWindow (IntPtr window) + { + Hwnd hwnd = Hwnd.ObjectFromHandle (window); + if (hwnd == null) + return null; + + Widget res = Widget.FromHandle (hwnd.client_window); + + if (res == null) + res = Widget.FromHandle (window); + + return res; + } + + private bool IsWindowDndAware (IntPtr handle) + { + bool res = true; + // Check the version number, we need greater than 3 + IntPtr actual; + int format; + IntPtr count; + IntPtr remaining; + IntPtr data = IntPtr.Zero; + + XplatUIX11.XGetWindowProperty (display, handle, XdndAware, IntPtr.Zero, new IntPtr(0x8000000), false, + (IntPtr) Atom.XA_ATOM, out actual, out format, + out count, out remaining, ref data); + + if (actual != (IntPtr) Atom.XA_ATOM || format != 32 || + count.ToInt32() == 0 || data == IntPtr.Zero) { + if (data != IntPtr.Zero) + XplatUIX11.XFree (data); + return false; + } + + int version = Marshal.ReadInt32 (data, 0); + + if (version < 3) { + Console.Error.WriteLine ("XDND Version too old (" + version + ")."); + XplatUIX11.XFree (data); + return false; + } + + // First type is actually the XDND version + if (count.ToInt32() > 1) { + res = false; + for (int i = 1; i < count.ToInt32(); i++) { + IntPtr type = (IntPtr) Marshal.ReadInt32 (data, i * + Marshal.SizeOf (typeof (int))); + for (int j = 0; j < drag_data.SupportedTypes.Length; j++) { + if (drag_data.SupportedTypes [j] == type) { + res = true; + break; + } + } + } + } + + XplatUIX11.XFree (data); + return res; + } + + private IntPtr [] DetermineSupportedTypes (object data) + { + ArrayList res = new ArrayList (); + + if (data is string) { + MimeHandler handler = FindHandler ("text/plain"); + if (handler != null) + res.Add (handler.Type); + }/* else if (data is Bitmap) + res.Add (data); + + */ + + IDataObject data_object = data as IDataObject; + if (data_object != null) { + foreach (string format in data_object.GetFormats (true)) { + MimeHandler handler = FindHandler (format); + if (handler != null && !res.Contains (handler.Type)) + res.Add (handler.Type); + } + } + + if (data is ISerializable) { + MimeHandler handler = FindHandler ("application/x-mono-serialized-object"); + if (handler != null) + res.Add (handler.Type); + } + + return (IntPtr []) res.ToArray (typeof (IntPtr)); + } + } +} diff --git a/source/ShiftUI/Internal/X11Exception.cs b/source/ShiftUI/Internal/X11Exception.cs new file mode 100644 index 0000000..5d3d47e --- /dev/null +++ b/source/ShiftUI/Internal/X11Exception.cs @@ -0,0 +1,87 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. (http://www.novell.com) +// +// + +using System; +using System.Text; +using System.Threading; +using ShiftUI; + +namespace ShiftUI.X11Internal { + + internal class X11Exception : ApplicationException { + IntPtr Display; + IntPtr ResourceID; + IntPtr Serial; + XRequest RequestCode; + byte ErrorCode; + byte MinorCode; + + public X11Exception (IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) + { + this.Display = Display; + this.ResourceID = ResourceID; + this.Serial = Serial; + this.RequestCode = RequestCode; + this.ErrorCode = ErrorCode; + this.MinorCode = MinorCode; + } + + public override string Message { + get { + return GetMessage (Display, ResourceID, Serial, ErrorCode, RequestCode, MinorCode); + } + } + + public static string GetMessage (IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) + { + StringBuilder sb; + string x_error_text; + string error; + string hwnd_text; + string Widget_text; + Hwnd hwnd; + Widget c; + + sb = new StringBuilder(160); + Xlib.XGetErrorText (Display, ErrorCode, sb, sb.Capacity); + x_error_text = sb.ToString(); + hwnd = Hwnd.ObjectFromHandle(ResourceID); + if (hwnd != null) { + hwnd_text = hwnd.ToString(); + c = Widget.FromHandle(hwnd.Handle); + if (c != null) { + Widget_text = c.ToString(); + } else { + Widget_text = String.Format("", hwnd.Handle); + } + } + else { + hwnd_text = ""; + Widget_text = ""; + } + + error = String.Format("\n Error: {0}\n Request: {1:D} ({2})\n Resource ID: 0x{3:X}\n Serial: {4}\n Hwnd: {5}\n Widget: {6}", x_error_text, RequestCode, RequestCode, ResourceID.ToInt32(), Serial, hwnd_text, Widget_text); + return error; + } + } +} diff --git a/source/ShiftUI/Internal/X11Hwnd.cs b/source/ShiftUI/Internal/X11Hwnd.cs new file mode 100644 index 0000000..0ef248d --- /dev/null +++ b/source/ShiftUI/Internal/X11Hwnd.cs @@ -0,0 +1,1750 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. (http://www.novell.com) +// +// + +using System; +using System.Collections; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using ShiftUI; + +namespace ShiftUI.X11Internal { + + internal class X11Hwnd : Hwnd + { + X11Display display; + + bool refetch_window_type = true; + bool refetch_window_opacity = true; + + IntPtr[] wm_state = new IntPtr[0]; + IntPtr[] window_type = new IntPtr[0]; + double trans = 1.0; + + string text; + new X11ThreadQueue queue; + + const EventMask SelectInputMask = (EventMask.ButtonPressMask | + EventMask.ButtonReleaseMask | + EventMask.KeyPressMask | + EventMask.KeyReleaseMask | + EventMask.EnterWindowMask | + EventMask.LeaveWindowMask | + EventMask.ExposureMask | + EventMask.FocusChangeMask | + EventMask.PointerMotionMask | + EventMask.SubstructureNotifyMask); + + public X11Hwnd (X11Display display) + { + this.display = display; + Queue = XplatUIX11_new.GetInstance().ThreadQueue(Thread.CurrentThread); + } + + public X11Hwnd (X11Display display, IntPtr handle) : this (display) + { + if (handle == IntPtr.Zero) + throw new ArgumentNullException ("handle"); + WholeWindow = ClientWindow = handle; + } + + // XXX this needs to be here so we don't have to + // change Hwnd. once we land, remove this and make + // Hwnd.Queue virtual or abstract + public new X11ThreadQueue Queue { + get { return queue; } + set { queue = value; } + } + + public virtual void CreateWindow (CreateParams cp) + { + if (WholeWindow != IntPtr.Zero || ClientWindow != IntPtr.Zero) + throw new Exception ("createwindow called a second time on live X11Hwnd"); + + XSetWindowAttributes Attributes; + int x; + int y; + int width; + int height; + IntPtr ParentHandle; + SetWindowValuemask ValueMask; + + Attributes = new XSetWindowAttributes(); + x = cp.X; + y = cp.Y; + width = cp.Width; + height = cp.Height; + initial_ex_style = (WindowExStyles) cp.ExStyle; + + /* Figure out our parent handle */ + if (cp.Parent != IntPtr.Zero) + // the parent handle is specified in the CreateParams + ParentHandle = Hwnd.ObjectFromHandle(cp.Parent).ClientWindow; + else if (StyleSet (cp.Style, WindowStyles.WS_CHILD)) + // a child Widget with an unassigned parent gets created under the FosterParent + ParentHandle = display.FosterParent.Handle; + else + // for all other cases, the parent is the root window + ParentHandle = display.RootWindow.Handle; + + ValueMask = SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity; + + Attributes.bit_gravity = Gravity.NorthWestGravity; + Attributes.win_gravity = Gravity.NorthWestGravity; + + // Save what's under the toolwindow + if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + Attributes.save_under = true; + ValueMask |= SetWindowValuemask.SaveUnder; + } + + // If we're a popup without caption we override the WM + if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && !StyleSet (cp.Style, WindowStyles.WS_CAPTION)) { + Attributes.override_redirect = true; + ValueMask |= SetWindowValuemask.OverrideRedirect; + } + + // Default position on screen, if window manager doesn't place us somewhere else + if (!StyleSet (cp.Style, WindowStyles.WS_CHILD) + && !StyleSet (cp.Style, WindowStyles.WS_POPUP)) { + if (x<0) x = 50; + if (y<0) y = 50; + } + // minimum width/height + if (width<1) width=1; + if (height<1) height=1; + + X = x; + Y = y; + Width = width; + Height = height; + Parent = Hwnd.ObjectFromHandle (cp.Parent); + + Enabled = !StyleSet (cp.Style, WindowStyles.WS_DISABLED); + + ClientWindow = IntPtr.Zero; + + WholeWindow = Xlib.XCreateWindow (display.Handle, ParentHandle, + X, Y, Width, Height, 0, + (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, + IntPtr.Zero, new UIntPtr ((uint)ValueMask), ref Attributes); + if (WholeWindow == IntPtr.Zero) + throw new Exception ("Coult not create X11 nc window"); + + ValueMask &= ~(SetWindowValuemask.OverrideRedirect | SetWindowValuemask.SaveUnder); + + if (display.CustomVisual != IntPtr.Zero && display.CustomColormap != IntPtr.Zero) { + ValueMask |= SetWindowValuemask.ColorMap; + Attributes.colormap = display.CustomColormap; + } + + ClientWindow = Xlib.XCreateWindow (display.Handle, WholeWindow, + ClientRect.X, ClientRect.Y, ClientRect.Width, ClientRect.Height, 0, + (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, + display.CustomVisual, new UIntPtr ((uint)ValueMask), ref Attributes); + + if (ClientWindow == IntPtr.Zero) + throw new Exception("Could not create X11 client window"); + +#if DriverDebug || DriverDebugCreate + Console.WriteLine("Created window {0:X} / {1:X} parent {2:X}, Style {3}, ExStyle {4}", ClientWindow.ToInt32(), WholeWindow.ToInt32(), Parent != null ? Parent.Handle.ToInt32() : 0, (WindowStyles)cp.Style, (WindowExStyles)cp.ExStyle); +#endif + + if (!StyleSet (cp.Style, WindowStyles.WS_CHILD)) { + if ((X != unchecked((int)0x80000000)) && (Y != unchecked((int)0x80000000))) { + XSizeHints hints; + + hints = new XSizeHints(); + hints.x = X; + hints.y = Y; + hints.flags = (IntPtr)(XSizeHintsFlags.USPosition | XSizeHintsFlags.PPosition); + Xlib.XSetWMNormalHints (display.Handle, WholeWindow, ref hints); + } + } + + Xlib.XSelectInput (display.Handle, WholeWindow, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask))); + if (WholeWindow != ClientWindow) + Xlib.XSelectInput (display.Handle, ClientWindow, new IntPtr ((int)SelectInputMask)); + + if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOPMOST)) { + WINDOW_TYPE = display.Atoms._NET_WM_WINDOW_TYPE_NORMAL; + Xlib.XSetTransientForHint (display.Handle, WholeWindow, display.RootWindow.Handle); + } + + SetWMStyles (cp); + + // set the group leader + XWMHints wm_hints = new XWMHints (); + + wm_hints.flags = (IntPtr)(XWMHintsFlags.InputHint | XWMHintsFlags.StateHint | XWMHintsFlags.WindowGroupHint); + wm_hints.input = !StyleSet (cp.Style, WindowStyles.WS_DISABLED); + wm_hints.initial_state = StyleSet (cp.Style, WindowStyles.WS_MINIMIZE) ? XInitialState.IconicState : XInitialState.NormalState; + wm_hints.window_group = ParentHandle == display.RootWindow.Handle ? ParentHandle : WholeWindow; + + Xlib.XSetWMHints (display.Handle, WholeWindow, ref wm_hints ); + + if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZE)) + SetWindowState (FormWindowState.Minimized); + else if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZE)) + SetWindowState (FormWindowState.Maximized); + + // for now make all windows dnd enabled + display.Dnd.SetAllowDrop (this, true); + + // Set caption/window title + Text = cp.Caption; + + display.SendMessage (Handle, Msg.WM_CREATE, (IntPtr)1, IntPtr.Zero /* XXX unused */); + SendParentNotify (Msg.WM_CREATE, int.MaxValue, int.MaxValue); + + if (StyleSet (cp.Style, WindowStyles.WS_VISIBLE)) { + visible = true; + Map (); + if (!(Widget.FromHandle(Handle) is Form)) + display.SendMessage (Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero); + } + } + + public virtual void DestroyWindow () + { + if (WholeWindow != IntPtr.Zero) { +#if DriverDebug || DriverDebugDestroy + Console.WriteLine ("XDestroyWindow (whole_window = {0:X})", WholeWindow.ToInt32()); +#endif + Xlib.XDestroyWindow (display.Handle, WholeWindow); + } + else if (ClientWindow != IntPtr.Zero) { +#if DriverDebug || DriverDebugDestroy + Console.WriteLine ("XDestroyWindow (client_window = {0:X})", ClientWindow.ToInt32()); +#endif + Xlib.XDestroyWindow (display.Handle, ClientWindow); + } + } + + public void Activate () + { + if (((IList)display.RootWindow._NET_SUPPORTED).Contains (display.Atoms._NET_ACTIVE_WINDOW)) { + display.SendNetWMMessage (WholeWindow, display.Atoms._NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero); + } + else { + Xlib.XRaiseWindow (display.Handle, WholeWindow); + } + } + + public void Update () + { + try { + Queue.Lock (); + if (!Visible || !PendingExpose || !Mapped) + return; + + // XXX this SendMessage call should probably not be inside the lock + display.SendMessage (ClientWindow, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero); + + PendingExpose = false; + } + finally { + Queue.Unlock (); + } + } + + public void MenuToScreen (ref int x, ref int y) + { + int dest_x_return; + int dest_y_return; + IntPtr child; + + Xlib.XTranslateCoordinates (display.Handle, + WholeWindow, display.RootWindow.Handle, + x, y, out dest_x_return, out dest_y_return, out child); + + x = dest_x_return; + y = dest_y_return; + } + + public virtual void PropertyChanged (XEvent xevent) + { + if (xevent.PropertyEvent.atom == display.Atoms._NET_WM_WINDOW_TYPE) { + // we need to recache our WINDOW_TYPE on the next query + refetch_window_type = true; + window_type = null; + } + else if (xevent.PropertyEvent.atom == display.Atoms._NET_WM_STATE) { + // we need to recache our WM_STATE on the next query + } + else if (xevent.PropertyEvent.atom == display.Atoms._NET_WM_NAME) { + // update our Text property + } + else if (xevent.PropertyEvent.atom == display.Atoms._NET_WM_WINDOW_OPACITY) { + // we need to recache our _NET_WM_WINDOW_OPACITY on the next query. + refetch_window_opacity = true; + } + // else we don't care about it + + } + + public void SetIcon (Icon icon) + { + if (icon == null) { + Xlib.XDeleteProperty (display.Handle, WholeWindow, display.Atoms._NET_WM_ICON); + } + else { + Bitmap bitmap; + int size; + IntPtr[] data; + int index; + + bitmap = icon.ToBitmap(); + index = 0; + size = bitmap.Width * bitmap.Height + 2; + data = new IntPtr[size]; + + data[index++] = (IntPtr)bitmap.Width; + data[index++] = (IntPtr)bitmap.Height; + + for (int y = 0; y < bitmap.Height; y++) { + for (int x = 0; x < bitmap.Width; x++) { + data[index++] = (IntPtr)bitmap.GetPixel(x, y).ToArgb(); + } + } + + Xlib.XChangeProperty (display.Handle, WholeWindow, + display.Atoms._NET_WM_ICON, display.Atoms.XA_CARDINAL, 32, + PropertyMode.Replace, data, size); + } + } + + public double GetWindowTransparency () + { + if (refetch_window_opacity) { + trans = 1.0; + + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + + IntPtr w = WholeWindow; + if (reparented) + w = display.XGetParent (WholeWindow); + + Xlib.XGetWindowProperty (display.Handle, w, + display.Atoms._NET_WM_WINDOW_OPACITY, IntPtr.Zero, new IntPtr (16), false, + display.Atoms.XA_CARDINAL, + out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + + if (((long)nitems == 1) && (prop != IntPtr.Zero)) { + uint x11_opacity = (uint)Marshal.ReadInt32(prop, 0); + trans = ((double)x11_opacity) / (uint)0xffffffff; + } + + if (prop != IntPtr.Zero) { + Xlib.XFree(prop); + } + } + + return trans; + } + + public void SetWindowTransparency (double transparency, Color key) + { + IntPtr x11_opacity; + + opacity = (uint)(0xffffffff * transparency); + x11_opacity = (IntPtr)((int)opacity); + + IntPtr w = WholeWindow; + if (reparented) + w = display.XGetParent (WholeWindow); + Xlib.XChangeProperty (display.Handle, w, + display.Atoms._NET_WM_WINDOW_OPACITY, display.Atoms.XA_CARDINAL, 32, + PropertyMode.Replace, ref x11_opacity, 1); + } + + public IntPtr DefWndProc (ref Message msg) + { + switch ((Msg)msg.Msg) { + case Msg.WM_PAINT: + Queue.Lock (); + PendingExpose = false; + Queue.Unlock (); + return IntPtr.Zero; + + case Msg.WM_NCPAINT: + Queue.Lock (); + PendingNCExpose = false; + Queue.Unlock (); + return IntPtr.Zero; + + case Msg.WM_CONTEXTMENU: + if (Parent != null) + display.SendMessage (Parent.ClientWindow, Msg.WM_CONTEXTMENU, msg.WParam, msg.LParam); + return IntPtr.Zero; + + case Msg.WM_MOUSEWHEEL: + if (Parent != null) { + display.SendMessage (Parent.ClientWindow, Msg.WM_MOUSEWHEEL, msg.WParam, msg.LParam); + if (msg.Result == IntPtr.Zero) + return IntPtr.Zero; + } + return IntPtr.Zero; + + case Msg.WM_SETCURSOR: + X11Hwnd parent = (X11Hwnd)Parent; + // Pass to parent window first + while ((parent != null) && (msg.Result == IntPtr.Zero)) { + msg.Result = NativeWindow.WndProc (parent.Handle, Msg.WM_SETCURSOR, msg.HWnd, msg.LParam); + parent = (X11Hwnd)Parent; + } + + if (msg.Result == IntPtr.Zero) { + IntPtr handle; + + switch((HitTest)(msg.LParam.ToInt32() & 0xffff)) { + case HitTest.HTBOTTOM: handle = Cursors.SizeNS.handle; break; + case HitTest.HTBORDER: handle = Cursors.SizeNS.handle; break; + case HitTest.HTBOTTOMLEFT: handle = Cursors.SizeNESW.handle; break; + case HitTest.HTBOTTOMRIGHT: handle = Cursors.SizeNWSE.handle; break; + case HitTest.HTERROR: + if ((msg.LParam.ToInt32() >> 16) == (int)Msg.WM_LBUTTONDOWN) + display.AudibleAlert(); + handle = Cursors.Default.handle; + break; + + case HitTest.HTHELP: handle = Cursors.Help.handle; break; + case HitTest.HTLEFT: handle = Cursors.SizeWE.handle; break; + case HitTest.HTRIGHT: handle = Cursors.SizeWE.handle; break; + case HitTest.HTTOP: handle = Cursors.SizeNS.handle; break; + case HitTest.HTTOPLEFT: handle = Cursors.SizeNWSE.handle; break; + case HitTest.HTTOPRIGHT: handle = Cursors.SizeNESW.handle; break; + +#if SameAsDefault + case HitTest.HTGROWBOX: + case HitTest.HTSIZE: + case HitTest.HTZOOM: + case HitTest.HTVSCROLL: + case HitTest.HTSYSMENU: + case HitTest.HTREDUCE: + case HitTest.HTNOWHERE: + case HitTest.HTMAXBUTTON: + case HitTest.HTMINBUTTON: + case HitTest.HTMENU: + case HitTest.HSCROLL: + case HitTest.HTBOTTOM: + case HitTest.HTCAPTION: + case HitTest.HTCLIENT: + case HitTest.HTCLOSE: +#endif + default: handle = Cursors.Default.handle; break; + } + + display.SetCursor (msg.HWnd, handle); + } + return (IntPtr)1; + + default: + return IntPtr.Zero; + } + } + + + public void AddExpose (bool client, int x, int y, int width, int height) + { + // Don't waste time + if ((x > Width) || (y > Height) || ((x + width) <= 0) || ((y + height) <= 0)) + return; + + // Keep the invalid area as small as needed + if ((x + width) > Width) + width = Width - x; + + if ((y + height) > Height) + height = Height - y; + + if (client) { + AddInvalidArea(x, y, width, height); + PendingExpose = true; + } + else { + AddNcInvalidArea (x, y, width, height); + PendingNCExpose = true; + } + } + + public void AddConfigureNotify (XEvent xevent) + { + // We drop configure events for Client windows + if ((xevent.ConfigureEvent.window != WholeWindow) || (xevent.ConfigureEvent.window != xevent.ConfigureEvent.xevent)) + return; + + if (!reparented) { + X = xevent.ConfigureEvent.x; + Y = xevent.ConfigureEvent.y; + } else { + // This sucks ass, part 1 + // Every WM does the ConfigureEvents of toplevel windows different, so there's + // no standard way of getting our adjustment. + // The code below is needed for KDE and FVWM, the 'whacky_wm' part is for metacity + // Several other WMs do their decorations different yet again and we fail to deal + // with that, since I couldn't find any frigging commonality between them. + // The only sane WM seems to be KDE + + if (!xevent.ConfigureEvent.send_event) { + IntPtr dummy_ptr; + + int trans_x; + int trans_y; + + Xlib.XTranslateCoordinates (display.Handle, WholeWindow, display.RootWindow.Handle, + -xevent.ConfigureEvent.x, -xevent.ConfigureEvent.y, + out trans_x, out trans_y, out dummy_ptr); + + X = trans_x; + Y = trans_y; + } else { + // This is a synthetic event, coordinates are in root space + X = xevent.ConfigureEvent.x; + Y = xevent.ConfigureEvent.y; + if (whacky_wm) { + int frame_left; + int frame_top; + + FrameExtents (out frame_left, out frame_top); + X -= frame_left; + Y -= frame_top; + } + } + } + + Width = xevent.ConfigureEvent.width; + Height = xevent.ConfigureEvent.height; + ClientRect = Rectangle.Empty; + + if (!configure_pending) { + Queue.AddConfigure (this); + configure_pending = true; + } + } + + public void HandleMapEvent (XEvent xevent) + { + if (xevent.type == XEventName.MapNotify) { + } + else { + } + } + + public void HandleConfigureNotify (XEvent xevent) + { + configure_pending = false; + + display.SendMessage (Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + + // We need to adjust our client window to track the resize of whole_window + if (WholeWindow != ClientWindow) + PerformNCCalc (); + } + + public void Invalidate (Rectangle rc, bool clear) + { + if (clear) { + AddExpose (true, X, Y, Width, Height); + } else { + AddExpose (true, rc.X, rc.Y, rc.Width, rc.Height); + } + } + + public void InvalidateNC () + { + AddExpose (false, 0, 0, Width, Height); + } + + // XXX this assumes the queue lock is held + public bool PendingNCExpose { + get { return nc_expose_pending; } + set { + if (nc_expose_pending == value) + return; + nc_expose_pending = value; + + if (nc_expose_pending && !expose_pending) + Queue.AddPaint (this); + else if (!nc_expose_pending && !expose_pending) + Queue.RemovePaint (this); + } + } + + // XXX this assumes the queue lock is held + public bool PendingExpose { + get { return expose_pending; } + set { + if (expose_pending == value) + return; + expose_pending = value; + + if (expose_pending && !nc_expose_pending) + Queue.AddPaint (this); + else if (!expose_pending && !nc_expose_pending) + Queue.RemovePaint (this); + } + } + + public PaintEventArgs PaintEventStart (ref Message m, bool client) + { + PaintEventArgs paint_event; + Graphics dc; + + if (client) { + dc = Graphics.FromHwnd (ClientWindow); + + Region clip_region = new Region (); + clip_region.MakeEmpty(); + + foreach (Rectangle r in ClipRectangles) + clip_region.Union (r); + + if (UserClip != null) + clip_region.Intersect(UserClip); + + dc.Clip = clip_region; + paint_event = new PaintEventArgs(dc, Invalid); + PendingExpose = false; + + ClearInvalidArea(); + + drawing_stack.Push (paint_event); + drawing_stack.Push (dc); + + return paint_event; + } + else { + dc = Graphics.FromHwnd (WholeWindow); + + if (!nc_invalid.IsEmpty) { + dc.SetClip (nc_invalid); + paint_event = new PaintEventArgs(dc, nc_invalid); + } + else { + paint_event = new PaintEventArgs(dc, new Rectangle(0, 0, width, height)); + } + PendingNCExpose = false; + + ClearNcInvalidArea (); + + drawing_stack.Push (paint_event); + drawing_stack.Push (dc); + + return paint_event; + } + } + + public void PaintEventEnd (ref Message m, bool client) + { + Graphics dc = (Graphics)drawing_stack.Pop (); + dc.Flush(); + dc.Dispose(); + + PaintEventArgs pe = (PaintEventArgs)drawing_stack.Pop(); + pe.SetGraphics (null); + pe.Dispose (); + } + + public void DrawReversibleRectangle (Rectangle rect, int line_width) + { + XGCValues gc_values; + IntPtr gc; + + gc_values = new XGCValues (); + + gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors; + gc_values.line_width = line_width; + + // XXX multiscreen support + gc_values.foreground = Xlib.XBlackPixel (display.Handle, display.DefaultScreen); + + // This logic will give us true rubber bands: (libsx, SANE_XOR) + //mask = foreground ^ background; + //XSetForeground(DisplayHandle, gc, 0xffffffff); + //XSetBackground(DisplayHandle, gc, background); + //XSetFunction(DisplayHandle, gc, GXxor); + //XSetPlaneMask(DisplayHandle, gc, mask); + + + gc = Xlib.XCreateGC (display.Handle, ClientWindow, + new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCLineWidth | GCFunction.GCForeground)), ref gc_values); + uint foreground; + uint background; + + Widget Widget; + Widget = Widget.FromHandle(Handle); + + XColor xcolor = new XColor(); + + xcolor.red = (ushort)(Widget.ForeColor.R * 257); + xcolor.green = (ushort)(Widget.ForeColor.G * 257); + xcolor.blue = (ushort)(Widget.ForeColor.B * 257); + Xlib.XAllocColor (display.Handle, display.DefaultColormap, ref xcolor); + foreground = (uint)xcolor.pixel.ToInt32(); + + xcolor.red = (ushort)(Widget.BackColor.R * 257); + xcolor.green = (ushort)(Widget.BackColor.G * 257); + xcolor.blue = (ushort)(Widget.BackColor.B * 257); + Xlib.XAllocColor (display.Handle, display.DefaultColormap, ref xcolor); + background = (uint)xcolor.pixel.ToInt32(); + + uint mask = foreground ^ background; + + Xlib.XSetForeground (display.Handle, gc, (UIntPtr)0xffffffff); + Xlib.XSetBackground (display.Handle, gc, (UIntPtr)background); + Xlib.XSetFunction (display.Handle, gc, GXFunction.GXxor); + Xlib.XSetPlaneMask (display.Handle, gc, (IntPtr)mask); + + if ((rect.Width > 0) && (rect.Height > 0)) + Xlib.XDrawRectangle (display.Handle, ClientWindow, gc, rect.Left, rect.Top, rect.Width, rect.Height); + else if (rect.Width > 0) + Xlib.XDrawLine (display.Handle, ClientWindow, gc, rect.X, rect.Y, rect.Right, rect.Y); + else + Xlib.XDrawLine (display.Handle, ClientWindow, gc, rect.X, rect.Y, rect.X, rect.Bottom); + + Xlib.XFreeGC (display.Handle, gc); + } + + private void WaitForMessage (Msg message) + { + MSG msg = new MSG (); + + queue.DispatchIdle = false; + + bool done = false; + do { + if (display.PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) { + if ((Msg)msg.message == Msg.WM_QUIT) { + // XXX this should live someplace else + XplatUI.PostQuitMessage (0); + done = true; + } + else { + if ((msg.hwnd == Handle) && + ((Msg)msg.message == message || (Msg)msg.message == Msg.WM_DESTROY)) + done = true; + display.TranslateMessage (ref msg); + display.DispatchMessage (ref msg); + } + } + } while (!done); + + queue.DispatchIdle = true; + } + + public void Map () + { + // FIXME why do we set this here and also in the MapNotify event handling? + if (!mapped) { + + Xlib.XMapWindow (display.Handle, WholeWindow); + Xlib.XMapWindow (display.Handle, ClientWindow); + + mapped = true; + + if (Widget.FromHandle(Handle) is Form) + WaitForMessage (Msg.WM_SHOWWINDOW); + } + } + + public void Unmap () + { + // FIXME why do we set this here and also in the UnmapNotify event handling? + if (mapped) { + Xlib.XUnmapWindow (display.Handle, ClientWindow); + Xlib.XUnmapWindow (display.Handle, WholeWindow); + + mapped = false; + + if (Widget.FromHandle(Handle) is Form) + WaitForMessage (Msg.WM_SHOWWINDOW); + } + } + + public void PerformNCCalc () + { + XplatUIWin32.NCCALCSIZE_PARAMS ncp; + IntPtr ptr; + Rectangle rect; + + rect = DefaultClientRect; + + ncp = new XplatUIWin32.NCCALCSIZE_PARAMS (); + ptr = Marshal.AllocHGlobal (Marshal.SizeOf(ncp)); + + ncp.rgrc1.left = rect.Left; + ncp.rgrc1.top = rect.Top; + ncp.rgrc1.right = rect.Right; + ncp.rgrc1.bottom = rect.Bottom; + + Marshal.StructureToPtr (ncp, ptr, true); + NativeWindow.WndProc (ClientWindow, Msg.WM_NCCALCSIZE, (IntPtr)1, ptr); + ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure (ptr, typeof(XplatUIWin32.NCCALCSIZE_PARAMS)); + Marshal.FreeHGlobal(ptr); + + // FIXME - debug this with Menus + + rect = new Rectangle(ncp.rgrc1.left, ncp.rgrc1.top, ncp.rgrc1.right - ncp.rgrc1.left, ncp.rgrc1.bottom - ncp.rgrc1.top); + ClientRect = rect; + + if (Visible) { + if ((rect.Width < 1) || (rect.Height < 1)) + Xlib.XMoveResizeWindow (display.Handle, ClientWindow, -5, -5, 1, 1); + else + Xlib.XMoveResizeWindow (display.Handle, ClientWindow, rect.X, rect.Y, rect.Width, rect.Height); + } + + InvalidateNC (); + } + + public void RequestNCRecalc () + { + PerformNCCalc (); + display.SendMessage (Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + InvalidateNC (); + } + + [MonoTODO] + public void RequestAdditionalWM_NCMessages (bool hover, bool leave) + { + // Missing messages won't crash anything so just don't generate them for the moment. + // throw new NotImplementedException( ); + } + + public void FrameExtents (out int left, out int top) + { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + + Xlib.XGetWindowProperty (display.Handle, WholeWindow, + display.Atoms._NET_FRAME_EXTENTS, IntPtr.Zero, new IntPtr (16), false, + display.Atoms.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + if (((long)nitems == 4) && (prop != IntPtr.Zero)) { + left = Marshal.ReadIntPtr(prop, 0).ToInt32(); + //right = Marshal.ReadIntPtr(prop, IntPtr.Size).ToInt32(); + top = Marshal.ReadIntPtr(prop, IntPtr.Size * 2).ToInt32(); + //bottom = Marshal.ReadIntPtr(prop, IntPtr.Size * 3).ToInt32(); + } else { + left = 0; + top = 0; + } + + if (prop != IntPtr.Zero) { + Xlib.XFree(prop); + } + } + + static bool StyleSet (int s, WindowStyles ws) + { + return (s & (int)ws) == (int)ws; + } + + static bool ExStyleSet (int ex, WindowExStyles exws) + { + return (ex & (int)exws) == (int)exws; + } + + // XXX this should be a static method on Hwnd so other backends can use it + public static void DeriveStyles(int Style, int ExStyle, out FormBorderStyle border_style, out bool border_static, + out TitleStyle title_style, out int caption_height, out int tool_caption_height) + { + + // Only MDI windows get caption_heights + caption_height = 0; + tool_caption_height = 19; + border_static = false; + + if (StyleSet (Style, WindowStyles.WS_CHILD)) { + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_CLIENTEDGE)) { + border_style = FormBorderStyle.Fixed3D; + } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_STATICEDGE)) { + border_style = FormBorderStyle.Fixed3D; + border_static = true; + } else if (!StyleSet (Style, WindowStyles.WS_BORDER)) { + border_style = FormBorderStyle.None; + } else { + border_style = FormBorderStyle.FixedSingle; + } + title_style = TitleStyle.None; + + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_MDICHILD)) { + caption_height = 26; + + if (StyleSet (Style, WindowStyles.WS_CAPTION)) { + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) + title_style = TitleStyle.Tool; + else + title_style = TitleStyle.Normal; + } + + if (StyleSet (Style, WindowStyles.WS_OVERLAPPEDWINDOW) || + ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) + border_style = (FormBorderStyle) 0xFFFF; + else + border_style = FormBorderStyle.None; + } + } + else { + title_style = TitleStyle.None; + if (StyleSet (Style, WindowStyles.WS_CAPTION)) { + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) + title_style = TitleStyle.Tool; + else + title_style = TitleStyle.Normal; + } + + border_style = FormBorderStyle.None; + + if (StyleSet (Style, WindowStyles.WS_THICKFRAME)) { + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) + border_style = FormBorderStyle.SizableToolWindow; + else + border_style = FormBorderStyle.Sizable; + } else { + if (StyleSet (Style, WindowStyles.WS_CAPTION)) { + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_CLIENTEDGE)) + border_style = FormBorderStyle.Fixed3D; + else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_STATICEDGE)) { + border_style = FormBorderStyle.Fixed3D; + border_static = true; + } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_DLGMODALFRAME)) + border_style = FormBorderStyle.FixedDialog; + else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) + border_style = FormBorderStyle.FixedToolWindow; + else if (StyleSet (Style, WindowStyles.WS_BORDER)) + border_style = FormBorderStyle.FixedSingle; + } else if (StyleSet (Style, WindowStyles.WS_BORDER)) + border_style = FormBorderStyle.FixedSingle; + } + } + } + + public void SetHwndStyles (CreateParams cp) + { + DeriveStyles(cp.Style, cp.ExStyle, out this.border_style, out this.border_static, out this.title_style, out this.caption_height, out this.tool_caption_height); + } + + public void SetWMStyles (CreateParams cp) + { + MotifWmHints mwmHints; + MotifFunctions functions; + MotifDecorations decorations; + IntPtr[] atoms; + int atom_count; + Rectangle client_rect; + + // Child windows don't need WM window styles + if (StyleSet (cp.Style, WindowStyles.WS_CHILDWINDOW)) + return; + + atoms = new IntPtr[8]; + mwmHints = new MotifWmHints(); + functions = 0; + decorations = 0; + + mwmHints.flags = (IntPtr)(MotifFlags.Functions | MotifFlags.Decorations); + mwmHints.functions = (IntPtr)0; + mwmHints.decorations = (IntPtr)0; + + if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW) + || !StyleSet (cp.Style, WindowStyles.WS_CAPTION | WindowStyles.WS_BORDER | WindowStyles.WS_DLGFRAME)) { + /* tool windows get no window manager + decorations, and neither do windows + which lack CAPTION/BORDER/DLGFRAME + styles. + */ + + /* just because the window doesn't get any decorations doesn't + mean we should disable the functions. for instance, without + MotifFunctions.Maximize, changing the windowstate to Maximized + is ignored by metacity. */ + functions |= MotifFunctions.Move | MotifFunctions.Resize | MotifFunctions.Minimize | MotifFunctions.Maximize; + } + else { + if (StyleSet (cp.Style, WindowStyles.WS_CAPTION)) { + functions |= MotifFunctions.Move; + decorations |= MotifDecorations.Title | MotifDecorations.Menu; + } + + if (StyleSet (cp.Style, WindowStyles.WS_THICKFRAME)) { + functions |= MotifFunctions.Move | MotifFunctions.Resize; + decorations |= MotifDecorations.Border | MotifDecorations.ResizeH; + } + + if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZEBOX)) { + functions |= MotifFunctions.Minimize; + decorations |= MotifDecorations.Minimize; + } + + if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZEBOX)) { + functions |= MotifFunctions.Maximize; + decorations |= MotifDecorations.Maximize; + } + + if (StyleSet (cp.Style, WindowStyles.WS_SIZEBOX)) { + functions |= MotifFunctions.Resize; + decorations |= MotifDecorations.ResizeH; + } + + if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_DLGMODALFRAME)) { + decorations |= MotifDecorations.Border; + } + + if (StyleSet (cp.Style, WindowStyles.WS_BORDER)) { + decorations |= MotifDecorations.Border; + } + + if (StyleSet (cp.Style, WindowStyles.WS_DLGFRAME)) { + decorations |= MotifDecorations.Border; + } + + if (StyleSet (cp.Style, WindowStyles.WS_SYSMENU)) { + functions |= MotifFunctions.Close; + } + else { + functions &= ~(MotifFunctions.Maximize | MotifFunctions.Minimize | MotifFunctions.Close); + decorations &= ~(MotifDecorations.Menu | MotifDecorations.Maximize | MotifDecorations.Minimize); + if (cp.Caption == "") { + functions &= ~MotifFunctions.Move; + decorations &= ~(MotifDecorations.Title | MotifDecorations.ResizeH); + } + } + } + + if ((functions & MotifFunctions.Resize) == 0) { + fixed_size = true; + SetMinMax (new Rectangle(cp.X, cp.Y, cp.Width, cp.Height), new Size(cp.Width, cp.Height), new Size(cp.Width, cp.Height)); + } else { + fixed_size = false; + } + + mwmHints.functions = (IntPtr)functions; + mwmHints.decorations = (IntPtr)decorations; + + FormWindowState current_state = GetWindowState (); + if (current_state == (FormWindowState)(-1)) + current_state = FormWindowState.Normal; + + client_rect = ClientRect; + + atom_count = 0; + + // needed! map toolwindows to _NET_WM_WINDOW_TYPE_UTILITY to make newer metacity versions happy + // and get those windows in front of their parents + if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + WINDOW_TYPE = display.Atoms._NET_WM_WINDOW_TYPE_UTILITY; + + Form f = Widget.FromHandle(Handle) as Form; + if (f != null && !reparented) { + if (f.Owner != null && f.Owner.Handle != IntPtr.Zero) { + Hwnd owner_hwnd = Hwnd.ObjectFromHandle(f.Owner.Handle); + if (owner_hwnd != null) + Xlib.XSetTransientForHint (display.Handle, WholeWindow, + owner_hwnd.WholeWindow); + } + } + } + + Xlib.XChangeProperty (display.Handle, WholeWindow, + display.Atoms._MOTIF_WM_HINTS, display.Atoms._MOTIF_WM_HINTS, 32, + PropertyMode.Replace, ref mwmHints, 5); + + if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && (parent != null) && (parent.WholeWindow != IntPtr.Zero)) { + WINDOW_TYPE = display.Atoms._NET_WM_WINDOW_TYPE_NORMAL; + Xlib.XSetTransientForHint(display.Handle, WholeWindow, parent.WholeWindow); + } else if (!ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_APPWINDOW)) { + /* this line keeps the window from showing up in gnome's taskbar */ + atoms[atom_count++] = display.Atoms._NET_WM_STATE_SKIP_TASKBAR; + } + if ((client_rect.Width < 1) || (client_rect.Height < 1)) { + Xlib.XMoveResizeWindow (display.Handle, ClientWindow, -5, -5, 1, 1); + } else { + Xlib.XMoveResizeWindow (display.Handle, ClientWindow, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height); + } + + if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) + atoms[atom_count++] = display.Atoms._NET_WM_STATE_SKIP_TASKBAR; + + /* we need to add these atoms in the + * event we're maximized, since we're + * replacing the existing + * _NET_WM_STATE here. If we don't + * add them, future calls to + * GetWindowState will return Normal + * for a window which is maximized. */ + if (current_state == FormWindowState.Maximized) { + atoms[atom_count++] = display.Atoms._NET_WM_STATE_MAXIMIZED_HORZ; + atoms[atom_count++] = display.Atoms._NET_WM_STATE_MAXIMIZED_VERT; + } + + Set_WM_STATE (atoms, atom_count); + + atom_count = 0; + atoms[atom_count++] = display.Atoms.WM_DELETE_WINDOW; + if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_CONTEXTHELP)) + atoms[atom_count++] = display.Atoms._NET_WM_CONTEXT_HELP; + + Xlib.XSetWMProtocols (display.Handle, WholeWindow, atoms, atom_count); + } + + public void ClientToScreen (ref int x, ref int y) + { + int dest_x_return; + int dest_y_return; + IntPtr child; + + Xlib.XTranslateCoordinates (display.Handle, + ClientWindow, display.RootWindow.Handle, + x, y, out dest_x_return, out dest_y_return, out child); + + x = dest_x_return; + y = dest_y_return; + } + + public void ScreenToClient (ref int x, ref int y) + { + int dest_x_return; + int dest_y_return; + IntPtr child; + + Xlib.XTranslateCoordinates (display.Handle, + display.RootWindow.Handle, ClientWindow, + x, y, out dest_x_return, out dest_y_return, out child); + + x = dest_x_return; + y = dest_y_return; + } + + + public void ScreenToMenu (ref int x, ref int y) + { + int dest_x_return; + int dest_y_return; + IntPtr child; + + Xlib.XTranslateCoordinates (display.Handle, + display.RootWindow.Handle, WholeWindow, + x, y, out dest_x_return, out dest_y_return, out child); + + x = dest_x_return; + y = dest_y_return; + } + + public void ScrollWindow (Rectangle area, int XAmount, int YAmount, bool with_children) + { + IntPtr gc; + XGCValues gc_values; + + Rectangle r = Rectangle.Intersect (Invalid, area); + if (!r.IsEmpty) { + /* We have an invalid area in the window we're scrolling. + Adjust our stored invalid rectangle to to match the scrolled amount */ + + r.X += XAmount; + r.Y += YAmount; + + if (r.X < 0) { + r.Width += r.X; + r.X =0; + } + + if (r.Y < 0) { + r.Height += r.Y; + r.Y =0; + } + + if (area.Contains (Invalid)) + ClearInvalidArea(); + AddInvalidArea(r); + } + + gc_values = new XGCValues(); + + gc_values.graphics_exposures = false; + if (with_children) + gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors; + + gc = Xlib.XCreateGC (display.Handle, ClientWindow, IntPtr.Zero, ref gc_values); + + int src_x, src_y; + int dest_x, dest_y; + int width, height; + + if (YAmount > 0) { + src_y = area.Y; + height = area.Height - YAmount; + dest_y = area.Y + YAmount; + } + else { + src_y = area.Y - YAmount; + height = area.Height + YAmount; + dest_y = area.Y; + } + + if (XAmount > 0) { + src_x = area.X; + width = area.Width - XAmount; + dest_x = area.X + XAmount; + } + else { + src_x = area.X - XAmount; + width = area.Width + XAmount; + dest_x = area.X; + } + + Xlib.XCopyArea (display.Handle, ClientWindow, ClientWindow, gc, src_x, src_y, width, height, dest_x, dest_y); + + // Generate an expose for the area exposed by the horizontal scroll + // We don't use AddExpose since we're + if (XAmount > 0) { + AddExpose (true, area.X, area.Y, XAmount, area.Height); + } else if (XAmount < 0) { + AddExpose (true, XAmount + area.X + area.Width, area.Y, -XAmount, area.Height); + } + + // Generate an expose for the area exposed by the vertical scroll + if (YAmount > 0) { + AddExpose (true, area.X, area.Y, area.Width, YAmount); + } else if (YAmount < 0) { + AddExpose (true, area.X, YAmount + area.Y + area.Height, area.Width, -YAmount); + } + + Xlib.XFreeGC (display.Handle, gc); + } + + + public void SetBorderStyle (FormBorderStyle border_style) + { + Form form = Widget.FromHandle (Handle) as Form; + if (form != null && form.window_manager == null && (border_style == FormBorderStyle.FixedToolWindow || + border_style == FormBorderStyle.SizableToolWindow)) { + form.window_manager = new ToolWindowManager (form); + } + + BorderStyle = border_style; + RequestNCRecalc (); + } + + // XXX this should probably be in Hwnd + public void SetClipRegion (Region region) + { + UserClip = region; + Invalidate (new Rectangle(0, 0, Width, Height), false); + } + + // XXX this should probably be in Hwnd + public Region GetClipRegion () + { + return UserClip; + } + + public void SetMenu (Menu menu) + { + Menu = menu; + + RequestNCRecalc (); + } + + public void SetMinMax (Rectangle maximized, Size min, Size max) + { + XSizeHints hints; + IntPtr dummy; + + hints = new XSizeHints(); + + Xlib.XGetWMNormalHints (display.Handle, WholeWindow, ref hints, out dummy); + if ((min != Size.Empty) && (min.Width > 0) && (min.Height > 0)) { + hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize); + hints.min_width = min.Width; + hints.min_height = min.Height; + } + + if ((max != Size.Empty) && (max.Width > 0) && (max.Height > 0)) { + hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize); + hints.max_width = max.Width; + hints.max_height = max.Height; + } + + if (hints.flags != IntPtr.Zero) + Xlib.XSetWMNormalHints (display.Handle, WholeWindow, ref hints); + + if ((maximized != Rectangle.Empty) && (maximized.Width > 0) && (maximized.Height > 0)) { + hints.flags = (IntPtr)XSizeHintsFlags.PPosition; + hints.x = maximized.X; + hints.y = maximized.Y; + hints.width = maximized.Width; + hints.height = maximized.Height; + + // Metacity does not seem to follow this constraint for maximized (zoomed) windows + Xlib.XSetZoomHints (display.Handle, WholeWindow, ref hints); + } + } + + // For WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN, WM_XBUTTONDOWN + // WM_CREATE and WM_DESTROY causes + public void SendParentNotify (Msg cause, int x, int y) + { + if (Handle == IntPtr.Zero) + return; + + if (ExStyleSet ((int) initial_ex_style, WindowExStyles.WS_EX_NOPARENTNOTIFY)) + return; + + if (Parent == null || Parent.Handle == IntPtr.Zero) + return; + + if (cause == Msg.WM_CREATE || cause == Msg.WM_DESTROY) { + display.SendMessage(Parent.Handle, Msg.WM_PARENTNOTIFY, Widget.MakeParam((int)cause, 0), Handle); + } else { + display.SendMessage(Parent.Handle, Msg.WM_PARENTNOTIFY, Widget.MakeParam((int)cause, 0), Widget.MakeParam(x, y)); + } + + ((X11Hwnd)Parent).SendParentNotify (cause, x, y); + } + + + public void GetPosition (bool is_toplevel, out int x, out int y, out int width, out int height, out int client_width, out int client_height) + { + x = X; + y = Y; + width = Width; + height = Height; + + PerformNCCalc (); + + client_width = ClientRect.Width; + client_height = ClientRect.Height; + } + + public void SetPosition (int x, int y, int width, int height) + { + // Win32 automatically changes negative width/height to 0. + if (width < 0) + width = 0; + if (height < 0) + height = 0; + + // X requires a sanity check for width & height; otherwise it dies + if (zero_sized && width > 0 && height > 0) { + if (Visible) { + Map (); + } + zero_sized = false; + } + + if ((width < 1) || (height < 1)) { + zero_sized = true; + Unmap (); + } + + // Save a server roundtrip (and prevent a feedback loop) + if ((X == x) && (Y == y) && + (Width == width) && (Height == height)) { + return; + } + + if (!zero_sized) { + //Hack? + X = x; + Y = y; + Width = width; + Height = height; + display.SendMessage (Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + + if (fixed_size) { + SetMinMax (Rectangle.Empty, new Size(width, height), new Size(width, height)); + } + + Xlib.XMoveResizeWindow (display.Handle, WholeWindow, x, y, width, height); + PerformNCCalc (); + } + + // Update our position/size immediately, so + // that future calls to SetWindowPos aren't + // kept from calling XMoveResizeWindow (by the + // "Save a server roundtrip" block above). + X = x; + Y = y; + Width = width; + Height = height; + ClientRect = Rectangle.Empty; + } + + public void SetParent (X11Hwnd parent_hwnd) + { + Parent = parent_hwnd; + +#if DriverDebug || DriverDebugParent + Console.WriteLine("Parent for window {0} = {1}", XplatUI.Window(Handle), XplatUI.Window(hwnd.parent != null ? parent_hwnd.Handle : IntPtr.Zero)); +#endif + Xlib.XReparentWindow (display.Handle, WholeWindow, + parent_hwnd == null ? display.FosterParent.ClientWindow : parent_hwnd.ClientWindow, + X, Y); + } + + public void SetCursorPos (int x, int y) + { + Xlib.XWarpPointer (display.Handle, IntPtr.Zero, ClientWindow, 0, 0, 0, 0, x, y); + } + + public bool SetTopmost (bool enabled) + { + if (enabled) { + int[] atoms = new int[8]; + atoms[0] = display.Atoms._NET_WM_STATE_ABOVE.ToInt32(); + Xlib.XChangeProperty (display.Handle, WholeWindow, display.Atoms._NET_WM_STATE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1); + } + else { + Xlib.XDeleteProperty (display.Handle, WholeWindow, display.Atoms._NET_WM_STATE); + } + + return true; + } + + public bool SetOwner (X11Hwnd owner) + { + if (owner != null) { + WINDOW_TYPE = display.Atoms._NET_WM_WINDOW_TYPE_NORMAL; + if (owner != null) + Xlib.XSetTransientForHint (display.Handle, WholeWindow, owner.WholeWindow); + else + Xlib.XSetTransientForHint (display.Handle, WholeWindow, display.RootWindow.WholeWindow); + } + else { + Xlib.XDeleteProperty (display.Handle, WholeWindow, display.Atoms.XA_WM_TRANSIENT_FOR); + } + + return true; + } + + public bool SetVisible (bool visible, bool activate) + { + Visible = visible; + + if (visible) { + Map (); + + if (Widget.FromHandle (Handle) is Form) { + FormWindowState s; + + s = ((Form)Widget.FromHandle(Handle)).WindowState; + + switch(s) { + case FormWindowState.Minimized: SetWindowState (FormWindowState.Minimized); break; + case FormWindowState.Maximized: SetWindowState (FormWindowState.Maximized); break; + } + + } + + display.SendMessage (Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + } + else { + Unmap (); + } + + return true; + } + + public FormWindowState GetWindowState () + { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + IntPtr atom; + int maximized; + bool minimized; + XWindowAttributes attributes; + + maximized = 0; + minimized = false; + Xlib.XGetWindowProperty (display.Handle, WholeWindow, + display.Atoms._NET_WM_STATE, IntPtr.Zero, new IntPtr (256), false, + display.Atoms.XA_ATOM, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + + if (((long)nitems > 0) && (prop != IntPtr.Zero)) { + for (int i = 0; i < (long)nitems; i++) { + // XXX 64 bit clean? + atom = (IntPtr)Marshal.ReadInt32(prop, i * 4); + if ((atom == display.Atoms._NET_WM_STATE_MAXIMIZED_HORZ) || (atom == display.Atoms._NET_WM_STATE_MAXIMIZED_VERT)) + maximized++; + else if (atom == display.Atoms._NET_WM_STATE_HIDDEN) + minimized = true; + } + Xlib.XFree(prop); + } + + if (minimized) + return FormWindowState.Minimized; + else if (maximized == 2) + return FormWindowState.Maximized; + + attributes = new XWindowAttributes(); + Xlib.XGetWindowAttributes (display.Handle, ClientWindow, ref attributes); + if (attributes.map_state == MapState.IsUnmapped) + return (FormWindowState)(-1); + + return FormWindowState.Normal; + } + + + public void SetWindowState (FormWindowState state) + { + FormWindowState current_state; + + current_state = GetWindowState (); + + if (current_state == state) + return; + + switch (state) { + case FormWindowState.Normal: + if (current_state == FormWindowState.Minimized) + Map (); + else if (current_state == FormWindowState.Maximized) + display.SendNetWMMessage (WholeWindow, + display.Atoms._NET_WM_STATE, (IntPtr)2 /* toggle */, + display.Atoms._NET_WM_STATE_MAXIMIZED_HORZ, + display.Atoms._NET_WM_STATE_MAXIMIZED_VERT); + Activate (); + break; + + case FormWindowState.Minimized: + if (current_state == FormWindowState.Maximized) + display.SendNetWMMessage (WholeWindow, + display.Atoms._NET_WM_STATE, (IntPtr)2 /* toggle */, + display.Atoms._NET_WM_STATE_MAXIMIZED_HORZ, + display.Atoms._NET_WM_STATE_MAXIMIZED_VERT); + + // FIXME multiscreen support + Xlib.XIconifyWindow (display.Handle, WholeWindow, display.DefaultScreen); + break; + + case FormWindowState.Maximized: + if (current_state == FormWindowState.Minimized) + Map (); + + display.SendNetWMMessage (WholeWindow, + display.Atoms._NET_WM_STATE, (IntPtr)1 /* Add */, + display.Atoms._NET_WM_STATE_MAXIMIZED_HORZ, + display.Atoms._NET_WM_STATE_MAXIMIZED_VERT); + Activate (); + break; + } + } + + public bool SetZOrder (X11Hwnd after_hwnd, bool top, bool bottom) + { + if (top) { + Xlib.XRaiseWindow (display.Handle, WholeWindow); + return true; + } + else if (bottom) { + Xlib.XLowerWindow (display.Handle, WholeWindow); + return true; + } + else { + if (after_hwnd == null) { + Update_USER_TIME (); + Xlib.XRaiseWindow (display.Handle, WholeWindow); + display.SendNetWMMessage (WholeWindow, display.Atoms._NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero); + return true; + } + + XWindowChanges values = new XWindowChanges(); + values.sibling = after_hwnd.WholeWindow; + values.stack_mode = StackMode.Below; + + Xlib.XConfigureWindow (display.Handle, WholeWindow, ChangeWindowFlags.CWStackMode | ChangeWindowFlags.CWSibling, ref values); + } + return false; + } + + public X11Display Display { + get { return display; } + } + + public string Text { + get { return text; } + set { + if (value == null) + value = ""; + + if (value == text) + return; + + text = value; + + Xlib.XChangeProperty(display.Handle, WholeWindow, + display.Atoms._NET_WM_NAME, display.Atoms.UNICODETEXT, 8, + PropertyMode.Replace, text, Encoding.UTF8.GetByteCount (text)); + + // XXX this has problems with UTF8. + // we need to either use the actual + // text if it's latin-1, or convert it + // to compound text if it's in a + // different charset. + Xlib.XStoreName(display.Handle, WholeWindow, text); + } + } + + public bool GetText (out string text) + { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + + Xlib.XGetWindowProperty (display.Handle, WholeWindow, + display.Atoms._NET_WM_NAME, IntPtr.Zero, new IntPtr (1), false, + display.Atoms.UNICODETEXT, out actual_atom, out actual_format, + out nitems, out bytes_after, ref prop); + + if ((long)nitems > 0 && prop != IntPtr.Zero) { + text = Marshal.PtrToStringUni (prop, (int)nitems); + Xlib.XFree (prop); + return true; + } + else { + // fallback on the non-_NET property + IntPtr textptr; + + textptr = IntPtr.Zero; + + Xlib.XFetchName (display.Handle, WholeWindow, ref textptr); + if (textptr != IntPtr.Zero) { + text = Marshal.PtrToStringAnsi(textptr); + Xlib.XFree(textptr); + return true; + } else { + text = ""; + return false; + } + } + } + + public IntPtr WINDOW_TYPE { + get { + if (refetch_window_type) { + window_type = GetAtomListProperty (display.Atoms._NET_WM_WINDOW_TYPE); + refetch_window_type = false; + } + + return window_type.Length > 0 ? window_type[0] : IntPtr.Zero; + } + set { + Set_WINDOW_TYPE (new IntPtr[] {value}, 1); + } + } + + public void Set_WINDOW_TYPE (IntPtr[] value, int count) + { + if (refetch_window_type) { + window_type = GetAtomListProperty (display.Atoms._NET_WM_WINDOW_TYPE); + refetch_window_type = false; + } + + if (ArrayDifferent (window_type, value)) { + window_type = value; + Xlib.XChangeProperty (display.Handle, WholeWindow, + display.Atoms._NET_WM_WINDOW_TYPE, display.Atoms.XA_ATOM, 32, + PropertyMode.Replace, window_type, window_type.Length); + } + } + + public void Set_WM_STATE (IntPtr[] value, int count) + { + if (ArrayDifferent (wm_state, value)) { + wm_state = value; + Xlib.XChangeProperty (display.Handle, WholeWindow, + display.Atoms._NET_WM_STATE, display.Atoms.XA_ATOM, 32, + PropertyMode.Replace, wm_state, wm_state.Length); + } + } + + public void Update_USER_TIME () + { + int[] args; + + args = new int[2]; + args[0] = display.CurrentTimestamp; + Xlib.XChangeProperty (display.Handle, WholeWindow, + display.Atoms._NET_WM_USER_TIME, display.Atoms.XA_CARDINAL, 32, + PropertyMode.Replace, args, 1); + } + + public IntPtr[] GetAtomListProperty (IntPtr atom) + { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + + Xlib.XGetWindowProperty (display.Handle, WholeWindow, + atom, IntPtr.Zero, new IntPtr (Int32.MaxValue), false, + display.Atoms.XA_ATOM, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + + if (actual_atom != display.Atoms.XA_ATOM || + (long)nitems == 0 || + prop == IntPtr.Zero) { + return new IntPtr[0]; + } + + IntPtr[] values = new IntPtr[(long)nitems]; + int ofs = 0; + + for (int i = 0; i < values.Length; i ++) { + values[i] = Marshal.ReadIntPtr (prop, ofs); ofs += IntPtr.Size; + } + + Xlib.XFree (prop); + + return values; + } + + bool ArrayDifferent (IntPtr[] a, IntPtr[] b) + { + if (a.Length != b.Length) + return true; + + for (int i = 0; i < a.Length; i ++) { + if (a[i] != b[i]) + return true; + } + + return false; + } + } +} diff --git a/source/ShiftUI/Internal/X11Keyboard.cs b/source/ShiftUI/Internal/X11Keyboard.cs new file mode 100644 index 0000000..70a6c03 --- /dev/null +++ b/source/ShiftUI/Internal/X11Keyboard.cs @@ -0,0 +1,1478 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// +// + + +// +// TODO: +// - dead chars are not translated properly +// - There is a lot of potential for optimmization in here +// +using System; +using System.Collections; +using System.Diagnostics; +using System.Drawing; +using System.Text; +using System.Globalization; +using System.Runtime.InteropServices; + +namespace ShiftUI { + + public enum XLookupStatus + { + XBufferOverflow = -1, + XLookupNone = 1, + XLookupChars = 2, + XLookupKeySym = 3, + XLookupBoth = 4 + } + + internal class X11Keyboard : IDisposable { + internal static object XlibLock; + + private IntPtr display; + private IntPtr client_window; + private IntPtr xim; + private Hashtable xic_table = new Hashtable (); + private XIMPositionContext positionContext; + private XIMCallbackContext callbackContext; + private XIMProperties ximStyle; + private EventMask xic_event_mask = EventMask.NoEventMask; + private StringBuilder lookup_buffer; + private byte [] lookup_byte_buffer = new byte [100]; + private int min_keycode, max_keycode, keysyms_per_keycode, syms; + private int [] keyc2vkey = new int [256]; + private int [] keyc2scan = new int [256]; + private byte [] key_state_table = new byte [256]; + private int lcid; + private bool num_state, cap_state; + private bool initialized; + private bool menu_state = false; + private Encoding encoding; + + private int NumLockMask; + private int AltGrMask; + + public X11Keyboard (IntPtr display, IntPtr clientWindow) + { + this.display = display; + lookup_buffer = new StringBuilder (24); + EnsureLayoutInitialized (); + } + + private Encoding AnsiEncoding + { + get + { + if (encoding == null) + encoding = Encoding.GetEncoding(new CultureInfo(lcid).TextInfo.ANSICodePage); + return encoding; + } + } + + public IntPtr ClientWindow { + get { return client_window; } + } + + void IDisposable.Dispose () + { + if (xim != IntPtr.Zero) { + foreach (IntPtr xic in xic_table.Values) + XDestroyIC (xic); + xic_table.Clear (); + + XCloseIM (xim); + xim = IntPtr.Zero; + } + } + + public void DestroyICForWindow (IntPtr window) + { + IntPtr xic = GetXic (window); + if (xic != IntPtr.Zero) { + xic_table.Remove ((long) window); + XDestroyIC (xic); + } + } + + public void EnsureLayoutInitialized () + { + if (initialized) + return; + + KeyboardLayouts layouts = new KeyboardLayouts (); + KeyboardLayout layout = DetectLayout (layouts); + lcid = layout.Lcid; + CreateConversionArray (layouts, layout); + SetupXIM (); + initialized = true; + } + + private void SetupXIM () + { + xim = IntPtr.Zero; + + if (!XSupportsLocale ()) { + Console.Error.WriteLine ("X does not support your locale"); + return; + } + + if (!XSetLocaleModifiers (String.Empty)) { + Console.Error.WriteLine ("Could not set X locale modifiers"); + return; + } + + if (Environment.GetEnvironmentVariable (ENV_NAME_XIM_STYLE) == "disabled") { + return; + } + + xim = XOpenIM (display, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + if (xim == IntPtr.Zero) + Console.Error.WriteLine ("Could not get XIM"); + + initialized = true; + } + + void CreateXicForWindow (IntPtr window) + { + IntPtr xic = CreateXic (window, xim); + xic_table [(long) window] = xic; + if (xic == IntPtr.Zero) + Console.Error.WriteLine ("Could not get XIC"); + else { + if (XGetICValues (xic, "filterEvents", out xic_event_mask, IntPtr.Zero) != null) + Console.Error.WriteLine ("Could not get XIC values"); + EventMask mask = EventMask.ExposureMask | EventMask.KeyPressMask | EventMask.FocusChangeMask; + if ((xic_event_mask | mask) == xic_event_mask) { + xic_event_mask |= mask; + lock (XlibLock) { + XplatUIX11.XSelectInput(display, window, new IntPtr ((int) xic_event_mask)); + } + } + } + } + + public EventMask KeyEventMask { + get { return xic_event_mask; } + } + + public Keys ModifierKeys { + get { + Keys keys = Keys.None; + if ((key_state_table [(int) VirtualKeys.VK_SHIFT] & 0x80) != 0) + keys |= Keys.Shift; + if ((key_state_table [(int) VirtualKeys.VK_CONTROL ] & 0x80) != 0) + keys |= Keys.Widget; + if ((key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0) + keys |= Keys.Alt; + return keys; + } + } + + private IntPtr GetXic (IntPtr window) + { + if (xim != IntPtr.Zero && xic_table.ContainsKey ((long) window)) + return (IntPtr) xic_table [(long) window]; + else + return IntPtr.Zero; + } + + private bool FilterKey (XEvent e, int vkey) + { + if (XplatUI.key_filters.Count == 0) + return false; + XLookupStatus status; + XKeySym ks; + KeyFilterData data; + data.Down = (e.type == XEventName.KeyPress); + data.ModifierKeys = ModifierKeys; + LookupString (ref e, 0, out ks, out status); + data.keysym = (int)ks; + data.keycode = e.KeyEvent.keycode; + data.str = lookup_buffer.ToString (0, lookup_buffer.Length); + return XplatUI.FilterKey (data); + } + + public void FocusIn (IntPtr window) + { + this.client_window = window; + if (xim == IntPtr.Zero) + return; + + if (!xic_table.ContainsKey ((long) window)) + CreateXicForWindow (window); + IntPtr xic = GetXic (window); + if (xic != IntPtr.Zero) + XSetICFocus (xic); + } + + private bool have_Xutf8ResetIC = true; + + public void FocusOut (IntPtr window) + { + this.client_window = IntPtr.Zero; + if (xim == IntPtr.Zero) + return; + + IntPtr xic = GetXic (window); + if (xic != IntPtr.Zero) { + if (have_Xutf8ResetIC) { + try { + Xutf8ResetIC (xic); + } catch (EntryPointNotFoundException) { + have_Xutf8ResetIC = false; + } + } + XUnsetICFocus (xic); + } + } + + public bool ResetKeyState(IntPtr hwnd, ref MSG msg) { + // FIXME - keep defining events/msg and return true until we've 'restored' all + // pending keypresses + if ((key_state_table [(int) VirtualKeys.VK_SHIFT] & 0x80) != 0) { + key_state_table [(int) VirtualKeys.VK_SHIFT] &= unchecked((byte)~0x80); + } + + if ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) != 0) { + key_state_table [(int) VirtualKeys.VK_CONTROL] &= unchecked((byte)~0x80); + } + + if ((key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0) { + key_state_table [(int) VirtualKeys.VK_MENU] &= unchecked((byte)~0x80); + } + return false; + } + + // Almost identical to UpdateKeyState() but does not call LookupString(). + // The actual purpose is to handle shift state correctly. + public void PreFilter (XEvent xevent) + { + // It is still possible that some keyboards could have some shift + // keys outside this range, but let's think about such cases only + // if it actually happened. + if (xevent.KeyEvent.keycode >= keyc2vkey.Length) + return; + + int vkey = keyc2vkey [xevent.KeyEvent.keycode]; + + switch (xevent.type) { + case XEventName.KeyRelease: + key_state_table [vkey & 0xff] &= unchecked ((byte) ~0x80); + break; + case XEventName.KeyPress: + if ((key_state_table [vkey & 0xff] & 0x80) == 0) { + key_state_table [vkey & 0xff] ^= 0x01; + } + key_state_table [vkey & 0xff] |= 0x80; + break; + } + } + + public void KeyEvent (IntPtr hwnd, XEvent xevent, ref MSG msg) + { + XKeySym keysym; + int ascii_chars; + + XLookupStatus status; + ascii_chars = LookupString (ref xevent, 24, out keysym, out status); + + if (((int) keysym >= (int) MiscKeys.XK_ISO_Lock && + (int) keysym <= (int) MiscKeys.XK_ISO_Last_Group_Lock) || + (int) keysym == (int) MiscKeys.XK_Mode_switch) { + UpdateKeyState (xevent); + return; + } + + if ((xevent.KeyEvent.keycode >> 8) == 0x10) + xevent.KeyEvent.keycode = xevent.KeyEvent.keycode & 0xFF; + + int event_time = (int)xevent.KeyEvent.time; + + if (status == XLookupStatus.XLookupChars) { + // do not ignore those inputs. They are mostly from XIM. + msg = SendImeComposition (lookup_buffer.ToString (0, lookup_buffer.Length)); + msg.hwnd = hwnd; + return; + } + + AltGrMask = xevent.KeyEvent.state & (0x6000 | (int) KeyMasks.ModMasks); + int vkey = EventToVkey (xevent); + if (vkey == 0 && ascii_chars != 0) { + vkey = (int) VirtualKeys.VK_NONAME; + } + + if (FilterKey (xevent, vkey)) + return; + switch ((VirtualKeys) (vkey & 0xFF)) { + case VirtualKeys.VK_NUMLOCK: + GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, xevent.KeyEvent.keycode, xevent.type, event_time); + break; + case VirtualKeys.VK_CAPITAL: + GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, xevent.KeyEvent.keycode, xevent.type, event_time); + break; + default: + if (((key_state_table [(int) VirtualKeys.VK_NUMLOCK] & 0x01) == 0) != ((xevent.KeyEvent.state & NumLockMask) == 0)) { + GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, xevent.KeyEvent.keycode, XEventName.KeyPress, event_time); + GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, xevent.KeyEvent.keycode, XEventName.KeyRelease, event_time); + } + + if (((key_state_table [(int) VirtualKeys.VK_CAPITAL] & 0x01) == 0) != ((xevent.KeyEvent.state & (int) KeyMasks.LockMask) == 0)) { + GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, xevent.KeyEvent.keycode, XEventName.KeyPress, event_time); + GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, xevent.KeyEvent.keycode, XEventName.KeyRelease, event_time); + } + + num_state = false; + cap_state = false; + + int bscan = (keyc2scan [xevent.KeyEvent.keycode] & 0xFF); + KeybdEventFlags dw_flags = KeybdEventFlags.None; + if (xevent.type == XEventName.KeyRelease) + dw_flags |= KeybdEventFlags.KeyUp; + if ((vkey & 0x100) != 0) + dw_flags |= KeybdEventFlags.ExtendedKey; + msg = SendKeyboardInput ((VirtualKeys) (vkey & 0xFF), bscan, xevent.KeyEvent.keycode, dw_flags, event_time); + msg.hwnd = hwnd; + break; + } + } + + public bool TranslateMessage (ref MSG msg) + { + bool res = false; + + if (msg.message >= Msg.WM_KEYFIRST && msg.message <= Msg.WM_KEYLAST) + res = true; + + if (msg.message == Msg.WM_SYSKEYUP && msg.wParam == (IntPtr) 0x12 && menu_state) { + msg.message = Msg.WM_KEYUP; + menu_state = false; + } + + if (msg.message != Msg.WM_KEYDOWN && msg.message != Msg.WM_SYSKEYDOWN) + return res; + + if ((key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0 && msg.wParam != (IntPtr) 0x12) + menu_state = true; + + EnsureLayoutInitialized (); + + string buffer; + Msg message; + int tu = ToUnicode ((int) msg.wParam, Widget.HighOrder ((int) msg.lParam), out buffer); + switch (tu) { + case 1: + message = (msg.message == Msg.WM_KEYDOWN ? Msg.WM_CHAR : Msg.WM_SYSCHAR); + XplatUI.PostMessage (msg.hwnd, message, (IntPtr) buffer [0], msg.lParam); + break; + case -1: + message = (msg.message == Msg.WM_KEYDOWN ? Msg.WM_DEADCHAR : Msg.WM_SYSDEADCHAR); + XplatUI.PostMessage (msg.hwnd, message, (IntPtr) buffer [0], msg.lParam); + return true; + } + + return res; + } + + public int ToKeycode(int key) + { + int keycode = 0; + + if (nonchar_vkey_key[key] > 0) + keycode = XKeysymToKeycode (display, nonchar_vkey_key[key]); + + if (keycode == 0) + keycode = XKeysymToKeycode (display, key); + + return keycode; + } + + public int ToUnicode (int vkey, int scan, out string buffer) + { + if ((scan & 0x8000) != 0) { + buffer = String.Empty; + return 0; + } + + XEvent e = new XEvent (); + e.AnyEvent.type = XEventName.KeyPress; + e.KeyEvent.display = display; + e.KeyEvent.keycode = 0; + e.KeyEvent.state = 0; + + if ((key_state_table [(int) VirtualKeys.VK_SHIFT] & 0x80) != 0) { + e.KeyEvent.state |= (int) KeyMasks.ShiftMask; + } + + if ((key_state_table [(int) VirtualKeys.VK_CAPITAL] & 0x01) != 0) { + e.KeyEvent.state |= (int) KeyMasks.LockMask; + } + + if ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) != 0) { + e.KeyEvent.state |= (int) KeyMasks.ControlMask; + } + + if ((key_state_table [(int) VirtualKeys.VK_NUMLOCK] & 0x01) != 0) { + e.KeyEvent.state |= NumLockMask; + } + + e.KeyEvent.state |= AltGrMask; + + for (int keyc = min_keycode; (keyc <= max_keycode) && (e.KeyEvent.keycode == 0); keyc++) { + // find keycode that could have generated this vkey + if ((keyc2vkey [keyc] & 0xFF) == vkey) { + // filter extended bit because it is not known + e.KeyEvent.keycode = keyc; + if ((EventToVkey (e) & 0xFF) != vkey) { + // Wrong one (ex: because of num,lock state) + e.KeyEvent.keycode = 0; + } + } + } + + if ((vkey >= (int) VirtualKeys.VK_NUMPAD0) && (vkey <= (int) VirtualKeys.VK_NUMPAD9)) + e.KeyEvent.keycode = XKeysymToKeycode (display, vkey - (int) VirtualKeys.VK_NUMPAD0 + (int) KeypadKeys.XK_KP_0); + + if (vkey == (int) VirtualKeys.VK_DECIMAL) + e.KeyEvent.keycode = XKeysymToKeycode (display, (int) KeypadKeys.XK_KP_Decimal); + + if (vkey == (int) VirtualKeys.VK_SEPARATOR) + e.KeyEvent.keycode = XKeysymToKeycode(display, (int) KeypadKeys.XK_KP_Separator); + + if (e.KeyEvent.keycode == 0 && vkey != (int) VirtualKeys.VK_NONAME) { + // And I couldn't find the keycode so i returned the vkey and was like whatever + Console.Error.WriteLine ("unknown virtual key {0:X}", vkey); + buffer = String.Empty; + return vkey; + } + + XKeySym t; + XLookupStatus status; + int res = LookupString (ref e, 24, out t, out status); + int keysym = (int) t; + + buffer = String.Empty; + if (res == 0) { + int dead_char = MapDeadKeySym (keysym); + if (dead_char != 0) { + byte [] bytes = new byte [1]; + bytes [0] = (byte) dead_char; + buffer = new string (AnsiEncoding.GetChars (bytes)); + res = -1; + } + } else { + // Shift + arrow, shift + home, .... + // X returns a char for it, but windows doesn't + if (((e.KeyEvent.state & NumLockMask) == 0) && ((e.KeyEvent.state & (int) KeyMasks.ShiftMask) != 0) && + (keysym >= (int) KeypadKeys.XK_KP_0) && (keysym <= (int) KeypadKeys.XK_KP_9)) { + buffer = String.Empty; + res = 0; + } + + // CTRL + number, X returns chars, windows does not + if ((e.KeyEvent.state & (int) KeyMasks.ControlMask) != 0) { + if (((keysym >= 33) && (keysym < 'A')) || ((keysym > 'Z') && (keysym < 'a'))) { + buffer = String.Empty; + res = 0; + } + } + + // X returns a char for delete key on extended keyboards, windows does not + if (keysym == (int) TtyKeys.XK_Delete) { + buffer = String.Empty; + res = 0; + } + + if (keysym == (int) TtyKeys.XK_BackSpace && (key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) != 0) { + buffer = new string (new char [] { (char) 127 }); + + return 1; + } + + // For some special chars, such backspace and enter, looking up for a string + // can randomly fail to properly fill the buffer (either marshaling or X11), so we use + // the keysysm value to fill the gap + if (keysym == (int) XKeySym.XK_BackSpace) { + buffer = new string (new char [] { (char) 8 }); + return 1; + } + if (keysym == (int) XKeySym.XK_Return) { + buffer = new string (new char [] { (char)13 }); + return 1; + } + + if (res != 0) { + buffer = lookup_buffer.ToString (); + res = buffer.Length; + } + } + + return res; + } + + string stored_keyevent_string; + + internal string GetCompositionString () + { + return stored_keyevent_string; + } + + private MSG SendImeComposition (string s) + { + MSG msg = new MSG (); + msg.message = Msg.WM_IME_COMPOSITION; + msg.refobject = s; + stored_keyevent_string = s; + return msg; + } + + private MSG SendKeyboardInput (VirtualKeys vkey, int scan, int keycode, KeybdEventFlags dw_flags, int time) + { + Msg message; + + if ((dw_flags & KeybdEventFlags.KeyUp) != 0) { + bool sys_key = (key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0 && + ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) == 0); + key_state_table [(int) vkey] &= unchecked ((byte) ~0x80); + message = (sys_key ? Msg.WM_SYSKEYUP : Msg.WM_KEYUP); + } else { + if ((key_state_table [(int) vkey] & 0x80) == 0) { + key_state_table [(int) vkey] ^= 0x01; + } + key_state_table [(int) vkey] |= 0x80; + bool sys_key = (key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0 && + ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) == 0); + message = (sys_key ? Msg.WM_SYSKEYDOWN : Msg.WM_KEYDOWN); + } + + MSG msg = new MSG (); + msg.message = message; + msg.wParam = (IntPtr) vkey; + msg.lParam = GenerateLParam (msg, keycode); + return msg; + } + + private IntPtr GenerateLParam (MSG m, int keyCode) + { + // http://msdn.microsoft.com/en-us/library/ms646267(VS.85).aspx + // + byte flags = 0; + + if (m.message == Msg.WM_SYSKEYUP || m.message == Msg.WM_KEYUP) + flags |= 0x80; // transition state flag = 1 + + flags |= 0x40; // previous key state flag = 1 + + if ((key_state_table [(int) VirtualKeys.VK_RMENU] & 0x80) != 0 || + (key_state_table [(int) VirtualKeys.VK_LMENU] & 0x80) != 0 || + (key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0) + flags |= 0x20; // context code flag = 1 + + if ((key_state_table [(int) VirtualKeys.VK_INSERT] & 0x80) != 0 || + (key_state_table [(int) VirtualKeys.VK_DELETE] & 0x80) != 0 || + (key_state_table [(int) VirtualKeys.VK_HOME] & 0x80) != 0 || + (key_state_table [(int) VirtualKeys.VK_END] & 0x80) != 0 || + (key_state_table [(int) VirtualKeys.VK_UP] & 0x80) != 0 || + (key_state_table [(int) VirtualKeys.VK_DOWN] & 0x80) != 0 || + (key_state_table [(int) VirtualKeys.VK_LEFT] & 0x80) != 0 || + (key_state_table [(int) VirtualKeys.VK_RIGHT] & 0x80) != 0 || + (key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) != 0 || + (key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0 || + (key_state_table [(int) VirtualKeys.VK_NUMLOCK] & 0x80) != 0 || + (key_state_table [(int) VirtualKeys.VK_PRINT] & 0x80) != 0 || + (key_state_table [(int) VirtualKeys.VK_RETURN] & 0x80) != 0 || + (key_state_table [(int) VirtualKeys.VK_DIVIDE] & 0x80) != 0 || + (key_state_table [(int) VirtualKeys.VK_PRIOR] & 0x80) != 0 || + (key_state_table [(int) VirtualKeys.VK_NEXT] & 0x80) != 0) + flags |= 0x01; // extended key flag = 1 + + int lparam = ((((int)flags) & 0x000000FF) << 3*8); // message flags + lparam |= ((keyCode & 0x000000FF) << 2*8); // scan code + lparam |= 0x00000001; // repeat count = 1 + + return (IntPtr)lparam; + } + + private void GenerateMessage (VirtualKeys vkey, int scan, int key_code, XEventName type, int event_time) + { + bool state = (vkey == VirtualKeys.VK_NUMLOCK ? num_state : cap_state); + KeybdEventFlags up, down; + + if (state) { + // The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes, + // don't treat it. It's from the same key press. Then the state goes to ON. + // And from there, a 'release' event will switch off the toggle key. + SetState (vkey, false); + } else { + down = (vkey == VirtualKeys.VK_NUMLOCK ? KeybdEventFlags.ExtendedKey : KeybdEventFlags.None); + up = (vkey == VirtualKeys.VK_NUMLOCK ? KeybdEventFlags.ExtendedKey : + KeybdEventFlags.None) | KeybdEventFlags.KeyUp; + if ((key_state_table [(int) vkey] & 0x1) != 0) { // it was on + if (type != XEventName.KeyPress) { + SendKeyboardInput (vkey, scan, key_code, down, event_time); + SendKeyboardInput (vkey, scan, key_code, up, event_time); + SetState (vkey, false); + key_state_table [(int) vkey] &= unchecked ((byte) ~0x01); + } + } else { + if (type == XEventName.KeyPress) { + SendKeyboardInput (vkey, scan, key_code, down, event_time); + SendKeyboardInput (vkey, scan, key_code, up, event_time); + SetState (vkey, true); + key_state_table [(int) vkey] |= 0x01; + } + } + } + } + + private void UpdateKeyState (XEvent xevent) + { + int vkey = EventToVkey (xevent); + + switch (xevent.type) { + case XEventName.KeyRelease: + key_state_table [vkey & 0xff] &= unchecked ((byte) ~0x80); + break; + case XEventName.KeyPress: + if ((key_state_table [vkey & 0xff] & 0x80) == 0) { + key_state_table [vkey & 0xff] ^= 0x01; + } + key_state_table [vkey & 0xff] |= 0x80; + break; + } + } + + private void SetState (VirtualKeys key, bool state) + { + if (VirtualKeys.VK_NUMLOCK == key) + num_state = state; + else + cap_state = state; + } + + public int EventToVkey (XEvent e) + { + XLookupStatus status; + XKeySym ks; + + LookupString (ref e, 0, out ks, out status); + int keysym = (int) ks; + + if (((e.KeyEvent.state & NumLockMask) != 0) && + (keysym == (int)KeypadKeys.XK_KP_Separator || keysym == (int)KeypadKeys.XK_KP_Decimal || + (keysym >= (int)KeypadKeys.XK_KP_0 && keysym <= (int)KeypadKeys.XK_KP_9))) { + // Only the Keypad keys 0-9 and . send different keysyms + // depending on the NumLock state + return nonchar_key_vkey [keysym & 0xFF]; + } + + return keyc2vkey [e.KeyEvent.keycode]; + } + + private void CreateConversionArray (KeyboardLayouts layouts, KeyboardLayout layout) + { + XEvent e2 = new XEvent (); + uint keysym = 0; + int [] ckey = new int [] { 0, 0, 0, 0 }; + + e2.KeyEvent.display = display; + e2.KeyEvent.state = 0; + + for (int keyc = min_keycode; keyc <= max_keycode; keyc++) { + int vkey = 0; + int scan = 0; + + e2.KeyEvent.keycode = keyc; + XKeySym t; + + XLookupStatus status; + LookupString (ref e2, 0, out t, out status); + + keysym = (uint) t; + if (keysym != 0) { + if ((keysym >> 8) == 0xFF) { + vkey = nonchar_key_vkey [keysym & 0xFF]; + scan = nonchar_key_scan [keysym & 0xFF]; + // Set extended bit + if ((scan & 0x100) != 0) + vkey |= 0x100; + } else if (keysym == 0x20) { // spacebar + vkey = (int) VirtualKeys.VK_SPACE; + scan = 0x39; + } else { + // Search layout dependent scancodes + int maxlen = 0; + int maxval = -1;; + + for (int i = 0; i < syms; i++) { + keysym = XKeycodeToKeysym (display, keyc, i); + if ((keysym < 0x800) && (keysym != ' ')) + ckey [i] = (sbyte) (keysym & 0xFF); + else + ckey [i] = (sbyte) MapDeadKeySym ((int) keysym); + } + + for (int keyn = 0; keyn < layout.Keys.Length; keyn++) { + int ml = Math.Min (layout.Keys [keyn].Length, 4); + int ok = -1; + for (int i = 0; (ok != 0) && (i < ml); i++) { + sbyte ck = (sbyte) layout.Keys [keyn][i]; + if (ck != ckey [i]) + ok = 0; + if ((ok != 0) || (i > maxlen)) { + maxlen = i; + maxval = keyn; + } + if (ok != 0) + break; + } + } + if (maxval >= 0) { + if (maxval < layouts.scan_table [(int) layout.ScanIndex].Length) + scan = layouts.scan_table [(int) layout.ScanIndex][maxval]; + if (maxval < layouts.vkey_table [(int) layout.VKeyIndex].Length) + vkey = layouts.vkey_table [(int) layout.VKeyIndex][maxval]; + } + } + } + keyc2vkey [e2.KeyEvent.keycode] = vkey; + keyc2scan [e2.KeyEvent.keycode] = scan; + } + + + } + + private KeyboardLayout DetectLayout (KeyboardLayouts layouts) + { + XDisplayKeycodes (display, out min_keycode, out max_keycode); + IntPtr ksp = XGetKeyboardMapping (display, (byte) min_keycode, + max_keycode + 1 - min_keycode, out keysyms_per_keycode); + lock (XlibLock) { + XplatUIX11.XFree (ksp); + } + + syms = keysyms_per_keycode; + if (syms > 4) { + //Console.Error.WriteLine ("{0} keysymbols per a keycode is not supported, setting to 4", syms); + syms = 2; + } + + IntPtr modmap_unmanaged; + XModifierKeymap xmk = new XModifierKeymap (); + + modmap_unmanaged = XGetModifierMapping (display); + xmk = (XModifierKeymap) Marshal.PtrToStructure (modmap_unmanaged, typeof (XModifierKeymap)); + + int mmp = 0; + for (int i = 0; i < 8; i++) { + for (int j = 0; j < xmk.max_keypermod; j++, mmp++) { + byte b = Marshal.ReadByte (xmk.modifiermap, mmp); + if (b != 0) { + for (int k = 0; k < keysyms_per_keycode; k++) { + if ((int) XKeycodeToKeysym (display, b, k) == (int) MiscKeys.XK_Num_Lock) + NumLockMask = 1 << i; + } + } + } + } + XFreeModifiermap (modmap_unmanaged); + + int [] ckey = new int [4]; + KeyboardLayout layout = null; + int max_score = 0; + int max_seq = 0; + + foreach (KeyboardLayout current in layouts.Layouts) { + int ok = 0; + int score = 0; + int match = 0; + int mismatch = 0; + int seq = 0; + int pkey = -1; + int key = min_keycode; + int i; + + for (int keyc = min_keycode; keyc <= max_keycode; keyc++) { + for (i = 0; i < syms; i++) { + uint keysym = XKeycodeToKeysym (display, keyc, i); + + if ((keysym < 0x800) && (keysym != ' ')) { + ckey [i] = (sbyte) (keysym & 0xFF); + } else { + ckey [i] = (sbyte) MapDeadKeySym ((int) keysym); + } + } + if (ckey [0] != 0) { + for (key = 0; key < current.Keys.Length; key++) { + int ml = Math.Min (syms, current.Keys [key].Length); + for (ok = 0, i = 0; (ok >= 0) && (i < ml); i++) { + sbyte ck = (sbyte) current.Keys [key][i]; + if (ck != 0 && ck == ckey[i]) + ok++; + if (ck != 0 && ck != ckey[i]) + ok = -1; + } + if (ok > 0) { + score += ok; + break; + } + } + if (ok > 0) { + match++; + /* and how much the keycode order matches */ + if (key > pkey) + seq++; + pkey = key; + } else { + /* print spaces instead of \0's */ + mismatch++; + score -= syms; + } + } + } + + if ((score > max_score) || ((score == max_score) && (seq > max_seq))) { + // best match so far + layout = current; + max_score = score; + max_seq = seq; + } + } + + if (layout != null) { + return layout; + } else { + Console.WriteLine ("Keyboard layout not recognized, using default layout: " + + layouts.Layouts [0].Name); + } + + return layouts.Layouts [0]; + } + + // TODO + private int MapDeadKeySym (int val) + { + switch (val) { + case (int) DeadKeys.XK_dead_tilde : + case 0x1000FE7E : // Xfree's Dtilde + return '~'; + case (int) DeadKeys.XK_dead_acute : + case 0x1000FE27 : // Xfree's XK_Dacute_accent + return 0xb4; + case (int) DeadKeys.XK_dead_circumflex: + case 0x1000FE5E : // Xfree's XK_.Dcircumflex_accent + return '^'; + case (int) DeadKeys.XK_dead_grave : + case 0x1000FE60 : // Xfree's XK_.Dgrave_accent + return '`'; + case (int) DeadKeys.XK_dead_diaeresis : + case 0x1000FE22 : // Xfree's XK_.Ddiaeresis + return 0xa8; + case (int) DeadKeys.XK_dead_cedilla : + return 0xb8; + case (int) DeadKeys.XK_dead_macron : + return '-'; + case (int) DeadKeys.XK_dead_breve : + return 0xa2; + case (int) DeadKeys.XK_dead_abovedot : + return 0xff; + case (int) DeadKeys.XK_dead_abovering : + return '0'; + case (int) DeadKeys.XK_dead_doubleacute : + return 0xbd; + case (int) DeadKeys.XK_dead_caron : + return 0xb7; + case (int) DeadKeys.XK_dead_ogonek : + return 0xb2; + } + + return 0; + } + + private XIMProperties [] GetSupportedInputStyles (IntPtr xim) + { + IntPtr stylesPtr; + string ret = XGetIMValues (xim, XNames.XNQueryInputStyle, out stylesPtr, IntPtr.Zero); + if (ret != null || stylesPtr == IntPtr.Zero) + return new XIMProperties [0]; + XIMStyles styles = (XIMStyles) Marshal.PtrToStructure (stylesPtr, typeof (XIMStyles)); + XIMProperties [] supportedStyles = new XIMProperties [styles.count_styles]; + for (int i = 0; i < styles.count_styles; i++) + supportedStyles [i] = (XIMProperties) Marshal.PtrToStructure (new IntPtr ((long) styles.supported_styles + i * Marshal.SizeOf (typeof (IntPtr))), typeof (XIMProperties)); + lock (XlibLock) { + XplatUIX11.XFree (stylesPtr); + } + return supportedStyles; + } + + const XIMProperties styleRoot = XIMProperties.XIMPreeditNothing | XIMProperties.XIMStatusNothing; + const XIMProperties styleOverTheSpot = XIMProperties.XIMPreeditPosition | XIMProperties.XIMStatusNothing; + const XIMProperties styleOnTheSpot = XIMProperties.XIMPreeditCallbacks | XIMProperties.XIMStatusNothing; + const string ENV_NAME_XIM_STYLE = "MONO_WINFORMS_XIM_STYLE"; + + private XIMProperties [] GetPreferredStyles () + { + string env = Environment.GetEnvironmentVariable (ENV_NAME_XIM_STYLE); + if (env == null) + env = "over-the-spot"; + string [] list = env.Split (' '); + XIMProperties [] ret = new XIMProperties [list.Length]; + for (int i = 0; i < list.Length; i++) { + string s = list [i]; + switch (s) { + case "over-the-spot": + ret [i] = styleOverTheSpot; + break; + case "on-the-spot": + ret [i] = styleOnTheSpot; + break; + case "root": + ret [i] = styleRoot; + break; + } + } + return ret; + } + + private IEnumerable GetMatchingStylesInPreferredOrder (IntPtr xim) + { + XIMProperties [] supportedStyles = GetSupportedInputStyles (xim); + foreach (XIMProperties p in GetPreferredStyles ()) + if (Array.IndexOf (supportedStyles, p) >= 0) + yield return p; + } + + private IntPtr CreateXic (IntPtr window, IntPtr xim) + { + IntPtr xic = IntPtr.Zero; + foreach (XIMProperties targetStyle in GetMatchingStylesInPreferredOrder (xim)) { + ximStyle = targetStyle; + // FIXME: use __arglist when it gets working. See bug #321686 + switch (targetStyle) { + case styleOverTheSpot: + xic = CreateOverTheSpotXic (window, xim); + if (xic != IntPtr.Zero) + break; + //Console.WriteLine ("failed to create XIC in over-the-spot mode."); + continue; + case styleOnTheSpot: + // Since .NET/Winforms seems to support only over-the-spot mode,, + // I'm not likely to continue on-the-spot implementation. But in + // case we need it, this code will be still useful. + xic = CreateOnTheSpotXic (window, xim); + if (xic != IntPtr.Zero) + break; + //Console.WriteLine ("failed to create XIC in on-the-spot mode."); + continue; + case styleRoot: + xic = XCreateIC (xim, + XNames.XNInputStyle, styleRoot, + XNames.XNClientWindow, window, + IntPtr.Zero); + break; + } + } + // fall back to root mode if all modes failed + if (xic == IntPtr.Zero) { + ximStyle = styleRoot; + xic = XCreateIC (xim, + XNames.XNInputStyle, styleRoot, + XNames.XNClientWindow, window, + XNames.XNFocusWindow, window, + IntPtr.Zero); + } + return xic; + } + + private IntPtr CreateOverTheSpotXic (IntPtr window, IntPtr xim) + { + IntPtr list; + int count; + Widget c = Widget.FromHandle (window); + string xlfd = String.Format ("-*-*-*-*-*-*-{0}-*-*-*-*-*-*-*", (int) c.Font.Size); + IntPtr fontSet = XCreateFontSet (display, xlfd, out list, out count, IntPtr.Zero); + XPoint spot = new XPoint (); + spot.X = 0; + spot.Y = 0; + IntPtr pSL = IntPtr.Zero, pFS = IntPtr.Zero; + try { + pSL = Marshal.StringToHGlobalAnsi (XNames.XNSpotLocation); + pFS = Marshal.StringToHGlobalAnsi (XNames.XNFontSet); + IntPtr preedit = XVaCreateNestedList (0, + pSL, spot, + pFS, fontSet, + IntPtr.Zero); + return XCreateIC (xim, + XNames.XNInputStyle, styleOverTheSpot, + XNames.XNClientWindow, window, + XNames.XNPreeditAttributes, preedit, + IntPtr.Zero); + } finally { + if (pSL != IntPtr.Zero) + Marshal.FreeHGlobal (pSL); + if (pFS != IntPtr.Zero) + Marshal.FreeHGlobal (pFS); + XFreeStringList (list); + //XplatUIX11.XFree (preedit); + //XFreeFontSet (fontSet); + } + } + + private IntPtr CreateOnTheSpotXic (IntPtr window, IntPtr xim) + { + callbackContext = new XIMCallbackContext (window); + return callbackContext.CreateXic (window, xim); + } + + class XIMCallbackContext + { + XIMCallback startCB, doneCB, drawCB, caretCB; + IntPtr pStartCB = IntPtr.Zero, pDoneCB = IntPtr.Zero, pDrawCB = IntPtr.Zero, pCaretCB = IntPtr.Zero; + IntPtr pStartCBN = IntPtr.Zero, pDoneCBN = IntPtr.Zero, pDrawCBN = IntPtr.Zero, pCaretCBN = IntPtr.Zero; + + public XIMCallbackContext (IntPtr clientWindow) + { + startCB = new XIMCallback (clientWindow, DoPreeditStart); + doneCB = new XIMCallback (clientWindow, DoPreeditDone); + drawCB = new XIMCallback (clientWindow, DoPreeditDraw); + caretCB = new XIMCallback (clientWindow, DoPreeditCaret); + pStartCB = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (XIMCallback))); + pDoneCB = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (XIMCallback))); + pDrawCB = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (XIMCallback))); + pCaretCB = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (XIMCallback))); + pStartCBN = Marshal.StringToHGlobalAnsi (XNames.XNPreeditStartCallback); + pDoneCBN = Marshal.StringToHGlobalAnsi (XNames.XNPreeditDoneCallback); + pDrawCBN = Marshal.StringToHGlobalAnsi (XNames.XNPreeditDrawCallback); + pCaretCBN = Marshal.StringToHGlobalAnsi (XNames.XNPreeditCaretCallback); + } + + ~XIMCallbackContext () + { + if (pStartCBN != IntPtr.Zero) + Marshal.FreeHGlobal (pStartCBN); + if (pDoneCBN != IntPtr.Zero) + Marshal.FreeHGlobal (pDoneCBN); + if (pDrawCBN != IntPtr.Zero) + Marshal.FreeHGlobal (pDrawCBN); + if (pCaretCBN != IntPtr.Zero) + Marshal.FreeHGlobal (pCaretCBN); + + if (pStartCB != IntPtr.Zero) + Marshal.FreeHGlobal (pStartCB); + if (pDoneCB != IntPtr.Zero) + Marshal.FreeHGlobal (pDoneCB); + if (pDrawCB != IntPtr.Zero) + Marshal.FreeHGlobal (pDrawCB); + if (pCaretCB != IntPtr.Zero) + Marshal.FreeHGlobal (pCaretCB); + } + + int DoPreeditStart (IntPtr xic, IntPtr clientData, IntPtr callData) + { + Debug.WriteLine ("DoPreeditStart"); + XplatUI.SendMessage(clientData, Msg.WM_XIM_PREEDITSTART, clientData, callData); + return 100; + } + + int DoPreeditDone (IntPtr xic, IntPtr clientData, IntPtr callData) + { + Debug.WriteLine ("DoPreeditDone"); + XplatUI.SendMessage(clientData, Msg.WM_XIM_PREEDITDONE, clientData, callData); + return 0; + } + + int DoPreeditDraw (IntPtr xic, IntPtr clientData, IntPtr callData) + { + Debug.WriteLine ("DoPreeditDraw"); + XplatUI.SendMessage(clientData, Msg.WM_XIM_PREEDITDRAW, clientData, callData); + return 0; + } + + int DoPreeditCaret (IntPtr xic, IntPtr clientData, IntPtr callData) + { + Debug.WriteLine ("DoPreeditCaret"); + XplatUI.SendMessage(clientData, Msg.WM_XIM_PREEDITCARET, clientData, callData); + return 0; + } + + public IntPtr CreateXic (IntPtr window, IntPtr xim) + { + Marshal.StructureToPtr (startCB, pStartCB, false); + Marshal.StructureToPtr (doneCB, pDoneCB, false); + Marshal.StructureToPtr (drawCB, pDrawCB, false); + Marshal.StructureToPtr (caretCB, pCaretCB, false); + IntPtr preedit = XVaCreateNestedList (0, + pStartCBN, pStartCB, + pDoneCBN, pDoneCB, + pDrawCBN, pDrawCB, + pCaretCBN, pCaretCB, + IntPtr.Zero); + return XCreateIC (xim, + XNames.XNInputStyle, styleOnTheSpot, + XNames.XNClientWindow, window, + XNames.XNPreeditAttributes, preedit, + IntPtr.Zero); + } + } + + class XIMPositionContext + { + public CaretStruct Caret; + public int X; + public int Y; + } + + internal void SetCaretPos (CaretStruct caret, IntPtr handle, int x, int y) + { + if (ximStyle != styleOverTheSpot) + return; + + if (positionContext == null) + this.positionContext = new XIMPositionContext (); + + positionContext.Caret = caret; + positionContext.X = x; + positionContext.Y = y + caret.Height; + + MoveCurrentCaretPos (); + } + + internal void MoveCurrentCaretPos () + { + if (positionContext == null || ximStyle != styleOverTheSpot || client_window == IntPtr.Zero) + return; + + int x = positionContext.X; + int y = positionContext.Y; + CaretStruct caret = positionContext.Caret; + IntPtr xic = GetXic (client_window); + if (xic == IntPtr.Zero) + return; + Widget Widget = Widget.FromHandle (client_window); + if (Widget == null || !Widget.IsHandleCreated) + return; + Widget = Widget.FromHandle (caret.Hwnd); + if (Widget == null || !Widget.IsHandleCreated) + return; + Hwnd hwnd = Hwnd.ObjectFromHandle (client_window); + if (!hwnd.mapped) + return; + + int dx, dy; + IntPtr child; + lock (XlibLock) { + XplatUIX11.XTranslateCoordinates (display, client_window, client_window, x, y, out dx, out dy, out child); + } + + XPoint spot = new XPoint (); + spot.X = (short) dx; + spot.Y = (short) dy; + + IntPtr pSL = IntPtr.Zero; + try { + pSL = Marshal.StringToHGlobalAnsi (XNames.XNSpotLocation); + IntPtr preedit = XVaCreateNestedList (0, pSL, spot, IntPtr.Zero); + XSetICValues (xic, XNames.XNPreeditAttributes, preedit, IntPtr.Zero); + } finally { + if (pSL != IntPtr.Zero) + Marshal.FreeHGlobal (pSL); + } + } + + private bool have_Xutf8LookupString = true; + + private int LookupString (ref XEvent xevent, int len, out XKeySym keysym, out XLookupStatus status) + { + IntPtr keysym_res; + int res; + + status = XLookupStatus.XLookupNone; + IntPtr xic = GetXic (client_window); + if (xic != IntPtr.Zero && have_Xutf8LookupString && xevent.type == XEventName.KeyPress) { + do { + try { + res = Xutf8LookupString (xic, ref xevent, lookup_byte_buffer, 100, out keysym_res, out status); + } catch (EntryPointNotFoundException) { + have_Xutf8LookupString = false; + + // call again, this time we'll go through the non-xic clause + return LookupString (ref xevent, len, out keysym, out status); + } + if (status != XLookupStatus.XBufferOverflow) + break; + lookup_byte_buffer = new byte [lookup_byte_buffer.Length << 1]; + } while (true); + lookup_buffer.Length = 0; + string s = Encoding.UTF8.GetString (lookup_byte_buffer, 0, res); + lookup_buffer.Append (s); + keysym = (XKeySym) keysym_res.ToInt32 (); + return s.Length; + } else { + IntPtr statusPtr = IntPtr.Zero; + lookup_buffer.Length = 0; + res = XLookupString (ref xevent, lookup_buffer, len, out keysym_res, out statusPtr); + keysym = (XKeySym) keysym_res.ToInt32 (); + return res; + } + } + + [DllImport ("libX11")] + private static extern IntPtr XOpenIM (IntPtr display, IntPtr rdb, IntPtr res_name, IntPtr res_class); + + [DllImport ("libX11", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr XCreateIC (IntPtr xim, string name, XIMProperties im_style, string name2, IntPtr value2, IntPtr terminator); + [DllImport ("libX11", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr XCreateIC (IntPtr xim, string name, XIMProperties im_style, string name2, IntPtr value2, string name3, IntPtr value3, IntPtr terminator); +// [DllImport ("libX11", CallingConvention = CallingConvention.Cdecl)] +// private static extern IntPtr XCreateIC (IntPtr xim, string name, XIMProperties im_style, string name2, IntPtr value2, string name3, IntPtr value3, string name4, IntPtr value4, IntPtr terminator); + + [DllImport ("libX11", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr XVaCreateNestedList (int dummy, IntPtr name0, XPoint value0, IntPtr terminator); + [DllImport ("libX11", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr XVaCreateNestedList (int dummy, IntPtr name0, XPoint value0, IntPtr name1, IntPtr value1, IntPtr terminator); + [DllImport ("libX11", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr XVaCreateNestedList (int dummy, IntPtr name0, IntPtr value0, IntPtr name1, IntPtr value1, IntPtr name2, IntPtr value2, IntPtr name3, IntPtr value3, IntPtr terminator); + + [DllImport ("libX11")] + private static extern IntPtr XCreateFontSet (IntPtr display, string name, out IntPtr list, out int count, IntPtr terminator); + + [DllImport ("libX11")] + internal extern static void XFreeFontSet (IntPtr data); + + [DllImport ("libX11")] + private static extern void XFreeStringList (IntPtr ptr); + + //[DllImport ("libX11")] + //private static extern IntPtr XIMOfIC (IntPtr xic); + + [DllImport ("libX11")] + private static extern void XCloseIM (IntPtr xim); + + [DllImport ("libX11")] + private static extern void XDestroyIC (IntPtr xic); + + [DllImport ("libX11")] + private static extern string XGetIMValues (IntPtr xim, string name, out IntPtr value, IntPtr terminator); + + [DllImport ("libX11")] + private static extern string XGetICValues (IntPtr xic, string name, out EventMask value, IntPtr terminator); + + [DllImport ("libX11", CallingConvention = CallingConvention.Cdecl)] + private static extern void XSetICValues (IntPtr xic, string name, IntPtr value, IntPtr terminator); + + [DllImport ("libX11")] + private static extern void XSetICFocus (IntPtr xic); + + [DllImport ("libX11")] + private static extern void XUnsetICFocus (IntPtr xic); + + [DllImport ("libX11")] + private static extern string Xutf8ResetIC (IntPtr xic); + + [DllImport ("libX11")] + private static extern bool XSupportsLocale (); + + [DllImport ("libX11")] + private static extern bool XSetLocaleModifiers (string mods); + + [DllImport ("libX11")] + internal extern static int XLookupString(ref XEvent xevent, StringBuilder buffer, int num_bytes, out IntPtr keysym, out IntPtr status); + [DllImport ("libX11")] + internal extern static int Xutf8LookupString(IntPtr xic, ref XEvent xevent, byte [] buffer, int num_bytes, out IntPtr keysym, out XLookupStatus status); + + [DllImport ("libX11")] + private static extern IntPtr XGetKeyboardMapping (IntPtr display, byte first_keycode, int keycode_count, + out int keysyms_per_keycode_return); + + [DllImport ("libX11")] + private static extern void XDisplayKeycodes (IntPtr display, out int min, out int max); + + [DllImport ("libX11", EntryPoint="XKeycodeToKeysym")] + private static extern uint XKeycodeToKeysym (IntPtr display, int keycode, int index); + + [DllImport ("libX11")] + private static extern int XKeysymToKeycode (IntPtr display, IntPtr keysym); + private static int XKeysymToKeycode (IntPtr display, int keysym) { + return XKeysymToKeycode(display, (IntPtr)keysym); + } + + [DllImport ("libX11")] + internal extern static IntPtr XGetModifierMapping (IntPtr display); + + [DllImport ("libX11")] + internal extern static int XFreeModifiermap (IntPtr modmap); + + + private readonly static int [] nonchar_key_vkey = new int [] + { + /* unused */ + 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */ + /* special keys */ + (int) VirtualKeys.VK_BACK, (int) VirtualKeys.VK_TAB, 0, (int) VirtualKeys.VK_CLEAR, 0, (int) VirtualKeys.VK_RETURN, 0, 0, /* FF08 */ + 0, 0, 0, (int) VirtualKeys.VK_PAUSE, (int) VirtualKeys.VK_SCROLL, 0, 0, 0, /* FF10 */ + 0, 0, 0, (int) VirtualKeys.VK_ESCAPE, 0, 0, 0, 0, /* FF18 */ + 0, 0, (int) VirtualKeys.VK_NONCONVERT, (int) VirtualKeys.VK_CONVERT, 0, 0, 0, 0, /* FF20 */ + 0, 0, (int) VirtualKeys.VK_OEM_AUTO, 0, 0, 0, 0, 0, /* FF28 */ + /* unused */ + 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */ + /* cursor keys */ + (int) VirtualKeys.VK_HOME, (int) VirtualKeys.VK_LEFT, (int) VirtualKeys.VK_UP, (int) VirtualKeys.VK_RIGHT, /* FF50 */ + (int) VirtualKeys.VK_DOWN, (int) VirtualKeys.VK_PRIOR, (int) VirtualKeys.VK_NEXT, (int) VirtualKeys.VK_END, + 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */ + /* misc keys */ + (int) VirtualKeys.VK_SELECT, (int) VirtualKeys.VK_SNAPSHOT, (int) VirtualKeys.VK_EXECUTE, (int) VirtualKeys.VK_INSERT, 0, 0, 0, 0, /* FF60 */ + (int) VirtualKeys.VK_CANCEL, (int) VirtualKeys.VK_HELP, (int) VirtualKeys.VK_CANCEL, (int) VirtualKeys.VK_CANCEL, 0, 0, 0, 0, /* FF68 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */ + /* keypad keys */ + 0, 0, 0, 0, 0, 0, 0, (int) VirtualKeys.VK_NUMLOCK, /* FF78 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */ + 0, 0, 0, 0, 0, (int) VirtualKeys.VK_RETURN, 0, 0, /* FF88 */ + 0, 0, 0, 0, 0, (int) VirtualKeys.VK_HOME, (int) VirtualKeys.VK_LEFT, (int) VirtualKeys.VK_UP, /* FF90 */ + (int) VirtualKeys.VK_RIGHT, (int) VirtualKeys.VK_DOWN, (int) VirtualKeys.VK_PRIOR, (int) VirtualKeys.VK_NEXT, /* FF98 */ + (int) VirtualKeys.VK_END, 0, (int) VirtualKeys.VK_INSERT, (int) VirtualKeys.VK_DELETE, + 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */ + 0, 0, (int) VirtualKeys.VK_MULTIPLY, (int) VirtualKeys.VK_ADD, /* FFA8 */ + (int) VirtualKeys.VK_SEPARATOR, (int) VirtualKeys.VK_SUBTRACT, (int) VirtualKeys.VK_DECIMAL, (int) VirtualKeys.VK_DIVIDE, + (int) VirtualKeys.VK_NUMPAD0, (int) VirtualKeys.VK_NUMPAD1, (int) VirtualKeys.VK_NUMPAD2, (int) VirtualKeys.VK_NUMPAD3, /* FFB0 */ + (int) VirtualKeys.VK_NUMPAD4, (int) VirtualKeys.VK_NUMPAD5, (int) VirtualKeys.VK_NUMPAD6, (int) VirtualKeys.VK_NUMPAD7, + (int) VirtualKeys.VK_NUMPAD8, (int) VirtualKeys.VK_NUMPAD9, 0, 0, 0, 0, /* FFB8 */ + /* function keys */ + (int) VirtualKeys.VK_F1, (int) VirtualKeys.VK_F2, + (int) VirtualKeys.VK_F3, (int) VirtualKeys.VK_F4, (int) VirtualKeys.VK_F5, (int) VirtualKeys.VK_F6, (int) VirtualKeys.VK_F7, (int) VirtualKeys.VK_F8, (int) VirtualKeys.VK_F9, (int) VirtualKeys.VK_F10, /* FFC0 */ + (int) VirtualKeys.VK_F11, (int) VirtualKeys.VK_F12, (int) VirtualKeys.VK_F13, (int) VirtualKeys.VK_F14, (int) VirtualKeys.VK_F15, (int) VirtualKeys.VK_F16, 0, 0, /* FFC8 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */ + /* modifier keys */ + 0, (int) VirtualKeys.VK_SHIFT, (int) VirtualKeys.VK_SHIFT, (int) VirtualKeys.VK_CONTROL, /* FFE0 */ + (int) VirtualKeys.VK_CONTROL, (int) VirtualKeys.VK_CAPITAL, 0, (int) VirtualKeys.VK_MENU, + (int) VirtualKeys.VK_MENU, (int) VirtualKeys.VK_MENU, (int) VirtualKeys.VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */ + 0, 0, 0, 0, 0, 0, 0, (int) VirtualKeys.VK_DELETE /* FFF8 */ + }; + + private static readonly int [] nonchar_key_scan = new int [] + { + /* unused */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */ + /* special keys */ + 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */ + 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */ + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */ + /* unused */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */ + /* cursor keys */ + 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */ + /* misc keys */ + /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */ + /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */ + /* keypad keys */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */ + 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */ + 0x00, 0x00, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */ + 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */ + 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */ + /* function keys */ + 0x3B, 0x3C, + 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */ + 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */ + /* modifier keys */ + 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */ + 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */ + }; + + private readonly static int [] nonchar_vkey_key = new int [] + { + 0, 0, 0, 0, 0, /* 00-04 */ + 0, 0, 0, (int)XKeySym.XK_BackSpace, (int)XKeySym.XK_Tab, /* 05-09 */ + 0, 0, (int)XKeySym.XK_Clear, (int)XKeySym.XK_Return, 0, 0, /* 0A-0F */ + (int)XKeySym.XK_Shift_L, (int)XKeySym.XK_Control_L, (int)XKeySym.XK_Menu, 0, (int)XKeySym.XK_Caps_Lock, /* 10-14 */ + 0, 0, 0, 0, 0, /* 15-19 */ + 0, 0, 0, 0, 0, 0, /* 1A-1F */ + 0, 0, 0, (int)XKeySym.XK_End, (int)XKeySym.XK_Home, /* 20-24 */ + (int)XKeySym.XK_Left, (int)XKeySym.XK_Up, (int)XKeySym.XK_Right, (int)XKeySym.XK_Down, 0, /* 25-29 */ + 0, 0, 0, 0, 0, 0, /* 2A-2F */ + 0, 0, 0, 0, 0, /* 30-34 */ + 0, 0, 0, 0, 0, /* 35-39 */ + 0, 0, 0, 0, 0, 0, /* 3A-3F */ + 0, 0, 0, 0, 0, /* 40-44 */ + 0, 0, 0, 0, 0, /* 45-49 */ + 0, 0, 0, 0, 0, 0, /* 4A-4F */ + 0, 0, 0, 0, 0, /* 50-54 */ + 0, 0, 0, 0, 0, /* 55-59 */ + 0, (int)XKeySym.XK_Meta_L, (int)XKeySym.XK_Meta_R, 0, 0, 0, /* 5A-5F */ + 0, 0, 0, 0, 0, /* 60-64 */ + 0, 0, 0, 0, 0, /* 65-69 */ + 0, 0, 0, 0, 0, 0, /* 6A-6F */ + 0, 0, 0, 0, 0, /* 70-74 */ + 0, 0, 0, 0, 0, /* 75-79 */ + 0, 0, 0, 0, 0, 0, /* 7A-7F */ + 0, 0, 0, 0, 0, /* 80-84 */ + 0, 0, 0, 0, 0, /* 85-89 */ + 0, 0, 0, 0, 0, 0, /* 8A-8F */ + 0, 0, 0, 0, 0, /* 90-94 */ + 0, 0, 0, 0, 0, /* 95-99 */ + 0, 0, 0, 0, 0, 0, /* 9A-9F */ + (int)XKeySym.XK_Shift_L, (int)XKeySym.XK_Shift_R, (int)XKeySym.XK_Control_L, (int)XKeySym.XK_Control_R, (int)XKeySym.XK_Alt_L, /* A0-A4 */ + (int)XKeySym.XK_Alt_R, 0, 0, 0, 0, /* A5-A9 */ + 0, 0, 0, 0, 0, 0, /* AA-AF */ + 0, 0, 0, 0, 0, /* B0-B4 */ + 0, 0, 0, 0, 0, /* B5-B9 */ + 0, 0, 0, 0, 0, 0, /* BA-BF */ + 0, 0, 0, 0, 0, /* C0-C4 */ + 0, 0, 0, 0, 0, /* C5-C9 */ + 0, 0, 0, 0, 0, 0, /* CA-CF */ + 0, 0, 0, 0, 0, /* D0-D4 */ + 0, 0, 0, 0, 0, /* D5-D9 */ + 0, 0, 0, 0, 0, 0, /* DA-DF */ + 0, 0, 0, 0, 0, /* E0-E4 */ + 0, 0, 0, 0, 0, /* E5-E9 */ + 0, 0, 0, 0, 0, 0, /* EA-EF */ + 0, 0, 0, 0, 0, /* F0-F4 */ + 0, 0, 0, 0, 0, /* F5-F9 */ + 0, 0, 0, 0, 0, 0 /* FA-FF */ + }; + + } + +} + diff --git a/source/ShiftUI/Internal/X11RootHwnd.cs b/source/ShiftUI/Internal/X11RootHwnd.cs new file mode 100644 index 0000000..45a7bee --- /dev/null +++ b/source/ShiftUI/Internal/X11RootHwnd.cs @@ -0,0 +1,87 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. (http://www.novell.com) +// +// + +using System; +using System.Runtime.InteropServices; +using ShiftUI; + +namespace ShiftUI.X11Internal { + + internal class X11RootHwnd : X11Hwnd + { + public X11RootHwnd (X11Display display, IntPtr window_handle) : base (display) + { + WholeWindow = ClientWindow = window_handle; + + Xlib.XSelectInput(display.Handle, WholeWindow, new IntPtr ((int)EventMask.PropertyChangeMask)); + } + + public override void CreateWindow (CreateParams cp) + { + // we don't do anything here + } + + public override void PropertyChanged (XEvent xevent) + { + if (xevent.PropertyEvent.atom == Display.Atoms._NET_ACTIVE_WINDOW) { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + + Xlib.XGetWindowProperty (Display.Handle, WholeWindow, + Display.Atoms._NET_ACTIVE_WINDOW, IntPtr.Zero, new IntPtr (1), false, + Display.Atoms.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + + if (((long)nitems > 0) && (prop != IntPtr.Zero)) { + // FIXME - is this 64 bit clean? + Display.SetActiveWindow ((X11Hwnd)Hwnd.ObjectFromHandle((IntPtr)Marshal.ReadInt32(prop))); + Xlib.XFree(prop); + } + } + else if (xevent.PropertyEvent.atom == Display.Atoms._NET_SUPPORTED) { + // we'll need to refetch the supported protocols list + refetch_net_supported = true; + _net_supported = null; + } + else + base.PropertyChanged (xevent); + } + + bool refetch_net_supported = true; + IntPtr[] _net_supported; + public IntPtr[] _NET_SUPPORTED { + get { + if (refetch_net_supported) { + _net_supported = GetAtomListProperty (Display.Atoms._NET_SUPPORTED); + refetch_net_supported = false; + } + + return _net_supported; + } + } + } + +} + diff --git a/source/ShiftUI/Internal/X11Structs.cs b/source/ShiftUI/Internal/X11Structs.cs new file mode 100644 index 0000000..52bd880 --- /dev/null +++ b/source/ShiftUI/Internal/X11Structs.cs @@ -0,0 +1,1824 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software",, to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// NOT COMPLETE + +using System; +using System.ComponentModel; +using System.Collections; +using System.Drawing; +using System.Diagnostics; +using System.Runtime.InteropServices; + +/// X11 Version +using System.Reflection; + + +namespace ShiftUI { + // + // In the structures below, fields of type long are mapped to IntPtr. + // This will work on all platforms where sizeof(long)==sizeof(void*), which + // is almost all platforms except WIN64. + // + + [StructLayout(LayoutKind.Sequential)] + internal struct XAnyEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XKeyEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal IntPtr root; + internal IntPtr subwindow; + internal IntPtr time; + internal int x; + internal int y; + internal int x_root; + internal int y_root; + internal int state; + internal int keycode; + internal bool same_screen; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XButtonEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal IntPtr root; + internal IntPtr subwindow; + internal IntPtr time; + internal int x; + internal int y; + internal int x_root; + internal int y_root; + internal int state; + internal int button; + internal bool same_screen; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XMotionEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal IntPtr root; + internal IntPtr subwindow; + internal IntPtr time; + internal int x; + internal int y; + internal int x_root; + internal int y_root; + internal int state; + internal byte is_hint; + internal bool same_screen; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XCrossingEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal IntPtr root; + internal IntPtr subwindow; + internal IntPtr time; + internal int x; + internal int y; + internal int x_root; + internal int y_root; + internal NotifyMode mode; + internal NotifyDetail detail; + internal bool same_screen; + internal bool focus; + internal int state; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XFocusChangeEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal int mode; + internal NotifyDetail detail; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XKeymapEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal byte key_vector0; + internal byte key_vector1; + internal byte key_vector2; + internal byte key_vector3; + internal byte key_vector4; + internal byte key_vector5; + internal byte key_vector6; + internal byte key_vector7; + internal byte key_vector8; + internal byte key_vector9; + internal byte key_vector10; + internal byte key_vector11; + internal byte key_vector12; + internal byte key_vector13; + internal byte key_vector14; + internal byte key_vector15; + internal byte key_vector16; + internal byte key_vector17; + internal byte key_vector18; + internal byte key_vector19; + internal byte key_vector20; + internal byte key_vector21; + internal byte key_vector22; + internal byte key_vector23; + internal byte key_vector24; + internal byte key_vector25; + internal byte key_vector26; + internal byte key_vector27; + internal byte key_vector28; + internal byte key_vector29; + internal byte key_vector30; + internal byte key_vector31; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XExposeEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal int x; + internal int y; + internal int width; + internal int height; + internal int count; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XGraphicsExposeEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr drawable; + internal int x; + internal int y; + internal int width; + internal int height; + internal int count; + internal int major_code; + internal int minor_code; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XNoExposeEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr drawable; + internal int major_code; + internal int minor_code; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XVisibilityEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal int state; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XCreateWindowEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr parent; + internal IntPtr window; + internal int x; + internal int y; + internal int width; + internal int height; + internal int border_width; + internal bool override_redirect; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XDestroyWindowEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr xevent; + internal IntPtr window; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XUnmapEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr xevent; + internal IntPtr window; + internal bool from_configure; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XMapEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr xevent; + internal IntPtr window; + internal bool override_redirect; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XMapRequestEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr parent; + internal IntPtr window; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XReparentEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr xevent; + internal IntPtr window; + internal IntPtr parent; + internal int x; + internal int y; + internal bool override_redirect; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XConfigureEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr xevent; + internal IntPtr window; + internal int x; + internal int y; + internal int width; + internal int height; + internal int border_width; + internal IntPtr above; + internal bool override_redirect; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XGravityEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr xevent; + internal IntPtr window; + internal int x; + internal int y; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XResizeRequestEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal int width; + internal int height; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XConfigureRequestEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr parent; + internal IntPtr window; + internal int x; + internal int y; + internal int width; + internal int height; + internal int border_width; + internal IntPtr above; + internal int detail; + internal IntPtr value_mask; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XCirculateEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr xevent; + internal IntPtr window; + internal int place; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XCirculateRequestEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr parent; + internal IntPtr window; + internal int place; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XPropertyEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal IntPtr atom; + internal IntPtr time; + internal int state; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XSelectionClearEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal IntPtr selection; + internal IntPtr time; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XSelectionRequestEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr owner; + internal IntPtr requestor; + internal IntPtr selection; + internal IntPtr target; + internal IntPtr property; + internal IntPtr time; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XSelectionEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr requestor; + internal IntPtr selection; + internal IntPtr target; + internal IntPtr property; + internal IntPtr time; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XColormapEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal IntPtr colormap; + internal bool c_new; + internal int state; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XClientMessageEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal IntPtr message_type; + internal int format; + internal IntPtr ptr1; + internal IntPtr ptr2; + internal IntPtr ptr3; + internal IntPtr ptr4; + internal IntPtr ptr5; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XMappingEvent { + internal XEventName type; + internal IntPtr serial; + internal bool send_event; + internal IntPtr display; + internal IntPtr window; + internal int request; + internal int first_keycode; + internal int count; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XErrorEvent { + internal XEventName type; + internal IntPtr display; + internal IntPtr resourceid; + internal IntPtr serial; + internal byte error_code; + internal XRequest request_code; + internal byte minor_code; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XEventPad { + internal IntPtr pad0; + internal IntPtr pad1; + internal IntPtr pad2; + internal IntPtr pad3; + internal IntPtr pad4; + internal IntPtr pad5; + internal IntPtr pad6; + internal IntPtr pad7; + internal IntPtr pad8; + internal IntPtr pad9; + internal IntPtr pad10; + internal IntPtr pad11; + internal IntPtr pad12; + internal IntPtr pad13; + internal IntPtr pad14; + internal IntPtr pad15; + internal IntPtr pad16; + internal IntPtr pad17; + internal IntPtr pad18; + internal IntPtr pad19; + internal IntPtr pad20; + internal IntPtr pad21; + internal IntPtr pad22; + internal IntPtr pad23; + } + + [StructLayout(LayoutKind.Explicit)] + internal struct XEvent { + [ FieldOffset(0) ] internal XEventName type; + [ FieldOffset(0) ] internal XAnyEvent AnyEvent; + [ FieldOffset(0) ] internal XKeyEvent KeyEvent; + [ FieldOffset(0) ] internal XButtonEvent ButtonEvent; + [ FieldOffset(0) ] internal XMotionEvent MotionEvent; + [ FieldOffset(0) ] internal XCrossingEvent CrossingEvent; + [ FieldOffset(0) ] internal XFocusChangeEvent FocusChangeEvent; + [ FieldOffset(0) ] internal XExposeEvent ExposeEvent; + [ FieldOffset(0) ] internal XGraphicsExposeEvent GraphicsExposeEvent; + [ FieldOffset(0) ] internal XNoExposeEvent NoExposeEvent; + [ FieldOffset(0) ] internal XVisibilityEvent VisibilityEvent; + [ FieldOffset(0) ] internal XCreateWindowEvent CreateWindowEvent; + [ FieldOffset(0) ] internal XDestroyWindowEvent DestroyWindowEvent; + [ FieldOffset(0) ] internal XUnmapEvent UnmapEvent; + [ FieldOffset(0) ] internal XMapEvent MapEvent; + [ FieldOffset(0) ] internal XMapRequestEvent MapRequestEvent; + [ FieldOffset(0) ] internal XReparentEvent ReparentEvent; + [ FieldOffset(0) ] internal XConfigureEvent ConfigureEvent; + [ FieldOffset(0) ] internal XGravityEvent GravityEvent; + [ FieldOffset(0) ] internal XResizeRequestEvent ResizeRequestEvent; + [ FieldOffset(0) ] internal XConfigureRequestEvent ConfigureRequestEvent; + [ FieldOffset(0) ] internal XCirculateEvent CirculateEvent; + [ FieldOffset(0) ] internal XCirculateRequestEvent CirculateRequestEvent; + [ FieldOffset(0) ] internal XPropertyEvent PropertyEvent; + [ FieldOffset(0) ] internal XSelectionClearEvent SelectionClearEvent; + [ FieldOffset(0) ] internal XSelectionRequestEvent SelectionRequestEvent; + [ FieldOffset(0) ] internal XSelectionEvent SelectionEvent; + [ FieldOffset(0) ] internal XColormapEvent ColormapEvent; + [ FieldOffset(0) ] internal XClientMessageEvent ClientMessageEvent; + [ FieldOffset(0) ] internal XMappingEvent MappingEvent; + [ FieldOffset(0) ] internal XErrorEvent ErrorEvent; + [ FieldOffset(0) ] internal XKeymapEvent KeymapEvent; + + //[MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=24)] + //[ FieldOffset(0) ] internal int[] pad; + [ FieldOffset(0) ] internal XEventPad Pad; + public override string ToString() { + switch (type) + { + case XEventName.ButtonPress: + case XEventName.ButtonRelease: + return ToString (ButtonEvent); + case XEventName.CirculateNotify: + case XEventName.CirculateRequest: + return ToString (CirculateEvent); + case XEventName.ClientMessage: + return ToString (ClientMessageEvent); + case XEventName.ColormapNotify: + return ToString (ColormapEvent); + case XEventName.ConfigureNotify: + return ToString (ConfigureEvent); + case XEventName.ConfigureRequest: + return ToString (ConfigureRequestEvent); + case XEventName.CreateNotify: + return ToString (CreateWindowEvent); + case XEventName.DestroyNotify: + return ToString (DestroyWindowEvent); + case XEventName.Expose: + return ToString (ExposeEvent); + case XEventName.FocusIn: + case XEventName.FocusOut: + return ToString (FocusChangeEvent); + case XEventName.GraphicsExpose: + return ToString (GraphicsExposeEvent); + case XEventName.GravityNotify: + return ToString (GravityEvent); + case XEventName.KeymapNotify: + return ToString (KeymapEvent); + case XEventName.MapNotify: + return ToString (MapEvent); + case XEventName.MappingNotify: + return ToString (MappingEvent); + case XEventName.MapRequest: + return ToString (MapRequestEvent); + case XEventName.MotionNotify: + return ToString (MotionEvent); + case XEventName.NoExpose: + return ToString (NoExposeEvent); + case XEventName.PropertyNotify: + return ToString (PropertyEvent); + case XEventName.ReparentNotify: + return ToString (ReparentEvent); + case XEventName.ResizeRequest: + return ToString (ResizeRequestEvent); + case XEventName.SelectionClear: + return ToString (SelectionClearEvent); + case XEventName.SelectionNotify: + return ToString (SelectionEvent); + case XEventName.SelectionRequest: + return ToString (SelectionRequestEvent); + case XEventName.UnmapNotify: + return ToString (UnmapEvent); + case XEventName.VisibilityNotify: + return ToString (VisibilityEvent); + case XEventName.EnterNotify: + case XEventName.LeaveNotify: + return ToString (CrossingEvent); + default: + return type.ToString (); + } + } + + public static string ToString (object ev) + { + string result = string.Empty; + Type type = ev.GetType (); + FieldInfo [] fields = type.GetFields (System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance); + for (int i = 0; i < fields.Length; i++) { + if (result != string.Empty) { + result += ", "; + } + object value = fields [i].GetValue (ev); + result += fields [i].Name + "=" + (value == null ? "" : value.ToString ()); + } + return type.Name + " (" + result + ")"; + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XSetWindowAttributes { + internal IntPtr background_pixmap; + internal IntPtr background_pixel; + internal IntPtr border_pixmap; + internal IntPtr border_pixel; + internal Gravity bit_gravity; + internal Gravity win_gravity; + internal int backing_store; + internal IntPtr backing_planes; + internal IntPtr backing_pixel; + internal bool save_under; + internal IntPtr event_mask; + internal IntPtr do_not_propagate_mask; + internal bool override_redirect; + internal IntPtr colormap; + internal IntPtr cursor; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XWindowAttributes { + internal int x; + internal int y; + internal int width; + internal int height; + internal int border_width; + internal int depth; + internal IntPtr visual; + internal IntPtr root; + internal int c_class; + internal Gravity bit_gravity; + internal Gravity win_gravity; + internal int backing_store; + internal IntPtr backing_planes; + internal IntPtr backing_pixel; + internal bool save_under; + internal IntPtr colormap; + internal bool map_installed; + internal MapState map_state; + internal IntPtr all_event_masks; + internal IntPtr your_event_mask; + internal IntPtr do_not_propagate_mask; + internal bool override_direct; + internal IntPtr screen; + + public override string ToString () + { + return XEvent.ToString (this); + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XTextProperty { + internal string value; + internal IntPtr encoding; + internal int format; + internal IntPtr nitems; + } + + internal enum XWindowClass { + InputOutput = 1, + InputOnly = 2 + } + + internal enum XEventName { + KeyPress = 2, + KeyRelease = 3, + ButtonPress = 4, + ButtonRelease = 5, + MotionNotify = 6, + EnterNotify = 7, + LeaveNotify = 8, + FocusIn = 9, + FocusOut = 10, + KeymapNotify = 11, + Expose = 12, + GraphicsExpose = 13, + NoExpose = 14, + VisibilityNotify = 15, + CreateNotify = 16, + DestroyNotify = 17, + UnmapNotify = 18, + MapNotify = 19, + MapRequest = 20, + ReparentNotify = 21, + ConfigureNotify = 22, + ConfigureRequest = 23, + GravityNotify = 24, + ResizeRequest = 25, + CirculateNotify = 26, + CirculateRequest = 27, + PropertyNotify = 28, + SelectionClear = 29, + SelectionRequest = 30, + SelectionNotify = 31, + ColormapNotify = 32, + ClientMessage = 33, + MappingNotify = 34, + + LASTEvent + } + + [Flags] + internal enum SetWindowValuemask { + Nothing = 0, + BackPixmap = 1, + BackPixel = 2, + BorderPixmap = 4, + BorderPixel = 8, + BitGravity = 16, + WinGravity = 32, + BackingStore = 64, + BackingPlanes = 128, + BackingPixel = 256, + OverrideRedirect = 512, + SaveUnder = 1024, + EventMask = 2048, + DontPropagate = 4096, + ColorMap = 8192, + Cursor = 16384 + } + + internal enum SendEventValues { + PointerWindow = 0, + InputFocus = 1 + } + + internal enum CreateWindowArgs { + CopyFromParent = 0, + ParentRelative = 1, + InputOutput = 1, + InputOnly = 2 + } + + internal enum Gravity { + ForgetGravity = 0, + NorthWestGravity= 1, + NorthGravity = 2, + NorthEastGravity= 3, + WestGravity = 4, + CenterGravity = 5, + EastGravity = 6, + SouthWestGravity= 7, + SouthGravity = 8, + SouthEastGravity= 9, + StaticGravity = 10 + } + + internal enum XKeySym : uint { + XK_BackSpace = 0xFF08, + XK_Tab = 0xFF09, + XK_Clear = 0xFF0B, + XK_Return = 0xFF0D, + XK_Home = 0xFF50, + XK_Left = 0xFF51, + XK_Up = 0xFF52, + XK_Right = 0xFF53, + XK_Down = 0xFF54, + XK_Page_Up = 0xFF55, + XK_Page_Down = 0xFF56, + XK_End = 0xFF57, + XK_Begin = 0xFF58, + XK_Menu = 0xFF67, + XK_Shift_L = 0xFFE1, + XK_Shift_R = 0xFFE2, + XK_Control_L = 0xFFE3, + XK_Control_R = 0xFFE4, + XK_Caps_Lock = 0xFFE5, + XK_Shift_Lock = 0xFFE6, + XK_Meta_L = 0xFFE7, + XK_Meta_R = 0xFFE8, + XK_Alt_L = 0xFFE9, + XK_Alt_R = 0xFFEA, + XK_Super_L = 0xFFEB, + XK_Super_R = 0xFFEC, + XK_Hyper_L = 0xFFED, + XK_Hyper_R = 0xFFEE, + } + + [Flags] + internal enum EventMask { + NoEventMask = 0, + KeyPressMask = 1<<0, + KeyReleaseMask = 1<<1, + ButtonPressMask = 1<<2, + ButtonReleaseMask = 1<<3, + EnterWindowMask = 1<<4, + LeaveWindowMask = 1<<5, + PointerMotionMask = 1<<6, + PointerMotionHintMask = 1<<7, + Button1MotionMask = 1<<8, + Button2MotionMask = 1<<9, + Button3MotionMask = 1<<10, + Button4MotionMask = 1<<11, + Button5MotionMask = 1<<12, + ButtonMotionMask = 1<<13, + KeymapStateMask = 1<<14, + ExposureMask = 1<<15, + VisibilityChangeMask = 1<<16, + StructureNotifyMask = 1<<17, + ResizeRedirectMask = 1<<18, + SubstructureNotifyMask = 1<<19, + SubstructureRedirectMask= 1<<20, + FocusChangeMask = 1<<21, + PropertyChangeMask = 1<<22, + ColormapChangeMask = 1<<23, + OwnerGrabButtonMask = 1<<24 + } + + internal enum GrabMode { + GrabModeSync = 0, + GrabModeAsync = 1 + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XStandardColormap { + internal IntPtr colormap; + internal IntPtr red_max; + internal IntPtr red_mult; + internal IntPtr green_max; + internal IntPtr green_mult; + internal IntPtr blue_max; + internal IntPtr blue_mult; + internal IntPtr base_pixel; + internal IntPtr visualid; + internal IntPtr killid; + } + + [StructLayout(LayoutKind.Sequential, Pack=2)] + internal struct XColor { + internal IntPtr pixel; + internal ushort red; + internal ushort green; + internal ushort blue; + internal byte flags; + internal byte pad; + } + + internal enum Atom { + AnyPropertyType = 0, + XA_PRIMARY = 1, + XA_SECONDARY = 2, + XA_ARC = 3, + XA_ATOM = 4, + XA_BITMAP = 5, + XA_CARDINAL = 6, + XA_COLORMAP = 7, + XA_CURSOR = 8, + XA_CUT_BUFFER0 = 9, + XA_CUT_BUFFER1 = 10, + XA_CUT_BUFFER2 = 11, + XA_CUT_BUFFER3 = 12, + XA_CUT_BUFFER4 = 13, + XA_CUT_BUFFER5 = 14, + XA_CUT_BUFFER6 = 15, + XA_CUT_BUFFER7 = 16, + XA_DRAWABLE = 17, + XA_FONT = 18, + XA_INTEGER = 19, + XA_PIXMAP = 20, + XA_POINT = 21, + XA_RECTANGLE = 22, + XA_RESOURCE_MANAGER = 23, + XA_RGB_COLOR_MAP = 24, + XA_RGB_BEST_MAP = 25, + XA_RGB_BLUE_MAP = 26, + XA_RGB_DEFAULT_MAP = 27, + XA_RGB_GRAY_MAP = 28, + XA_RGB_GREEN_MAP = 29, + XA_RGB_RED_MAP = 30, + XA_STRING = 31, + XA_VISUALID = 32, + XA_WINDOW = 33, + XA_WM_COMMAND = 34, + XA_WM_HINTS = 35, + XA_WM_CLIENT_MACHINE = 36, + XA_WM_ICON_NAME = 37, + XA_WM_ICON_SIZE = 38, + XA_WM_NAME = 39, + XA_WM_NORMAL_HINTS = 40, + XA_WM_SIZE_HINTS = 41, + XA_WM_ZOOM_HINTS = 42, + XA_MIN_SPACE = 43, + XA_NORM_SPACE = 44, + XA_MAX_SPACE = 45, + XA_END_SPACE = 46, + XA_SUPERSCRIPT_X = 47, + XA_SUPERSCRIPT_Y = 48, + XA_SUBSCRIPT_X = 49, + XA_SUBSCRIPT_Y = 50, + XA_UNDERLINE_POSITION = 51, + XA_UNDERLINE_THICKNESS = 52, + XA_STRIKEOUT_ASCENT = 53, + XA_STRIKEOUT_DESCENT = 54, + XA_ITALIC_ANGLE = 55, + XA_X_HEIGHT = 56, + XA_QUAD_WIDTH = 57, + XA_WEIGHT = 58, + XA_POINT_SIZE = 59, + XA_RESOLUTION = 60, + XA_COPYRIGHT = 61, + XA_NOTICE = 62, + XA_FONT_NAME = 63, + XA_FAMILY_NAME = 64, + XA_FULL_NAME = 65, + XA_CAP_HEIGHT = 66, + XA_WM_CLASS = 67, + XA_WM_TRANSIENT_FOR = 68, + + XA_LAST_PREDEFINED = 68 + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XScreen { + internal IntPtr ext_data; + internal IntPtr display; + internal IntPtr root; + internal int width; + internal int height; + internal int mwidth; + internal int mheight; + internal int ndepths; + internal IntPtr depths; + internal int root_depth; + internal IntPtr root_visual; + internal IntPtr default_gc; + internal IntPtr cmap; + internal IntPtr white_pixel; + internal IntPtr black_pixel; + internal int max_maps; + internal int min_maps; + internal int backing_store; + internal bool save_unders; + internal IntPtr root_input_mask; + } + + [Flags] + internal enum ChangeWindowFlags { + CWX = 1<<0, + CWY = 1<<1, + CWWidth = 1<<2, + CWHeight = 1<<3, + CWBorderWidth = 1<<4, + CWSibling = 1<<5, + CWStackMode = 1<<6 + } + + internal enum StackMode { + Above = 0, + Below = 1, + TopIf = 2, + BottomIf = 3, + Opposite = 4 + } + + [StructLayout(LayoutKind.Sequential)] + internal struct XWindowChanges { + internal int x; + internal int y; + internal int width; + internal int height; + internal int border_width; + internal IntPtr sibling; + internal StackMode stack_mode; + } + + [Flags] + internal enum ColorFlags { + DoRed = 1<<0, + DoGreen = 1<<1, + DoBlue = 1<<2 + } + + internal enum NotifyMode { + NotifyNormal = 0, + NotifyGrab = 1, + NotifyUngrab = 2 + } + + internal enum NotifyDetail { + NotifyAncestor = 0, + NotifyVirtual = 1, + NotifyInferior = 2, + NotifyNonlinear = 3, + NotifyNonlinearVirtual = 4, + NotifyPointer = 5, + NotifyPointerRoot = 6, + NotifyDetailNone = 7 + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MotifWmHints { + internal IntPtr flags; + internal IntPtr functions; + internal IntPtr decorations; + internal IntPtr input_mode; + internal IntPtr status; + + public override string ToString () + { + return string.Format("MotifWmHints 0) { + XEvent peek = xqueue.Peek (); + if (peek.AnyEvent.type == XEventName.MotionNotify) + return; // we've already got a pending motion notify. + } + + // otherwise fall through and enqueue + // the event. + break; + } + + xqueue.Enqueue (xevent); + // wake up any thread blocking in DequeueUnlocked + Monitor.PulseAll (lockobj); + } + + public void Enqueue (XEvent xevent) + { + lock (lockobj) { + EnqueueUnlocked (xevent); + } + } + + public bool Dequeue (out XEvent xevent) + { + StartOver: + bool got_xevent = false; + + lock (lockobj) { + if (xqueue.Count > 0) { + got_xevent = true; + xevent = xqueue.Dequeue (); + } + else + xevent = new XEvent (); /* not strictly needed, but mcs complains */ + } + + if (got_xevent) { + if (xevent.AnyEvent.type == XEventName.Expose) { +#if spew + Console.Write ("E"); + Console.Out.Flush (); +#endif + X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow (xevent.AnyEvent.window); + hwnd.AddExpose (xevent.AnyEvent.window == hwnd.ClientWindow, + xevent.ExposeEvent.x, xevent.ExposeEvent.y, + xevent.ExposeEvent.width, xevent.ExposeEvent.height); + goto StartOver; + } + else if (xevent.AnyEvent.type == XEventName.ConfigureNotify) { +#if spew + Console.Write ("C"); + Console.Out.Flush (); +#endif + X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow (xevent.AnyEvent.window); + hwnd.AddConfigureNotify (xevent); + goto StartOver; + } + else { +#if spew + Console.Write ("X"); + Console.Out.Flush (); +#endif + /* it was an event we can deal with directly, return it */ + return true; + } + } + else { + if (paint_queue.Count > 0) { + xevent = paint_queue.Dequeue (); +#if spew + Console.Write ("e"); + Console.Out.Flush (); +#endif + return true; + } + else if (configure_queue.Count > 0) { + xevent = configure_queue.Dequeue (); +#if spew + Console.Write ("c"); + Console.Out.Flush (); +#endif + return true; + } + } + + if (dispatch_idle && need_dispatch_idle) { + OnIdle (EventArgs.Empty); + need_dispatch_idle = false; + } + + lock (lockobj) { + if (CountUnlocked > 0) + goto StartOver; + + if (Monitor.Wait (lockobj, NextTimeout (), true)) { + // the lock was reaquired before the + // timeout. meaning an event was + // enqueued by X11Display.XEventThread. + goto StartOver; + } + else { + CheckTimers (); + return false; + } + } + } + + public void RemovePaint (Hwnd hwnd) + { + paint_queue.Remove (hwnd); + } + + public void AddPaint (Hwnd hwnd) + { + paint_queue.Enqueue (hwnd); + } + + public void AddConfigure (Hwnd hwnd) + { + configure_queue.Enqueue (hwnd); + } + + public ConfigureQueue Configure { + get { return configure_queue; } + } + + public PaintQueue Paint { + get { return paint_queue; } + } + + public void Lock () + { + Monitor.Enter (lockobj); + } + + public void Unlock () + { + Monitor.Exit (lockobj); + } + + private int NextTimeout () + { + int timeout = Int32.MaxValue; + DateTime now = DateTime.UtcNow; + + foreach (Timer timer in timer_list) { + int next = (int) (timer.Expires - now).TotalMilliseconds; + if (next < 0) + return 0; // Have a timer that has already expired + + if (next < timeout) + timeout = next; + } + + if (timeout < Timer.Minimum) { + timeout = Timer.Minimum; + } + + if (timeout == Int32.MaxValue) + timeout = Timeout.Infinite; + + return timeout; + } + + public void CheckTimers () + { + int count; + DateTime now = DateTime.UtcNow; + + count = timer_list.Count; + + if (count == 0) + return; + + for (int i = 0; i < timer_list.Count; i++) { + Timer timer; + + timer = (Timer) timer_list [i]; + + if (timer.Enabled && timer.Expires <= now) { + timer.Update (now); + timer.FireTick (); + } + } + } + + public void SetTimer (Timer timer) + { + lock (lockobj) { + timer_list.Add (timer); + + // we need to wake up any thread waiting in DequeueUnlocked, + // since it might need to wait for a different amount of time. + Monitor.PulseAll (lockobj); + } + + } + + public void KillTimer (Timer timer) + { + lock (lockobj) { + timer_list.Remove (timer); + + // we need to wake up any thread waiting in DequeueUnlocked, + // since it might need to wait for a different amount of time. + Monitor.PulseAll (lockobj); + } + } + + public event EventHandler Idle; + public void OnIdle (EventArgs e) + { + if (Idle != null) + Idle (thread, e); + } + + public bool NeedDispatchIdle { + get { return need_dispatch_idle; } + set { need_dispatch_idle = value; } + } + + public bool DispatchIdle { + get { return dispatch_idle; } + set { dispatch_idle = value; } + } + + public bool PostQuitState { + get { return quit_posted; } + set { quit_posted = value; } + } + + public abstract class HwndEventQueue { + protected ArrayList hwnds; +#if DebugHwndEventQueue + protected ArrayList stacks; +#endif + public HwndEventQueue (int size) + { + hwnds = new ArrayList (size); +#if DebugHwndEventQueue + stacks = new ArrayList (size); +#endif + } + + public int Count { + get { return hwnds.Count; } + } + + public void Enqueue (Hwnd hwnd) + { + if (hwnds.Contains (hwnd)) { +#if DebugHwndEventQueue + Console.WriteLine ("hwnds can only appear in the queue once."); + Console.WriteLine (Environment.StackTrace); + Console.WriteLine ("originally added here:"); + Console.WriteLine (stacks[hwnds.IndexOf (hwnd)]); +#endif + + return; + } + hwnds.Add(hwnd); +#if DebugHwndEventQueue + stacks.Add(Environment.StackTrace); +#endif + } + + public void Remove(Hwnd hwnd) + { +#if DebugHwndEventQueue + int index = hwnds.IndexOf(hwnd); + if (index != -1) + stacks.RemoveAt(index); +#endif + hwnds.Remove(hwnd); + } + + protected abstract XEvent Peek (); + + public virtual XEvent Dequeue () + { + if (hwnds.Count == 0) + throw new Exception ("Attempt to dequeue empty queue."); + + return Peek (); + } + } + + + public class ConfigureQueue : HwndEventQueue + { + public ConfigureQueue (int size) : base (size) + { + } + + protected override XEvent Peek () + { + X11Hwnd hwnd = (X11Hwnd)hwnds[0]; + + XEvent xevent = new XEvent (); + xevent.AnyEvent.type = XEventName.ConfigureNotify; + + xevent.ConfigureEvent.window = hwnd.ClientWindow; + xevent.ConfigureEvent.x = hwnd.X; + xevent.ConfigureEvent.y = hwnd.Y; + xevent.ConfigureEvent.width = hwnd.Width; + xevent.ConfigureEvent.height = hwnd.Height; + + return xevent; + } + + public override XEvent Dequeue () + { + XEvent xev = base.Dequeue (); + + + hwnds.RemoveAt(0); +#if DebugHwndEventQueue + stacks.RemoveAt(0); +#endif + + return xev; + } + } + + public class PaintQueue : HwndEventQueue + { + public PaintQueue (int size) : base (size) + { + } + + protected override XEvent Peek () + { + X11Hwnd hwnd = (X11Hwnd)hwnds[0]; + + XEvent xevent = new XEvent (); + + xevent.AnyEvent.type = XEventName.Expose; + + if (hwnd.PendingExpose) { + xevent.ExposeEvent.window = hwnd.ClientWindow; + } else { + xevent.ExposeEvent.window = hwnd.WholeWindow; + xevent.ExposeEvent.x = hwnd.nc_invalid.X; + xevent.ExposeEvent.y = hwnd.nc_invalid.Y; + xevent.ExposeEvent.width = hwnd.nc_invalid.Width; + xevent.ExposeEvent.height = hwnd.nc_invalid.Height; + } + + return xevent; + } + + // don't override Dequeue like ConfigureQueue does. + } + + /* a circular queue for holding X events for processing by GetMessage */ + private class XEventQueue { + + XEvent[] xevents; + int head; + int tail; + int size; + + public XEventQueue (int initial_size) + { + if (initial_size % 2 != 0) + throw new Exception ("XEventQueue must be a power of 2 size"); + + xevents = new XEvent [initial_size]; + } + + public int Count { + get { return size; } + } + + public void Enqueue (XEvent xevent) + { + if (size == xevents.Length) + Grow (); + + xevents [tail] = xevent; + tail = (tail + 1) & (xevents.Length - 1); + size++; + } + + public XEvent Dequeue () + { + if (size < 1) + throw new Exception ("Attempt to dequeue empty queue."); + + XEvent res = xevents [head]; + head = (head + 1) & (xevents.Length - 1); + size--; + return res; + } + + public XEvent Peek() + { + if (size < 1) + throw new Exception ("Attempt to peek at empty queue."); + + return xevents[head]; + } + + private void Grow () + { + int newcap = (xevents.Length * 2); + XEvent [] na = new XEvent [newcap]; + + if (head + size > xevents.Length) { + Array.Copy (xevents, head, na, 0, xevents.Length - head); + Array.Copy (xevents, 0, na, xevents.Length - head, head + size - xevents.Length); + } + else { + Array.Copy (xevents, head, na, 0, size); + } + + xevents = na; + head = 0; + tail = head + size; + } + } + } +} + diff --git a/source/ShiftUI/Internal/XEventQueue.cs b/source/ShiftUI/Internal/XEventQueue.cs new file mode 100644 index 0000000..526c14c --- /dev/null +++ b/source/ShiftUI/Internal/XEventQueue.cs @@ -0,0 +1,261 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// ShiftUI.XEventQueue +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// Peter Dennis Bartok (pbartok@novell.com) +// + +using System; +using System.Threading; +using System.Collections; + +namespace ShiftUI { + + internal class XEventQueue { + + private XQueue xqueue; + private XQueue lqueue; // Events inserted from threads other then the main X thread + private PaintQueue paint; // Paint-only queue + internal ArrayList timer_list; + private Thread thread; + private bool dispatch_idle; + + private static readonly int InitialXEventSize = 100; + private static readonly int InitialLXEventSize = 10; + private static readonly int InitialPaintSize = 50; + + public XEventQueue (Thread thread) { + xqueue = new XQueue (InitialXEventSize); + lqueue = new XQueue (InitialLXEventSize); + paint = new PaintQueue(InitialPaintSize); + timer_list = new ArrayList (); + this.thread = thread; + this.dispatch_idle = true; + } + + public int Count { + get { + lock (lqueue) { + return xqueue.Count + lqueue.Count; + } + } + } + + public PaintQueue Paint { + get { + return paint; + } + } + + public Thread Thread { + get { + return thread; + } + } + + public void Enqueue (XEvent xevent) + { + if (Thread.CurrentThread != thread) { + Console.WriteLine ("Hwnd.Queue.Enqueue called from a different thread without locking."); + Console.WriteLine (Environment.StackTrace); + } + + xqueue.Enqueue (xevent); + } + + public void EnqueueLocked (XEvent xevent) + { + lock (lqueue) { + lqueue.Enqueue (xevent); + } + } + + public XEvent Dequeue () + { + if (Thread.CurrentThread != thread) { + Console.WriteLine ("Hwnd.Queue.Dequeue called from a different thread without locking."); + Console.WriteLine (Environment.StackTrace); + } + + if (xqueue.Count == 0) { + lock (lqueue) { + return lqueue.Dequeue (); + } + } + return xqueue.Dequeue (); + } + + public XEvent Peek() + { + if (Thread.CurrentThread != thread) { + Console.WriteLine ("Hwnd.Queue.Peek called from a different thread without locking."); + Console.WriteLine (Environment.StackTrace); + } + + if (xqueue.Count == 0) { + lock (lqueue) { + return lqueue.Peek (); + } + } + return xqueue.Peek (); + } + + public bool DispatchIdle { + get { + return dispatch_idle; + } + set { + dispatch_idle = value; + } + } + + public class PaintQueue { + + private ArrayList hwnds; + private XEvent xevent; + + public PaintQueue (int size) { + hwnds = new ArrayList (size); + xevent = new XEvent (); + xevent.AnyEvent.type = XEventName.Expose; + } + + public int Count { + get { + lock (hwnds) { + return hwnds.Count; + } + } + } + + public void Enqueue (Hwnd hwnd) { + lock (hwnds) { + hwnds.Add (hwnd); + } + } + + public void Remove(Hwnd hwnd) { + if (!hwnd.expose_pending && !hwnd.nc_expose_pending) { + lock (hwnds) { + hwnds.Remove (hwnd); + } + } + } + + public XEvent Dequeue () { + Hwnd hwnd; + IEnumerator next; + + lock (hwnds) { + if (hwnds.Count == 0) { + xevent.ExposeEvent.window = IntPtr.Zero; + return xevent; + } + + next = hwnds.GetEnumerator (); + next.MoveNext (); + hwnd = (Hwnd)next.Current; + + // We only remove the event from the queue if we have one expose left since + // a single 'entry in our queue may be for both NC and Client exposed + if (!(hwnd.nc_expose_pending && hwnd.expose_pending)) { + hwnds.Remove (hwnd); + } + if (hwnd.expose_pending) { + xevent.ExposeEvent.window = hwnd.client_window; +#if not + xevent.ExposeEvent.x = hwnd.invalid.X; + xevent.ExposeEvent.y = hwnd.invalid.Y; + xevent.ExposeEvent.width = hwnd.invalid.Width; + xevent.ExposeEvent.height = hwnd.invalid.Height; +#endif + return xevent; + } else { + xevent.ExposeEvent.window = hwnd.whole_window; + xevent.ExposeEvent.x = hwnd.nc_invalid.X; + xevent.ExposeEvent.y = hwnd.nc_invalid.Y; + xevent.ExposeEvent.width = hwnd.nc_invalid.Width; + xevent.ExposeEvent.height = hwnd.nc_invalid.Height; + return xevent; + } + } + } + } + + private class XQueue { + + private XEvent [] xevents; + private int head; + private int tail; + private int size; + + public XQueue (int size) + { + xevents = new XEvent [size]; + } + + public int Count { + get { return size; } + } + + public void Enqueue (XEvent xevent) + { + if (size == xevents.Length) + Grow (); + + xevents [tail] = xevent; + tail = (tail + 1) % xevents.Length; + size++; + } + + public XEvent Dequeue () + { + if (size < 1) + throw new Exception ("Attempt to dequeue empty queue."); + XEvent res = xevents [head]; + head = (head + 1) % xevents.Length; + size--; + return res; + } + + public XEvent Peek() { + if (size < 1) { + throw new Exception ("Attempt to peek at empty queue"); + } + return xevents[head]; + } + + private void Grow () + { + int newcap = (xevents.Length * 2); + XEvent [] na = new XEvent [newcap]; + xevents.CopyTo (na, 0); + xevents = na; + head = 0; + tail = head + size; + } + } + } +} + diff --git a/source/ShiftUI/Internal/Xlib.cs b/source/ShiftUI/Internal/Xlib.cs new file mode 100644 index 0000000..5eebd7e --- /dev/null +++ b/source/ShiftUI/Internal/Xlib.cs @@ -0,0 +1,350 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. (http://www.novell.com) +// +// + +using System; +using System.Text; +using System.Runtime.InteropServices; + +namespace ShiftUI.X11Internal { + + internal class Xlib { + const string libX11 = "X11"; + + [DllImport (libX11)] + public extern static IntPtr XOpenDisplay(IntPtr display); + + [DllImport (libX11)] + public extern static int XCloseDisplay(IntPtr display); + + [DllImport (libX11)] + public extern static IntPtr XSynchronize(IntPtr display, bool onoff); + + [DllImport (libX11)] + public extern static IntPtr XCreateWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, int depth, int xclass, IntPtr visual, UIntPtr valuemask, ref XSetWindowAttributes attributes); + + [DllImport (libX11)] + public extern static IntPtr XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, UIntPtr border, UIntPtr background); + + [DllImport (libX11)] + public extern static int XMapWindow(IntPtr display, IntPtr window); + + [DllImport (libX11)] + public extern static int XUnmapWindow(IntPtr display, IntPtr window); + + [DllImport (libX11)] + public extern static int XMapSubindows(IntPtr display, IntPtr window); + + [DllImport (libX11)] + public extern static int XUnmapSubwindows(IntPtr display, IntPtr window); + + [DllImport (libX11)] + public extern static IntPtr XRootWindow(IntPtr display, int screen_number); + + [DllImport (libX11)] + public extern static IntPtr XNextEvent(IntPtr display, ref XEvent xevent); + + [DllImport (libX11)] + public extern static int XConnectionNumber (IntPtr diplay); + + [DllImport (libX11)] + public extern static int XPending (IntPtr diplay); + + [DllImport (libX11)] + public extern static IntPtr XSelectInput(IntPtr display, IntPtr window, IntPtr mask); + + [DllImport (libX11)] + public extern static int XDestroyWindow(IntPtr display, IntPtr window); + + [DllImport (libX11)] + public extern static int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y); + + [DllImport (libX11)] + public extern static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height); + + [DllImport (libX11)] + public extern static int XResizeWindow(IntPtr display, IntPtr window, int width, int height); + + [DllImport (libX11)] + public extern static int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes); + + [DllImport (libX11)] + public extern static int XFlush(IntPtr display); + + [DllImport (libX11)] + public extern static int XSetWMName(IntPtr display, IntPtr window, ref XTextProperty text_prop); + + [DllImport (libX11)] + public extern static int XStoreName(IntPtr display, IntPtr window, string window_name); + + [DllImport (libX11)] + public extern static int XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name); + + [DllImport (libX11)] + public extern static int XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask, ref XEvent send_event); + + [DllImport (libX11)] + public extern static int XQueryTree(IntPtr display, IntPtr window, out IntPtr root_return, out IntPtr parent_return, out IntPtr children_return, out int nchildren_return); + + [DllImport (libX11)] + public extern static int XFree(IntPtr data); + + [DllImport (libX11)] + public extern static int XRaiseWindow(IntPtr display, IntPtr window); + + [DllImport (libX11)] + public extern static uint XLowerWindow(IntPtr display, IntPtr window); + + [DllImport (libX11)] + public extern static uint XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values); + + [DllImport (libX11)] + public extern static IntPtr XInternAtom(IntPtr display, string atom_name, bool only_if_exists); + + [DllImport (libX11)] + public extern static int XInternAtoms(IntPtr display, string[] atom_names, int atom_count, bool only_if_exists, IntPtr[] atoms); + + [DllImport (libX11)] + public extern static int XSetWMProtocols(IntPtr display, IntPtr window, IntPtr[] protocols, int count); + + [DllImport (libX11)] + public extern static int XGrabPointer(IntPtr display, IntPtr window, bool owner_events, EventMask event_mask, GrabMode pointer_mode, GrabMode keyboard_mode, IntPtr confine_to, IntPtr cursor, IntPtr timestamp); + + [DllImport (libX11)] + public extern static int XUngrabPointer(IntPtr display, IntPtr timestamp); + + [DllImport (libX11)] + public extern static bool XQueryPointer(IntPtr display, IntPtr window, out IntPtr root, out IntPtr child, out int root_x, out int root_y, out int win_x, out int win_y, out int keys_buttons); + + [DllImport (libX11)] + public extern static bool XTranslateCoordinates (IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, out int intdest_x_return, out int dest_y_return, out IntPtr child_return); + + [DllImport (libX11)] + public extern static bool XGetGeometry(IntPtr display, IntPtr window, out IntPtr root, out int x, out int y, out int width, out int height, out int border_width, out int depth); + + [DllImport (libX11)] + public extern static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, out int width, out int height, IntPtr border_width, IntPtr depth); + + [DllImport (libX11)] + public extern static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, IntPtr width, IntPtr height, IntPtr border_width, IntPtr depth); + + [DllImport (libX11)] + public extern static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, IntPtr x, IntPtr y, out int width, out int height, IntPtr border_width, IntPtr depth); + + [DllImport (libX11)] + public extern static uint XWarpPointer(IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, uint src_width, uint src_height, int dest_x, int dest_y); + + [DllImport (libX11)] + public extern static int XClearWindow(IntPtr display, IntPtr window); + + [DllImport (libX11)] + public extern static int XClearArea(IntPtr display, IntPtr window, int x, int y, int width, int height, bool exposures); + + // Colormaps + [DllImport (libX11)] + public extern static IntPtr XDefaultScreenOfDisplay(IntPtr display); + + [DllImport (libX11)] + public extern static int XScreenNumberOfScreen(IntPtr display, IntPtr Screen); + + [DllImport (libX11)] + public extern static IntPtr XDefaultVisual(IntPtr display, int screen_number); + + [DllImport (libX11)] + public extern static uint XDefaultDepth(IntPtr display, int screen_number); + + [DllImport (libX11)] + public extern static int XDefaultScreen(IntPtr display); + + [DllImport (libX11)] + public extern static IntPtr XDefaultColormap(IntPtr display, int screen_number); + + [DllImport (libX11)] + public extern static int XLookupColor(IntPtr display, IntPtr Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color); + + [DllImport (libX11)] + public extern static int XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def); + + [DllImport (libX11)] + public extern static int XSetTransientForHint(IntPtr display, IntPtr window, IntPtr prop_window); + + [DllImport (libX11)] + public extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref MotifWmHints data, int nelements); + + [DllImport (libX11)] + public extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref uint value, int nelements); + + [DllImport (libX11)] + public extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref IntPtr value, int nelements); + + [DllImport (libX11)] + public extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, uint[] data, int nelements); + + [DllImport (libX11)] + public extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, int[] data, int nelements); + + [DllImport (libX11)] + public extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr[] data, int nelements); + + [DllImport (libX11)] + public extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr atoms, int nelements); + + [DllImport (libX11, CharSet=CharSet.Ansi)] + public extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, string text, int text_length); + + [DllImport (libX11)] + public extern static int XDeleteProperty(IntPtr display, IntPtr window, IntPtr property); + + // Drawing + [DllImport (libX11)] + public extern static IntPtr XCreateGC(IntPtr display, IntPtr window, IntPtr valuemask, ref XGCValues values); + + [DllImport (libX11)] + public extern static int XFreeGC(IntPtr display, IntPtr gc); + + [DllImport (libX11)] + public extern static int XSetFunction(IntPtr display, IntPtr gc, GXFunction function); + + [DllImport (libX11)] + internal extern static int XSetLineAttributes(IntPtr display, IntPtr gc, int line_width, GCLineStyle line_style, GCCapStyle cap_style, GCJoinStyle join_style); + + [DllImport (libX11)] + public extern static int XDrawLine(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2); + + [DllImport (libX11)] + public extern static int XDrawRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height); + + [DllImport (libX11)] + public extern static int XFillRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height); + + [DllImport (libX11)] + public extern static int XSetWindowBackground(IntPtr display, IntPtr window, IntPtr background); + + [DllImport (libX11)] + public extern static int XCopyArea(IntPtr display, IntPtr src, IntPtr dest, IntPtr gc, int src_x, int src_y, int width, int height, int dest_x, int dest_y); + + [DllImport (libX11)] + public extern static int XGetWindowProperty(IntPtr display, IntPtr window, IntPtr atom, IntPtr long_offset, IntPtr long_length, bool delete, IntPtr req_type, out IntPtr actual_type, out int actual_format, out IntPtr nitems, out IntPtr bytes_after, ref IntPtr prop); + + [DllImport (libX11)] + public extern static int XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time); + + [DllImport (libX11)] + public extern static int XIconifyWindow(IntPtr display, IntPtr window, int screen_number); + + [DllImport (libX11)] + public extern static int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor); + + [DllImport (libX11)] + public extern static int XUndefineCursor(IntPtr display, IntPtr window); + + [DllImport (libX11)] + public extern static int XFreeCursor(IntPtr display, IntPtr cursor); + + [DllImport (libX11)] + public extern static IntPtr XCreateFontCursor(IntPtr display, CursorFontShape shape); + + [DllImport (libX11)] + public extern static IntPtr XCreatePixmapCursor(IntPtr display, IntPtr source, IntPtr mask, ref XColor foreground_color, ref XColor background_color, int x_hot, int y_hot); + + [DllImport (libX11)] + public extern static IntPtr XCreatePixmapFromBitmapData(IntPtr display, IntPtr drawable, byte[] data, int width, int height, IntPtr fg, IntPtr bg, int depth); + + [DllImport (libX11)] + public extern static IntPtr XCreatePixmap(IntPtr display, IntPtr d, int width, int height, int depth); + + [DllImport (libX11)] + public extern static IntPtr XFreePixmap(IntPtr display, IntPtr pixmap); + + [DllImport (libX11)] + public extern static int XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, out int best_width, out int best_height); + + [DllImport (libX11)] + public extern static IntPtr XWhitePixel(IntPtr display, int screen_no); + + [DllImport (libX11)] + public extern static IntPtr XBlackPixel(IntPtr display, int screen_no); + + [DllImport (libX11)] + public extern static void XGrabServer(IntPtr display); + + [DllImport (libX11)] + public extern static void XUngrabServer(IntPtr display); + + [DllImport (libX11)] + public extern static void XGetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints, out IntPtr supplied_return); + + [DllImport (libX11)] + public extern static void XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints); + + [DllImport (libX11)] + public extern static void XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints); + + [DllImport (libX11)] + public extern static void XSetWMHints(IntPtr display, IntPtr window, ref XWMHints wmhints); + + [DllImport (libX11)] + public extern static int XGetIconSizes(IntPtr display, IntPtr window, out IntPtr size_list, out int count); + + [DllImport (libX11)] + public extern static IntPtr XSetErrorHandler(XErrorHandler error_handler); + + [DllImport (libX11)] + public extern static IntPtr XGetErrorText(IntPtr display, byte code, StringBuilder buffer, int length); + + [DllImport (libX11)] + public extern static int XInitThreads(); + + [DllImport (libX11)] + public extern static int XConvertSelection(IntPtr display, IntPtr selection, IntPtr target, IntPtr property, IntPtr requestor, IntPtr time); + + [DllImport (libX11)] + public extern static IntPtr XGetSelectionOwner(IntPtr display, IntPtr selection); + + [DllImport (libX11)] + public extern static int XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, IntPtr time); + + [DllImport (libX11)] + public extern static int XSetPlaneMask(IntPtr display, IntPtr gc, IntPtr mask); + + [DllImport (libX11)] + public extern static int XSetForeground(IntPtr display, IntPtr gc, UIntPtr foreground); + + [DllImport (libX11)] + public extern static int XSetBackground(IntPtr display, IntPtr gc, UIntPtr background); + + [DllImport (libX11)] + public extern static int XBell(IntPtr display, int percent); + + [DllImport (libX11)] + public extern static int XChangeActivePointerGrab (IntPtr display, EventMask event_mask, IntPtr cursor, IntPtr time); + + [DllImport (libX11)] + public extern static bool XFilterEvent(ref XEvent xevent, IntPtr window); + + [DllImport (libX11)] + public extern static void XkbSetDetectableAutoRepeat (IntPtr display, bool detectable, IntPtr supported); + + [DllImport (libX11)] + public extern static void XPeekEvent (IntPtr display, ref XEvent xevent); + } +} diff --git a/source/ShiftUI/Internal/XplatUI.cs b/source/ShiftUI/Internal/XplatUI.cs new file mode 100644 index 0000000..afa3ddb --- /dev/null +++ b/source/ShiftUI/Internal/XplatUI.cs @@ -0,0 +1,1235 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com + +// NOT COMPLETE + +// define to log API calls to stdout +#undef DriverDebug +#undef DriverDebugPaint +#undef DriverDebugCreate +#undef DriverDebugDestroy +#undef DriverDebugState + +using System; +using System.Drawing; +using System.ComponentModel; +using System.Collections; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Threading; + +namespace ShiftUI { + internal class XplatUI { + #region Local Variables + static XplatUIDriver driver; + //static String default_class_name; + internal static ArrayList key_filters = new ArrayList (); + #endregion // Local Variables + + public static string DefaultClassName { + get { return GetDefaultClassName(); } + } + + #region Private Methods + internal static string Window (IntPtr handle) + { + return String.Format ("'{0}' ({1:X})", Widget.FromHandle (handle), handle.ToInt32 ()); + } + + [Conditional ("DriverDebug")] + static void DriverDebug (string format, params object [] args) + { + Console.WriteLine (String.Format (format, args)); + } + + #endregion // Private Methods + + #region Subclasses + public class State { + static public Keys ModifierKeys { + get { + return driver.ModifierKeys; + } + } + + static public MouseButtons MouseButtons { + get { + return driver.MouseButtons; + } + } + + static public Point MousePosition { + get { + return driver.MousePosition; + } + } + + } + #endregion // Subclasses + + #region Constructor & Destructor + static XplatUI () + { + // Compose name with current domain id because on Win32 we register class name + // and name must be unique to process. If we load MWF into multiple appdomains + // and try to register same class name we fail. + //default_class_name = "SWFClass" + System.Threading.Thread.GetDomainID ().ToString (); + try { + if (RunningOnUnix) { + //if (Environment.GetEnvironmentVariable ("not_supported_MONO_MWF_USE_NEW_X11_BACKEND") != null) { + // driver=XplatUIX11_new.GetInstance (); + //} else + if (Environment.GetEnvironmentVariable ("MONO_MWF_MAC_FORCE_X11") != null) { + driver = XplatUIX11.GetInstance (); + } else { + IntPtr buf = Marshal.AllocHGlobal (8192); + // This is a hacktastic way of getting sysname from uname () + if (uname (buf) != 0) { + // WTF: We cannot run uname + driver=XplatUIX11.GetInstance (); + } else { + string os = Marshal.PtrToStringAnsi (buf); + if (os == "Darwin") + driver=XplatUICarbon.GetInstance (); + else + driver=XplatUIX11.GetInstance (); + } + Marshal.FreeHGlobal (buf); + } + } else { + driver=XplatUIWin32.GetInstance (); + } + + driver.InitializeDriver (); + + // Initialize things that need to be done after the driver is ready + DataFormats.GetFormat (0); + + // Signal that the Application loop can be run. + // This allows UIA to initialize a11y support for MWF + // before the main loop begins. + Application.FirePreRun (); + } + catch (Exception ex) { + Console.WriteLine ("[ShiftUI/XplatUI] Driver init error: {0}", ex.Message); + } + } + #endregion // Constructor & Destructor + + #region Public Static Properties + + public static bool RunningOnUnix { + get { + int p = (int) Environment.OSVersion.Platform; + + return (p == 4 || p == 6 || p == 128); + } + } + + public static int ActiveWindowTrackingDelay { + get { return driver.ActiveWindowTrackingDelay; } + } + + // Compose name with current domain id because on Win32 we register class name + // and name must be unique to process. If we load MWF into multiple appdomains + // and try to register same class name we fail. + internal static string GetDefaultClassName (Type type) + { + return "SWFClass" + Thread.GetDomainID ().ToString () + "." + type.ToString (); + } + + // Generate a class name using current domain and a random number. + internal static string GetDefaultClassName () + { + return "SWFClass" + Thread.GetDomainID ().ToString () + "." + new Random().Next(0, 9999999).ToString(); + } + + + static public Size Border3DSize { + get { + return driver.Border3DSize; + } + } + + static public Size BorderSize { + get { + return driver.BorderSize; + } + } + + static public Size CaptionButtonSize { + get { + return driver.CaptionButtonSize; + } + } + + static public int CaptionHeight { + get { + return driver.CaptionHeight; + } + } + + public static int CaretBlinkTime { get { return driver.CaretBlinkTime; } } + public static int CaretWidth { get { return driver.CaretWidth; } } + + static public Size CursorSize { + get { + return driver.CursorSize; + } + } + + static public Size DoubleClickSize { + get { + return driver.DoubleClickSize; + } + } + + static public int DoubleClickTime { + get { + return driver.DoubleClickTime; + } + } + + static public bool DragFullWindows { + get { + return driver.DragFullWindows; + } + } + + static public Size DragSize { + get { + return driver.DragSize; + } + } + + static public Size FixedFrameBorderSize { + get { + return driver.FixedFrameBorderSize; + } + } + + public static int FontSmoothingContrast { get { return driver.FontSmoothingContrast; } } + public static int FontSmoothingType { get { return driver.FontSmoothingType; } } + + public static Size FrameBorderSize { + get { + return driver.FrameBorderSize; + } + } + + public static int HorizontalResizeBorderThickness { get { return driver.HorizontalResizeBorderThickness; } } + + static public int HorizontalScrollBarHeight { + get { + return driver.HorizontalScrollBarHeight; + } + } + + static public Size IconSize { + get { + return driver.IconSize; + } + } + + public static bool IsActiveWindowTrackingEnabled { get { return driver.IsActiveWindowTrackingEnabled; } } + public static bool IsComboBoxAnimationEnabled { get { return driver.IsComboBoxAnimationEnabled; } } + public static bool IsDropShadowEnabled { get { return driver.IsDropShadowEnabled; } } + public static bool IsFontSmoothingEnabled { get { return driver.IsFontSmoothingEnabled; } } + public static bool IsHotTrackingEnabled { get { return driver.IsHotTrackingEnabled; } } + public static bool IsIconTitleWrappingEnabled { get { return driver.IsIconTitleWrappingEnabled; } } + public static bool IsKeyboardPreferred { get { return driver.IsKeyboardPreferred; } } + public static bool IsListBoxSmoothScrollingEnabled { get { return driver.IsListBoxSmoothScrollingEnabled; } } + public static bool IsMenuAnimationEnabled { get { return driver.IsMenuAnimationEnabled; } } + public static bool IsMenuFadeEnabled { get { return driver.IsMenuFadeEnabled; } } + public static bool IsMinimizeRestoreAnimationEnabled { get { return driver.IsMinimizeRestoreAnimationEnabled; } } + public static bool IsSelectionFadeEnabled { get { return driver.IsSelectionFadeEnabled; } } + public static bool IsSnapToDefaultEnabled { get { return driver.IsSnapToDefaultEnabled; } } + public static bool IsTitleBarGradientEnabled { get { return driver.IsTitleBarGradientEnabled; } } + public static bool IsToolTipAnimationEnabled { get { return driver.IsToolTipAnimationEnabled; } } + + static public int KeyboardSpeed { + get { + return driver.KeyboardSpeed; + } + } + + static public int KeyboardDelay { + get { + return driver.KeyboardDelay; + } + } + + static public Size MaxWindowTrackSize { + get { + return driver.MaxWindowTrackSize; + } + } + + static public bool MenuAccessKeysUnderlined { + get { + return driver.MenuAccessKeysUnderlined; + } + } + + static public Size MenuBarButtonSize { get { return driver.MenuBarButtonSize; } } + + public static Size MenuButtonSize { + get { + return driver.MenuButtonSize; + } + } + + static public int MenuShowDelay { get { return driver.MenuShowDelay; } } + + static public Size MinimizedWindowSize { + get { + return driver.MinimizedWindowSize; + } + } + + static public Size MinimizedWindowSpacingSize { + get { + return driver.MinimizedWindowSpacingSize; + } + } + + static public Size MinimumWindowSize { + get { + return driver.MinimumWindowSize; + } + } + + static public Size MinimumFixedToolWindowSize { + get { return driver.MinimumFixedToolWindowSize; } + } + + static public Size MinimumSizeableToolWindowSize { + get { return driver.MinimumSizeableToolWindowSize; } + } + + static public Size MinimumNoBorderWindowSize { + get { return driver.MinimumNoBorderWindowSize; } + } + + static public Size MinWindowTrackSize { + get { + return driver.MinWindowTrackSize; + } + } + + public static int MouseSpeed { + get { return driver.MouseSpeed; } + } + + static public Size SmallIconSize { + get { + return driver.SmallIconSize; + } + } + + static public int MenuHeight { + get { + return driver.MenuHeight; + } + } + + static public int MouseButtonCount { + get { + return driver.MouseButtonCount; + } + } + + static public bool MouseButtonsSwapped { + get { + return driver.MouseButtonsSwapped; + } + } + + static public Size MouseHoverSize { + get { + return driver.MouseHoverSize; + } + } + + static public int MouseHoverTime { + get { + return driver.MouseHoverTime; + } + } + + static public int MouseWheelScrollDelta { + get { + return driver.MouseWheelScrollDelta; + } + } + + static public bool MouseWheelPresent { + get { + return driver.MouseWheelPresent; + } + } + + public static LeftRightAlignment PopupMenuAlignment { + get { return driver.PopupMenuAlignment; } + } + + public static PowerStatus PowerStatus { + get { return driver.PowerStatus; } + } + + public static bool RequiresPositiveClientAreaSize { + get { + return driver.RequiresPositiveClientAreaSize; + } + } + + public static int SizingBorderWidth { + get { return driver.SizingBorderWidth; } + } + + public static Size SmallCaptionButtonSize { + get { return driver.SmallCaptionButtonSize; } + } + + public static bool UIEffectsEnabled { + get { return driver.UIEffectsEnabled; } + } + + static public bool UserClipWontExposeParent { + get { + return driver.UserClipWontExposeParent; + } + } + + public static int VerticalResizeBorderThickness { get { return driver.VerticalResizeBorderThickness; } } + + static public int VerticalScrollBarWidth { + get { + return driver.VerticalScrollBarWidth; + } + } + + static public Rectangle VirtualScreen { + get { + return driver.VirtualScreen; + } + } + + static public Rectangle WorkingArea { + get { + return driver.WorkingArea; + } + } + + public static Screen[] AllScreens { + get { + return driver.AllScreens; + } + } + + public static bool ThemesEnabled { + get { + return XplatUI.driver.ThemesEnabled; + } + } + + public static int ToolWindowCaptionHeight { + get { + return driver.ToolWindowCaptionHeight; + } + } + + public static Size ToolWindowCaptionButtonSize { + get { + return driver.ToolWindowCaptionButtonSize; + } + } + #endregion // Public Static Properties + + #region Events + + internal static event EventHandler Idle { + add { + driver.Idle += value; + } + remove { + driver.Idle -= value; + } + } + + #endregion // Events + + #region Public Static Methods + internal static void Activate (IntPtr handle) + { + DriverDebug ("Activate ({0}): Called", Window (handle)); + driver.Activate (handle); + } + + internal static void AudibleAlert (AlertType alert) + { + DriverDebug ("AudibleAlert (): Called"); + driver.AudibleAlert (alert); + } + + internal static void BeginMoveResize (IntPtr handle) + { + driver.BeginMoveResize (handle); + } + + internal static bool CalculateWindowRect (ref Rectangle ClientRect, CreateParams cp, Menu menu, out Rectangle WindowRect) + { + DriverDebug ("CalculateWindowRect ({0}, {1}, {2}): Called", ClientRect, cp, menu); + return driver.CalculateWindowRect (ref ClientRect, cp, menu, out WindowRect); + } + + internal static void CaretVisible (IntPtr handle, bool visible) + { + DriverDebug ("CaretVisible ({0:X}, {1}): Called", handle.ToInt32 (), visible); + driver.CaretVisible (handle, visible); + } + + internal static void CreateCaret (IntPtr handle, int width, int height) + { + DriverDebug ("CreateCaret ({0:X}), {1}, {2}: Called", handle.ToInt32 (), width, height); + driver.CreateCaret (handle, width, height); + } + + internal static IntPtr CreateWindow (CreateParams cp) + { + #if DriverDebug || DriverDebugCreate + IntPtr handle; + + handle = driver.CreateWindow (cp); + + Console.WriteLine ("CreateWindow (): Called, returning {0:X}", handle.ToInt32 ()); + return handle; + #else + return driver.CreateWindow (cp); + #endif + } + + internal static IntPtr CreateWindow (IntPtr Parent, int X, int Y, int Width, int Height) + { + #if DriverDebug || DriverDebugCreate + Console.WriteLine ("CreateWindow (): Called"); + #endif + return driver.CreateWindow (Parent, X, Y, Width, Height); + } + + internal static void ClientToScreen (IntPtr handle, ref int x, ref int y) + { + #if DriverDebug + Console.WriteLine ("ClientToScreen ({0}, {1}, {2}): Called", Window (handle), x, y); + #endif + driver.ClientToScreen (handle, ref x, ref y); + } + + internal static int[] ClipboardAvailableFormats (IntPtr handle) + { + DriverDebug ("ClipboardAvailableTypes ({0:X}): Called", handle.ToInt32 ()); + return driver.ClipboardAvailableFormats (handle); + } + + internal static void ClipboardClose (IntPtr handle) + { + DriverDebug ("ClipboardClose ({0:X}): Called", handle.ToInt32 ()); + driver.ClipboardClose (handle); + } + + internal static int ClipboardGetID (IntPtr handle, string format) + { + DriverDebug ("ClipboardGetID ({0:X}, {1}): Called", handle.ToInt32 (), format); + return driver.ClipboardGetID (handle, format); + } + + internal static IntPtr ClipboardOpen (bool primary_selection) + { + DriverDebug ("ClipboardOpen (): Called"); + return driver.ClipboardOpen (primary_selection); + } + + internal static void ClipboardStore (IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter, bool copy) + { + DriverDebug ("ClipboardStore ({0:X}, {1}, {2}, {3}, {4}): Called", handle.ToInt32 (), obj, type, converter, copy); + driver.ClipboardStore (handle, obj, type, converter, copy); + } + + internal static object ClipboardRetrieve (IntPtr handle, int type, XplatUI.ClipboardToObject converter) + { + DriverDebug ("ClipboardRetrieve ({0:X}, type, {1}): Called", handle.ToInt32 (), converter); + return driver.ClipboardRetrieve (handle, type, converter); + } + + internal static IntPtr DefineCursor (Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) + { + DriverDebug ("DefineCursor (...): Called"); + return driver.DefineCursor (bitmap, mask, cursor_pixel, mask_pixel, xHotSpot, yHotSpot); + } + + internal static IntPtr DefineStdCursor (StdCursor id) + { + return driver.DefineStdCursor (id); + } + + internal static Bitmap DefineStdCursorBitmap (StdCursor id) + { + return driver.DefineStdCursorBitmap (id); + } + + internal static IntPtr DefWndProc (ref Message msg) + { + return driver.DefWndProc (ref msg); + } + + internal static void DestroyCaret (IntPtr handle) + { + DriverDebug ("DestroyCaret ({0:X}): Called", handle.ToInt32 ()); + driver.DestroyCaret (handle); + } + + internal static void DestroyCursor (IntPtr cursor) + { + DriverDebug ("DestroyCursor ({0:X}): Called", cursor.ToInt32 ()); + driver.DestroyCursor (cursor); + } + + internal static void DestroyWindow (IntPtr handle) + { + DriverDebug ("DestroyWindow ({0}): Called", Window (handle)); + driver.DestroyWindow (handle); + } + + internal static IntPtr DispatchMessage (ref MSG msg) + { + return driver.DispatchMessage (ref msg); + } + + internal static void DoEvents () + { + driver.DoEvents (); + } + + internal static void DrawReversibleRectangle (IntPtr handle, Rectangle rect, int line_width) + { + DriverDebug ("DrawReversibleRectangle ({0}, {1}, {2}): Called", Window (handle), rect, line_width); + driver.DrawReversibleRectangle (handle, rect, line_width); + } + + internal static void FillReversibleRectangle (Rectangle rectangle, Color backColor) + { + DriverDebug ("FillReversibleRectangle ({0}, {1}): Called", rectangle, backColor); + driver.FillReversibleRectangle (rectangle, backColor); + } + + internal static void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style) + { + DriverDebug ("DrawReversibleFrame ({0}, {1}, {2}): Called", rectangle, backColor, style); + driver.DrawReversibleFrame (rectangle, backColor, style); + } + + internal static void DrawReversibleLine (Point start, Point end, Color backColor) + { + DriverDebug ("DrawReversibleLine ({0}, {1}, {2}): Called", start, end, backColor); + driver.DrawReversibleLine (start, end, backColor); + } + + internal static void EnableThemes () + { + driver.EnableThemes (); + } + + internal static void EnableWindow (IntPtr handle, bool Enable) + { + DriverDebug ("EnableWindow ({0}, {1}): Called", Window (handle), Enable); + driver.EnableWindow (handle, Enable); + } + + internal static void EndLoop (Thread thread) + { + DriverDebug ("EndLoop ({0:X}): Called", thread.GetHashCode ()); + driver.EndLoop (thread); + } + + internal static IntPtr GetActive () + { + DriverDebug ("GetActive (): Called"); + return driver.GetActive (); + } + + internal static SizeF GetAutoScaleSize (Font font) + { + DriverDebug ("GetAutoScaleSize ({0}): Called", font); + return driver.GetAutoScaleSize (font); + } + + internal static Region GetClipRegion (IntPtr handle) + { + DriverDebug ("GetClipRegion ({0}): Called", Window (handle)); + return driver.GetClipRegion (handle); + } + + internal static void GetCursorInfo (IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y) + { + DriverDebug ("GetCursorInfo ({0}): Called", cursor.ToInt32 ()); + driver.GetCursorInfo (cursor, out width, out height, out hotspot_x, out hotspot_y); + } + + internal static void GetCursorPos (IntPtr handle, out int x, out int y) + { + DriverDebug ("GetCursorPos ({0}): Called", Window (handle)); + driver.GetCursorPos (handle, out x, out y); + } + + internal static void GetDisplaySize (out Size size) + { + DriverDebug ("GetDisplaySize (): Called"); + driver.GetDisplaySize (out size); + } + + internal static IntPtr GetFocus () + { + DriverDebug ("GetFocus (): Called, Result:{0}", Window (driver.GetFocus ())); + return driver.GetFocus (); + } + + internal static bool GetFontMetrics (Graphics g, Font font, out int ascent, out int descent) + { + DriverDebug ("GetFontMetrics (): Called"); + return driver.GetFontMetrics (g, font, out ascent, out descent); + } + + internal static Point GetMenuOrigin (IntPtr handle) + { + DriverDebug ("GetMenuOrigin ({0}): Called", Window (handle)); + return driver.GetMenuOrigin (handle); + } + + internal static bool GetMessage (object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax) + { + return driver.GetMessage (queue_id, ref msg, hWnd, wFilterMin, wFilterMax); + } + + internal static IntPtr GetParent (IntPtr handle) + { + DriverDebug ("GetParent ({0}): Called", Window (handle)); + return driver.GetParent (handle); + } + + internal static IntPtr GetPreviousWindow (IntPtr handle) + { + return driver.GetPreviousWindow (handle); + } + + internal static bool GetText (IntPtr handle, out string text) + { + DriverDebug ("GetText ({0}): Called", Window (handle)); + return driver.GetText (handle, out text); + } + + internal static void GetWindowPos (IntPtr handle, bool is_toplevel, out int x, out int y, out int width, out int height, out int client_width, out int client_height) + { + DriverDebug ("GetWindowPos ({0}): Called", Window (handle)); + driver.GetWindowPos (handle, is_toplevel, out x, out y, out width, out height, out client_width, out client_height); + } + + /* this method can (and does, on X11) return + * (FormWindowState) (-1), when the state of the window + * cannot be determined (in the X11 case, when the + * window isn't mapped.) Checking for the additional + * return value is less expensive than + * throwing/catching an exception. */ + internal static FormWindowState GetWindowState (IntPtr handle) + { + DriverDebug ("GetWindowState ({0}): Called", Window (handle)); + return driver.GetWindowState (handle); + } + + internal static void GrabInfo (out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea) + { + DriverDebug ("GrabInfo (): Called"); + driver.GrabInfo (out handle, out GrabConfined, out GrabArea); + } + + internal static void GrabWindow (IntPtr handle, IntPtr ConfineToHwnd) + { + DriverDebug ("GrabWindow ({0}, {1}): Called", Window (handle), Window (ConfineToHwnd)); + driver.GrabWindow (handle, ConfineToHwnd); + } + + internal static void HandleException (Exception e) + { + driver.HandleException (e); + } + + internal static void Invalidate (IntPtr handle, Rectangle rc, bool clear) + { + DriverDebug ("Invalidate ({0}, {1}, {2}): Called", Window (handle), rc, clear); + driver.Invalidate (handle, rc, clear); + } + + internal static void InvalidateNC (IntPtr handle) + { + DriverDebug ("InvalidateNC ({0}): Called", Window (handle)); + driver.InvalidateNC (handle); + } + + + internal static bool IsEnabled (IntPtr handle) + { + #if DriverDebug || DriverDebugState + Console.WriteLine ("IsEnabled ({0}): Called, Result={1}", Window (handle), driver.IsEnabled (handle)); + #endif + return driver.IsEnabled (handle); + } + + internal static bool IsKeyLocked (VirtualKeys key) + { + #if DriverDebug || DriverDebugState + Console.WriteLine ("IsKeyLocked ({0}): Called, Result={1}", key, driver.IsKeyLocked (key)); + #endif + return driver.IsKeyLocked (key); + } + + internal static bool IsVisible (IntPtr handle) + { + #if DriverDebug || DriverDebugState + Console.WriteLine ("IsVisible ({0}): Called, Result={1}", Window (handle), driver.IsVisible (handle)); + #endif + return driver.IsVisible (handle); + } + + internal static void KillTimer (Timer timer) + { + DriverDebug ("KillTimer ({0}): Called", timer); + driver.KillTimer (timer); + } + + internal static void MenuToScreen (IntPtr handle, ref int x, ref int y) + { + DriverDebug ("MenuToScreen ({0}, {1}, {2}): Called", Window (handle), x, y); + driver.MenuToScreen (handle, ref x, ref y); + } + + internal static void OverrideCursor (IntPtr cursor) + { + DriverDebug ("OverrideCursor ({0:X}): Called", cursor.ToInt32 ()); + driver.OverrideCursor (cursor); + } + + internal static void PaintEventEnd (ref Message msg, IntPtr handle, bool client) + { + #if DriverDebug || DriverDebugPaint + Console.WriteLine ("PaintEventEnd ({0}, {1}, {2}): Called from thread {3}", msg, Window (handle), client, Thread.CurrentThread.GetHashCode ()); + #endif + driver.PaintEventEnd (ref msg, handle, client); + } + + internal static PaintEventArgs PaintEventStart (ref Message msg, IntPtr handle, bool client) + { + #if DriverDebug || DriverDebugPaint + Console.WriteLine ("PaintEventStart ({0}, {1}, {2}): Called from thread {3}", msg, Window (handle), client, Thread.CurrentThread.GetHashCode ()); + #endif + return driver.PaintEventStart (ref msg, handle, client); + } + + internal static bool PeekMessage (Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) + { + return driver.PeekMessage (queue_id, ref msg, hWnd, wFilterMin, wFilterMax, flags); + } + + internal static bool PostMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam) + { + DriverDebug ("PostMessage ({0}, {1}, {2:X}, {3:X}): Called", Window (hwnd), message, wParam.ToInt32 (), lParam.ToInt32 ()); + return driver.PostMessage (hwnd, message, wParam, lParam); + } + + internal static bool PostMessage (ref MSG msg) + { + DriverDebug ("PostMessage ({0}): Called", msg); + return driver.PostMessage (msg.hwnd, msg.message, msg.wParam, msg.lParam); + } + + internal static void PostQuitMessage (int exitCode) + { + DriverDebug ("PostQuitMessage ({0}): Called", exitCode); + driver.PostQuitMessage (exitCode); + } + + internal static void RaiseIdle (EventArgs e) + { + DriverDebug ("RaiseIdle ({0}): Called", e.ToString ()); + + driver.RaiseIdle (e); + } + + internal static void RequestAdditionalWM_NCMessages (IntPtr handle, bool hover, bool leave) + { + DriverDebug ("RequestAdditionalWM_NCMessages ({0}, {1}, {2}): Called", Window (handle), hover, leave); + driver.RequestAdditionalWM_NCMessages (handle, hover, leave); + } + + internal static void RequestNCRecalc (IntPtr handle) + { + DriverDebug ("RequestNCRecalc ({0}): Called", Window (handle)); + driver.RequestNCRecalc (handle); + } + + internal static void ResetMouseHover (IntPtr handle) + { + DriverDebug ("ResetMouseHover ({0}): Called", Window (handle)); + driver.ResetMouseHover (handle); + } + + internal static void ScreenToClient (IntPtr handle, ref int x, ref int y) + { + DriverDebug ("ScreenToClient ({0}, {1}, {2}): Called", Window (handle), x, y); + driver.ScreenToClient (handle, ref x, ref y); + } + + internal static void ScreenToMenu (IntPtr handle, ref int x, ref int y) + { + DriverDebug ("ScreenToMenu ({0}, {1}, {2}): Called", Window (handle), x, y); + driver.ScreenToMenu (handle, ref x, ref y); + } + + internal static void ScrollWindow (IntPtr handle, Rectangle rectangle, int XAmount, int YAmount, bool with_children) + { + DriverDebug ("ScrollWindow ({0}, {1}, {2}, {3}, {4}): Called", Window (handle), rectangle, XAmount, YAmount, with_children); + driver.ScrollWindow (handle, rectangle, XAmount, YAmount, with_children); + } + + internal static void ScrollWindow (IntPtr handle, int XAmount, int YAmount, bool with_children) + { + DriverDebug ("ScrollWindow ({0}, {1}, {2}, {3}): Called", Window (handle), XAmount, YAmount, with_children); + driver.ScrollWindow (handle, XAmount, YAmount, with_children); + } + + internal static void SendAsyncMethod (AsyncMethodData data) + { + DriverDebug ("SendAsyncMethod ({0}): Called", data); + driver.SendAsyncMethod (data); + } + + internal static int SendInput (IntPtr hwnd, Queue keys) + { + DriverDebug ("SendInput ({0}, {1}): Called", hwnd, keys); + return driver.SendInput (hwnd, keys); + } + + internal static IntPtr SendMessage (IntPtr handle, Msg message, IntPtr wParam, IntPtr lParam) + { + DriverDebug ("SendMessage ({0}, {1}, {2:X}, {3:X}): Called", Window (handle), message, wParam.ToInt32 (), lParam.ToInt32 ()); + return driver.SendMessage (handle, message, wParam, lParam); + } + + internal static void SendMessage (ref Message m) + { + DriverDebug ("SendMessage ({0}): Called", m); + m.Result = driver.SendMessage (m.HWnd, (Msg)m.Msg, m.WParam, m.LParam); + } + + internal static void SetAllowDrop (IntPtr handle, bool value) + { + DriverDebug ("SetAllowDrop ({0}, {1}): Called", handle, value); + driver.SetAllowDrop (handle, value); + } + + internal static void SetBorderStyle (IntPtr handle, FormBorderStyle border_style) + { + DriverDebug ("SetBorderStyle ({0}, {1}): Called", Window (handle), border_style); + driver.SetBorderStyle (handle, border_style); + } + + internal static void SetCaretPos (IntPtr handle, int x, int y) + { + DriverDebug ("SetCaretPos ({0}, {1}, {2}): Called", Window (handle), x, y); + driver.SetCaretPos (handle, x, y); + } + + internal static void SetClipRegion (IntPtr handle, Region region) + { + DriverDebug ("SetClipRegion ({0}, {1}): Called", Window (handle), region); + driver.SetClipRegion (handle, region); + } + + internal static void SetCursor (IntPtr handle, IntPtr cursor) + { + DriverDebug ("SetCursor ({0}, {1:X}): Called", Window (handle), cursor.ToInt32 ()); + driver.SetCursor (handle, cursor); + } + + internal static void SetCursorPos (IntPtr handle, int x, int y) + { + DriverDebug ("SetCursorPos ({0}, {1}, {2}): Called", Window (handle), x, y); + driver.SetCursorPos (handle, x, y); + } + + internal static void SetFocus (IntPtr handle) + { + DriverDebug ("SetFocus ({0}): Called", Window (handle)); + driver.SetFocus (handle); + } + + internal static void SetForegroundWindow (IntPtr handle) + { + DriverDebug ("SetForegroundWindow ({0}): Called", Window (handle)); + driver.SetForegroundWindow (handle); + } + + internal static void SetIcon (IntPtr handle, Icon icon) + { + DriverDebug ("SetIcon ({0}, {1}): Called", Window (handle), icon); + driver.SetIcon (handle, icon); + } + + internal static void SetMenu (IntPtr handle, Menu menu) + { + DriverDebug ("SetMenu ({0}, {1}): Called", Window (handle), menu); + driver.SetMenu (handle, menu); + } + + internal static void SetModal (IntPtr handle, bool Modal) + { + DriverDebug ("SetModal ({0}, {1}): Called", Window (handle), Modal); + driver.SetModal (handle, Modal); + } + + internal static IntPtr SetParent (IntPtr handle, IntPtr hParent) + { + DriverDebug ("SetParent ({0}, {1:X}): Called", Window (handle), Window (hParent)); + return driver.SetParent (handle, hParent); + } + + internal static void SetTimer (Timer timer) + { + DriverDebug ("SetTimer ({0}): Called", timer); + driver.SetTimer (timer); + } + + internal static bool SetTopmost (IntPtr handle, bool Enabled) + { + DriverDebug ("SetTopMost ({0}, {1}): Called", Window (handle), Enabled); + return driver.SetTopmost (handle, Enabled); + } + + internal static bool SetOwner (IntPtr handle, IntPtr hWndOwner) + { + DriverDebug ("SetOwner ({0}, {1}): Called", Window (handle), Window (hWndOwner)); + return driver.SetOwner (handle, hWndOwner); + } + + internal static bool SetVisible (IntPtr handle, bool visible, bool activate) + { + #if DriverDebug || DriverDebugState + Console.WriteLine ("SetVisible ({0}, {1}, {2}): Called", Window (handle), visible, activate); + #endif + return driver.SetVisible (handle, visible, activate); + } + + internal static void SetWindowMinMax (IntPtr handle, Rectangle maximized, Size min, Size max) + { + #if DriverDebug || DriverDebugState + Console.WriteLine ("SetWindowMinMax ({0}, {1}, {2}, {3}): Called", Window (handle), maximized, min, max); + #endif + driver.SetWindowMinMax (handle, maximized, min, max); + } + + internal static void SetWindowPos (IntPtr handle, int x, int y, int width, int height) + { + DriverDebug ("SetWindowPos ({0}, {1}, {2}, {3}, {4}): Called", Window (handle), x, y, width, height); + driver.SetWindowPos (handle, x, y, width, height); + } + + internal static void SetWindowState (IntPtr handle, FormWindowState state) + { + #if DriverDebug || DriverDebugState + Console.WriteLine ("SetWindowState ({0} {1}): Called", Window (handle), state); + #endif + driver.SetWindowState (handle, state); + } + + internal static void SetWindowStyle (IntPtr handle, CreateParams cp) + { + DriverDebug ("SetWindowStyle ({0}): Called", Window (handle)); + driver.SetWindowStyle (handle, cp); + } + + internal static double GetWindowTransparency (IntPtr handle) + { + DriverDebug ("SetWindowTransparency ({0}): Called", Window (handle)); + return driver.GetWindowTransparency (handle); + } + + internal static void SetWindowTransparency (IntPtr handle, double transparency, Color key) + { + DriverDebug ("SetWindowTransparency ({0}): Called", Window (handle)); + driver.SetWindowTransparency (handle, transparency, key); + } + + internal static bool SetZOrder (IntPtr handle, IntPtr AfterhWnd, bool Top, bool Bottom) + { + DriverDebug ("SetZOrder ({0}, {1:X}, {2}, {3}): Called", Window (handle), Window (AfterhWnd), Top, Bottom); + return driver.SetZOrder (handle, AfterhWnd, Top, Bottom); + } + + internal static void ShowCursor (bool show) + { + DriverDebug ("ShowCursor ({0}): Called", show); + driver.ShowCursor (show); + } + + internal static DragDropEffects StartDrag (IntPtr handle, object data, DragDropEffects allowedEffects) + { + DriverDebug ("StartDrag ({0}, {1}, {2}): Called", Window (handle), data, allowedEffects); + return driver.StartDrag (handle, data, allowedEffects); + } + + internal static object StartLoop (Thread thread) + { + DriverDebug ("StartLoop ({0:X}): Called", thread.GetHashCode ()); + return driver.StartLoop (thread); + } + + internal static TransparencySupport SupportsTransparency () + { + DriverDebug ("SupportsTransparency (): Called, result={0}", driver.SupportsTransparency ()); + return driver.SupportsTransparency (); + } + + internal static bool SystrayAdd (IntPtr handle, string tip, Icon icon, out ToolTip tt) + { + DriverDebug ("SystrayAdd ({0}, {1}): Called", Window (handle), tip); + return driver.SystrayAdd (handle, tip, icon, out tt); + } + + internal static void SystrayChange (IntPtr handle, string tip, Icon icon, ref ToolTip tt) + { + DriverDebug ("SystrayChange ({0}, {1}): Called", Window (handle), tip); + driver.SystrayChange (handle, tip, icon, ref tt); + } + + internal static void SystrayRemove (IntPtr handle, ref ToolTip tt) + { + DriverDebug ("SystrayRemove ({0}): Called", Window (handle)); + driver.SystrayRemove (handle, ref tt); + } + + internal static void SystrayBalloon (IntPtr handle, int timeout, string title, string text, ToolTipIcon icon) + { + DriverDebug ("SystrayBalloon ({0}, {1}, {2}, {3}, {4}): Called", Window (handle), timeout, title, text, icon); + driver.SystrayBalloon (handle, timeout, title, text, icon); + } + + internal static bool Text (IntPtr handle, string text) + { + DriverDebug ("Text ({0}, {1}): Called", Window (handle), text); + return driver.Text (handle, text); + } + + internal static bool TranslateMessage (ref MSG msg) + { + return driver.TranslateMessage (ref msg); + } + + internal static void UngrabWindow (IntPtr handle) + { + DriverDebug ("UngrabWindow ({0}): Called", Window (handle)); + driver.UngrabWindow (handle); + } + + internal static void UpdateWindow (IntPtr handle) + { + DriverDebug ("UpdateWindow ({0}): Called", Window (handle)); + driver.UpdateWindow (handle); + } + + // double buffering + internal static void CreateOffscreenDrawable (IntPtr handle, + int width, int height, + out object offscreen_drawable) + { + DriverDebug ("CreateOffscreenDrawable ({2}, {0},{1}): Called", width, height, Window (handle)); + driver.CreateOffscreenDrawable (handle, width, height, + out offscreen_drawable); + } + + internal static void DestroyOffscreenDrawable (object offscreen_drawable) + { + DriverDebug ("DestroyOffscreenDrawable (): Called"); + driver.DestroyOffscreenDrawable (offscreen_drawable); + } + + internal static Graphics GetOffscreenGraphics (object offscreen_drawable) + { + DriverDebug ("GetOffscreenGraphics (): Called"); + return driver.GetOffscreenGraphics (offscreen_drawable); + } + + internal static void BlitFromOffscreen (IntPtr dest_handle, + Graphics dest_dc, + object offscreen_drawable, + Graphics offscreen_dc, + Rectangle r) + { + DriverDebug ("BlitFromOffscreen ({0}): Called", Window (dest_handle)); + driver.BlitFromOffscreen (dest_handle, dest_dc, offscreen_drawable, offscreen_dc, r); + } + + + // Santa's little helper + internal static void Version () + { + Console.WriteLine ("Xplat version $Revision: $"); + } + + internal static void AddKeyFilter (IKeyFilter value) + { + lock (key_filters) { + key_filters.Add (value); + } + } + + internal static bool FilterKey (KeyFilterData key) + { + lock (key_filters) { + for (int i = 0; i < key_filters.Count; i++) { + IKeyFilter filter = (IKeyFilter) key_filters[i]; + if (filter.PreFilterKey (key)) + return true; + } + } + return false; + } + #endregion // Public Static Methods + + #region Delegates + public delegate bool ClipboardToObject (int type, IntPtr data, out object obj); + public delegate bool ObjectToClipboard (ref int type, object obj, out byte[] data); + #endregion // Delegates + + [DllImport ("libc")] + static extern int uname (IntPtr buf); + } +} diff --git a/source/ShiftUI/Internal/XplatUICarbon.cs b/source/ShiftUI/Internal/XplatUICarbon.cs new file mode 100644 index 0000000..ec1b53a --- /dev/null +++ b/source/ShiftUI/Internal/XplatUICarbon.cs @@ -0,0 +1,2432 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2007 Novell, Inc. +// +// Authors: +// Geoff Norton +// +// + +using System; +using System.Threading; +using System.Drawing; +using System.ComponentModel; +using System.Collections; +using System.Diagnostics; +using System.Runtime.InteropServices; + +using Carbon = ShiftUI.CarbonInternal; + +/// Carbon Version +using ShiftUI; + + +namespace ShiftUI { + internal delegate Rectangle [] HwndDelegate (IntPtr handle); + + internal class XplatUICarbon : XplatUIDriver { + #region Local Variables + // General driver variables + private static XplatUICarbon Instance; + private static int RefCount; + private static bool themes_enabled; + + // Internal members available to the event handler sub-system + internal static IntPtr FocusWindow; + internal static IntPtr ActiveWindow; + internal static IntPtr UnactiveWindow; + internal static IntPtr ReverseWindow; + internal static IntPtr CaretWindow; + + internal static Hwnd MouseHwnd; + + internal static MouseButtons MouseState; + internal static Carbon.Hover Hover; + + internal static HwndDelegate HwndDelegate = new HwndDelegate (GetClippingRectangles); + // Instance members + internal Point mouse_position; + + // Event handlers + internal Carbon.ApplicationHandler ApplicationHandler; + internal Carbon.WidgetHandler WidgetHandler; + internal Carbon.HIObjectHandler HIObjectHandler; + internal Carbon.KeyboardHandler KeyboardHandler; + internal Carbon.MouseHandler MouseHandler; + internal Carbon.WindowHandler WindowHandler; + + // Carbon Specific + internal static GrabStruct Grab; + internal static Carbon.Caret Caret; + private static Carbon.Dnd Dnd; + private static Hashtable WindowMapping; + private static Hashtable HandleMapping; + private static IntPtr FosterParent; + private static IntPtr Subclass; + private static int MenuBarHeight; + internal static ArrayList UtilityWindows; + + // Message loop + private static Queue MessageQueue; + private static bool GetMessageResult; + + private static bool ReverseWindowMapped; + + // Timers + private ArrayList TimerList; + private static bool in_doevents; + + static readonly object instancelock = new object (); + static readonly object queuelock = new object (); + + // Event Handlers + internal override event EventHandler Idle; + #endregion + + #region Constructors + private XplatUICarbon() { + + RefCount = 0; + TimerList = new ArrayList (); + in_doevents = false; + MessageQueue = new Queue (); + + Initialize (); + } + + ~XplatUICarbon() { + // FIXME: Clean up the FosterParent here. + } + #endregion + + #region Singleton specific code + public static XplatUICarbon GetInstance() { + lock (instancelock) { + if (Instance == null) { + Instance = new XplatUICarbon (); + } + RefCount++; + } + return Instance; + } + + public int Reference { + get { + return RefCount; + } + } + #endregion + + #region Internal methods + internal void AddExpose (Hwnd hwnd, bool client, Carbon.HIRect rect) { + AddExpose (hwnd, client, (int) rect.origin.x, (int) rect.origin.y, (int) rect.size.width, (int) rect.size.height); + } + + internal void AddExpose (Hwnd hwnd, bool client, Rectangle rect) { + AddExpose (hwnd, client, (int) rect.X, (int) rect.Y, (int) rect.Width, (int) rect.Height); + } + + internal void FlushQueue () { + CheckTimers (DateTime.UtcNow); + lock (queuelock) { + while (MessageQueue.Count > 0) { + object queueobj = MessageQueue.Dequeue (); + if (queueobj is GCHandle) { + XplatUIDriverSupport.ExecuteClientMessage((GCHandle)queueobj); + } else { + MSG msg = (MSG)queueobj; + NativeWindow.WndProc (msg.hwnd, msg.message, msg.wParam, msg.lParam); + } + } + } + } + + internal static Rectangle [] GetClippingRectangles (IntPtr handle) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd == null) + return null; + if (hwnd.Handle != handle) + return new Rectangle [] {hwnd.ClientRect}; + + return (Rectangle []) hwnd.GetClippingRectangles ().ToArray (typeof (Rectangle)); + } + + internal IntPtr GetMousewParam(int Delta) { + int result = 0; + + if ((MouseState & MouseButtons.Left) != 0) { + result |= (int)MsgButtons.MK_LBUTTON; + } + + if ((MouseState & MouseButtons.Middle) != 0) { + result |= (int)MsgButtons.MK_MBUTTON; + } + + if ((MouseState & MouseButtons.Right) != 0) { + result |= (int)MsgButtons.MK_RBUTTON; + } + + Keys mods = ModifierKeys; + if ((mods & Keys.Widget) != 0) { + result |= (int)MsgButtons.MK_CONTROL; + } + + if ((mods & Keys.Shift) != 0) { + result |= (int)MsgButtons.MK_SHIFT; + } + + result |= Delta << 16; + + return (IntPtr)result; + } + + internal IntPtr HandleToWindow (IntPtr handle) { + if (HandleMapping [handle] != null) + return (IntPtr) HandleMapping [handle]; + return IntPtr.Zero; + } + + internal void Initialize () { + if (Marshal.SizeOf () == 8){ + Console.Error.WriteLine ("WARNING: The Carbon driver has not been ported to 64bits, and very few parts of Windows.Forms will work properly, or at all"); + } + // Initialize the event handlers + Carbon.EventHandler.Driver = this; + ApplicationHandler = new Carbon.ApplicationHandler (this); + WidgetHandler = new Carbon.WidgetHandler (this); + HIObjectHandler = new Carbon.HIObjectHandler (this); + KeyboardHandler = new Carbon.KeyboardHandler (this); + MouseHandler = new Carbon.MouseHandler (this); + WindowHandler = new Carbon.WindowHandler (this); + + // Initilize the mouse Widgets + Hover.Interval = 500; + Hover.Timer = new Timer (); + Hover.Timer.Enabled = false; + Hover.Timer.Interval = Hover.Interval; + Hover.Timer.Tick += new EventHandler (HoverCallback); + Hover.X = -1; + Hover.Y = -1; + MouseState = MouseButtons.None; + mouse_position = Point.Empty; + + // Initialize the Caret + Caret.Timer = new Timer (); + Caret.Timer.Interval = 500; + Caret.Timer.Tick += new EventHandler (CaretCallback); + + // Initialize the D&D + Dnd = new Carbon.Dnd (); + + // Initialize the Carbon Specific stuff + WindowMapping = new Hashtable (); + HandleMapping = new Hashtable (); + UtilityWindows = new ArrayList (); + + // Initialize the FosterParent + Carbon.Rect rect = new Carbon.Rect (); + SetRect (ref rect, (short)0, (short)0, (short)0, (short)0); + Carbon.ProcessSerialNumber psn = new Carbon.ProcessSerialNumber(); + + GetCurrentProcess( ref psn ); + TransformProcessType (ref psn, 1); + SetFrontProcess (ref psn); + + HIObjectRegisterSubclass (__CFStringMakeConstantString ("com.novell.mwfview"), __CFStringMakeConstantString ("com.apple.hiview"), 0, Carbon.EventHandler.EventHandlerDelegate, (uint)Carbon.EventHandler.HIObjectEvents.Length, Carbon.EventHandler.HIObjectEvents, IntPtr.Zero, ref Subclass); + + Carbon.EventHandler.InstallApplicationHandler (); + + CreateNewWindow (Carbon.WindowClass.kDocumentWindowClass, Carbon.WindowAttributes.kWindowStandardHandlerAttribute | Carbon.WindowAttributes.kWindowCloseBoxAttribute | Carbon.WindowAttributes.kWindowFullZoomAttribute | Carbon.WindowAttributes.kWindowCollapseBoxAttribute | Carbon.WindowAttributes.kWindowResizableAttribute | Carbon.WindowAttributes.kWindowCompositingAttribute, ref rect, ref FosterParent); + + CreateNewWindow (Carbon.WindowClass.kOverlayWindowClass, Carbon.WindowAttributes.kWindowNoUpdatesAttribute | Carbon.WindowAttributes.kWindowNoActivatesAttribute, ref rect, ref ReverseWindow); + CreateNewWindow (Carbon.WindowClass.kOverlayWindowClass, Carbon.WindowAttributes.kWindowNoUpdatesAttribute | Carbon.WindowAttributes.kWindowNoActivatesAttribute, ref rect, ref CaretWindow); + + // Get some values about bar heights + Carbon.Rect structRect = new Carbon.Rect (); + Carbon.Rect contentRect = new Carbon.Rect (); + GetWindowBounds (FosterParent, 32, ref structRect); + GetWindowBounds (FosterParent, 33, ref contentRect); + + MenuBarHeight = GetMBarHeight (); + + // Focus + FocusWindow = IntPtr.Zero; + + // Message loop + GetMessageResult = true; + + ReverseWindowMapped = false; + } + + internal void PerformNCCalc(Hwnd hwnd) { + XplatUIWin32.NCCALCSIZE_PARAMS ncp; + IntPtr ptr; + Rectangle rect; + + rect = new Rectangle (0, 0, hwnd.Width, hwnd.Height); + + ncp = new XplatUIWin32.NCCALCSIZE_PARAMS(); + ptr = Marshal.AllocHGlobal(Marshal.SizeOf(ncp)); + + ncp.rgrc1.left = rect.Left; + ncp.rgrc1.top = rect.Top; + ncp.rgrc1.right = rect.Right; + ncp.rgrc1.bottom = rect.Bottom; + + Marshal.StructureToPtr(ncp, ptr, true); + NativeWindow.WndProc(hwnd.client_window, Msg.WM_NCCALCSIZE, (IntPtr)1, ptr); + ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(ptr, typeof(XplatUIWin32.NCCALCSIZE_PARAMS)); + Marshal.FreeHGlobal(ptr); + + + rect = new Rectangle(ncp.rgrc1.left, ncp.rgrc1.top, ncp.rgrc1.right - ncp.rgrc1.left, ncp.rgrc1.bottom - ncp.rgrc1.top); + hwnd.ClientRect = rect; + + rect = TranslateClientRectangleToQuartzClientRectangle (hwnd); + + if (hwnd.visible) { + Carbon.HIRect r = new Carbon.HIRect (rect.X, rect.Y, rect.Width, rect.Height); + HIViewSetFrame (hwnd.client_window, ref r); + } + + AddExpose (hwnd, false, 0, 0, hwnd.Width, hwnd.Height); + } + + internal void ScreenToClient(IntPtr handle, ref Carbon.QDPoint point) { + int x = (int) point.x; + int y = (int) point.y; + + ScreenToClient (handle, ref x, ref y); + + point.x = (short) x; + point.y = (short) y; + } + + internal static Rectangle TranslateClientRectangleToQuartzClientRectangle (Hwnd hwnd) { + return TranslateClientRectangleToQuartzClientRectangle (hwnd, Widget.FromHandle (hwnd.Handle)); + } + + internal static Rectangle TranslateClientRectangleToQuartzClientRectangle (Hwnd hwnd, Widget ctrl) { + /* From XplatUIX11 + * If this is a form with no window manager, X is handling all the border and caption painting + * so remove that from the area (since the area we set of the window here is the part of the window + * we're painting in only) + */ + Rectangle rect = hwnd.ClientRect; + Form form = ctrl as Form; + CreateParams cp = null; + + if (form != null) + cp = form.GetCreateParams (); + + if (form != null && (form.window_manager == null || cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) { + Hwnd.Borders borders = Hwnd.GetBorders (cp, null); + Rectangle qrect = rect; + + qrect.Y -= borders.top; + qrect.X -= borders.left; + qrect.Width += borders.left + borders.right; + qrect.Height += borders.top + borders.bottom; + + rect = qrect; + } + + if (rect.Width < 1 || rect.Height < 1) { + rect.Width = 1; + rect.Height = 1; + rect.X = -5; + rect.Y = -5; + } + + return rect; + } + + internal static Size TranslateWindowSizeToQuartzWindowSize (CreateParams cp) { + return TranslateWindowSizeToQuartzWindowSize (cp, new Size (cp.Width, cp.Height)); + } + + internal static Size TranslateWindowSizeToQuartzWindowSize (CreateParams cp, Size size) { + /* From XplatUIX11 + * If this is a form with no window manager, X is handling all the border and caption painting + * so remove that from the area (since the area we set of the window here is the part of the window + * we're painting in only) + */ + Form form = cp.control as Form; + if (form != null && (form.window_manager == null || cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) { + Hwnd.Borders borders = Hwnd.GetBorders (cp, null); + Size qsize = size; + + qsize.Width -= borders.left + borders.right; + qsize.Height -= borders.top + borders.bottom; + + size = qsize; + } + + if (size.Height == 0) + size.Height = 1; + if (size.Width == 0) + size.Width = 1; + return size; + } + + internal static Size TranslateQuartzWindowSizeToWindowSize (CreateParams cp, int width, int height) { + /* From XplatUIX11 + * If this is a form with no window manager, X is handling all the border and caption painting + * so remove that from the area (since the area we set of the window here is the part of the window + * we're painting in only) + */ + Size size = new Size (width, height); + Form form = cp.control as Form; + if (form != null && (form.window_manager == null || cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) { + Hwnd.Borders borders = Hwnd.GetBorders (cp, null); + Size qsize = size; + + qsize.Width += borders.left + borders.right; + qsize.Height += borders.top + borders.bottom; + + size = qsize; + } + + return size; + } + #endregion + + #region Callbacks + private void CaretCallback (object sender, EventArgs e) { + if (Caret.Paused) { + return; + } + + if (!Caret.On) { + ShowCaret (); + } else { + HideCaret (); + } + } + + private void HoverCallback (object sender, EventArgs e) { + if ((Hover.X == mouse_position.X) && (Hover.Y == mouse_position.Y)) { + MSG msg = new MSG (); + msg.hwnd = Hover.Hwnd; + msg.message = Msg.WM_MOUSEHOVER; + msg.wParam = GetMousewParam (0); + msg.lParam = (IntPtr)((ushort)Hover.X << 16 | (ushort)Hover.X); + EnqueueMessage (msg); + } + } + #endregion + + #region Private Methods + private Point ConvertScreenPointToClient (IntPtr handle, Point point) { + Point converted_point = new Point (); + Carbon.Rect window_bounds = new Carbon.Rect (); + Carbon.CGPoint native_point = new Carbon.CGPoint (); + + GetWindowBounds (HIViewGetWindow (handle), 32, ref window_bounds); + + native_point.x = (point.X - window_bounds.left); + native_point.y = (point.Y - window_bounds.top); + + HIViewConvertPoint (ref native_point, IntPtr.Zero, handle); + + converted_point.X = (int)native_point.x; + converted_point.Y = (int)native_point.y; + + return converted_point; + } + + private Point ConvertClientPointToScreen (IntPtr handle, Point point) { + Point converted_point = new Point (); + Carbon.Rect window_bounds = new Carbon.Rect (); + Carbon.CGPoint native_point = new Carbon.CGPoint (); + + GetWindowBounds (HIViewGetWindow (handle), 32, ref window_bounds); + + native_point.x = point.X; + native_point.y = point.Y; + + HIViewConvertPoint (ref native_point, handle, IntPtr.Zero); + + converted_point.X = (int)(native_point.x + window_bounds.left); + converted_point.Y = (int)(native_point.y + window_bounds.top); + + return converted_point; + } + + private double NextTimeout () { + DateTime now = DateTime.UtcNow; + int timeout = 0x7FFFFFF; + lock (TimerList) { + foreach (Timer timer in TimerList) { + int next = (int) (timer.Expires - now).TotalMilliseconds; + if (next < 0) + return 0; + if (next < timeout) + timeout = next; + } + } + if (timeout < Timer.Minimum) + timeout = Timer.Minimum; + + return (double)((double)timeout/1000); + } + + private void CheckTimers (DateTime now) { + lock (TimerList) { + int count = TimerList.Count; + if (count == 0) + return; + for (int i = 0; i < TimerList.Count; i++) { + Timer timer = (Timer) TimerList [i]; + if (timer.Enabled && timer.Expires <= now) { + // Timer ticks: + // - Before MainForm.OnLoad if DoEvents () is called. + // - After MainForm.OnLoad if not. + // + if (in_doevents || + (Application.MWFThread.Current.Context != null && + Application.MWFThread.Current.Context.MainForm != null && + Application.MWFThread.Current.Context.MainForm.IsLoaded)) { + timer.FireTick (); + timer.Update (now); + } + } + } + } + } + + private void WaitForHwndMessage (Hwnd hwnd, Msg message) { + MSG msg = new MSG (); + + bool done = false; + do { + if (GetMessage(null, ref msg, IntPtr.Zero, 0, 0)) { + if ((Msg)msg.message == Msg.WM_QUIT) { + PostQuitMessage (0); + done = true; + } + else { + if (msg.hwnd == hwnd.Handle) { + if ((Msg)msg.message == message) + break; + else if ((Msg)msg.message == Msg.WM_DESTROY) + done = true; + } + + TranslateMessage (ref msg); + DispatchMessage (ref msg); + } + } + } while (!done); + } + + private void SendParentNotify(IntPtr child, Msg cause, int x, int y) { + Hwnd hwnd; + + if (child == IntPtr.Zero) { + return; + } + + hwnd = Hwnd.GetObjectFromWindow (child); + + if (hwnd == null) { + return; + } + + if (hwnd.Handle == IntPtr.Zero) { + return; + } + + if (ExStyleSet ((int) hwnd.initial_ex_style, WindowExStyles.WS_EX_NOPARENTNOTIFY)) { + return; + } + + if (hwnd.Parent == null) { + return; + } + + if (hwnd.Parent.Handle == IntPtr.Zero) { + return; + } + + if (cause == Msg.WM_CREATE || cause == Msg.WM_DESTROY) { + SendMessage(hwnd.Parent.Handle, Msg.WM_PARENTNOTIFY, Widget.MakeParam((int)cause, 0), child); + } else { + SendMessage(hwnd.Parent.Handle, Msg.WM_PARENTNOTIFY, Widget.MakeParam((int)cause, 0), Widget.MakeParam(x, y)); + } + + SendParentNotify (hwnd.Parent.Handle, cause, x, y); + } + + private bool StyleSet (int s, WindowStyles ws) { + return (s & (int)ws) == (int)ws; + } + + private bool ExStyleSet (int ex, WindowExStyles exws) { + return (ex & (int)exws) == (int)exws; + } + + private void DeriveStyles(int Style, int ExStyle, out FormBorderStyle border_style, out bool border_static, out TitleStyle title_style, out int caption_height, out int tool_caption_height) { + + caption_height = 0; + tool_caption_height = 0; + border_static = false; + + if (StyleSet (Style, WindowStyles.WS_CHILD)) { + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_CLIENTEDGE)) { + border_style = FormBorderStyle.Fixed3D; + } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_STATICEDGE)) { + border_style = FormBorderStyle.Fixed3D; + border_static = true; + } else if (!StyleSet (Style, WindowStyles.WS_BORDER)) { + border_style = FormBorderStyle.None; + } else { + border_style = FormBorderStyle.FixedSingle; + } + title_style = TitleStyle.None; + + if (StyleSet (Style, WindowStyles.WS_CAPTION)) { + caption_height = 0; + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + title_style = TitleStyle.Tool; + } else { + title_style = TitleStyle.Normal; + } + } + + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_MDICHILD)) { + caption_height = 0; + + if (StyleSet (Style, WindowStyles.WS_OVERLAPPEDWINDOW) || + ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + border_style = (FormBorderStyle) 0xFFFF; + } else { + border_style = FormBorderStyle.None; + } + } + + } else { + title_style = TitleStyle.None; + if (StyleSet (Style, WindowStyles.WS_CAPTION)) { + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + title_style = TitleStyle.Tool; + } else { + title_style = TitleStyle.Normal; + } + } + + border_style = FormBorderStyle.None; + + if (StyleSet (Style, WindowStyles.WS_THICKFRAME)) { + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + border_style = FormBorderStyle.SizableToolWindow; + } else { + border_style = FormBorderStyle.Sizable; + } + } else { + if (StyleSet (Style, WindowStyles.WS_CAPTION)) { + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_CLIENTEDGE)) { + border_style = FormBorderStyle.Fixed3D; + } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_STATICEDGE)) { + border_style = FormBorderStyle.Fixed3D; + border_static = true; + } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_DLGMODALFRAME)) { + border_style = FormBorderStyle.FixedDialog; + } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + border_style = FormBorderStyle.FixedToolWindow; + } else if (StyleSet (Style, WindowStyles.WS_BORDER)) { + border_style = FormBorderStyle.FixedSingle; + } + } else { + if (StyleSet (Style, WindowStyles.WS_BORDER)) { + border_style = FormBorderStyle.FixedSingle; + } + } + } + } + } + + private void SetHwndStyles(Hwnd hwnd, CreateParams cp) { + DeriveStyles(cp.Style, cp.ExStyle, out hwnd.border_style, out hwnd.border_static, out hwnd.title_style, out hwnd.caption_height, out hwnd.tool_caption_height); + } + + private void ShowCaret () { + if (Caret.On) + return; + Caret.On = true; + ShowWindow (CaretWindow); + Graphics g = Graphics.FromHwnd (HIViewGetRoot (CaretWindow)); + + g.FillRectangle (new SolidBrush (Color.Black), new Rectangle (0, 0, Caret.Width, Caret.Height)); + + g.Dispose (); + } + + private void HideCaret () { + if (!Caret.On) + return; + Caret.On = false; + HideWindow (CaretWindow); + } + + private void AccumulateDestroyedHandles (Widget c, ArrayList list) { + if (c != null) { + Widget[] Widgets = c.Widgets.GetAllWidgets (); + + if (c.IsHandleCreated && !c.IsDisposed) { + Hwnd hwnd = Hwnd.ObjectFromHandle(c.Handle); + + list.Add (hwnd); + CleanupCachedWindows (hwnd); + } + + for (int i = 0; i < Widgets.Length; i ++) { + AccumulateDestroyedHandles (Widgets[i], list); + } + } + + } + + private void CleanupCachedWindows (Hwnd hwnd) { + if (ActiveWindow == hwnd.Handle) { + SendMessage(hwnd.client_window, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero); + ActiveWindow = IntPtr.Zero; + } + + if (FocusWindow == hwnd.Handle) { + SendMessage(hwnd.client_window, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero); + FocusWindow = IntPtr.Zero; + } + + if (Grab.Hwnd == hwnd.Handle) { + Grab.Hwnd = IntPtr.Zero; + Grab.Confined = false; + } + + DestroyCaret (hwnd.Handle); + } + + private void AddExpose (Hwnd hwnd, bool client, int x, int y, int width, int height) { + // Don't waste time + if ((hwnd == null) || (x > hwnd.Width) || (y > hwnd.Height) || ((x + width) < 0) || ((y + height) < 0)) { + return; + } + + // Keep the invalid area as small as needed + if ((x + width) > hwnd.width) { + width = hwnd.width - x; + } + + if ((y + height) > hwnd.height) { + height = hwnd.height - y; + } + + if (client) { + hwnd.AddInvalidArea(x, y, width, height); + if (!hwnd.expose_pending && hwnd.visible) { + MSG msg = new MSG (); + msg.message = Msg.WM_PAINT; + msg.hwnd = hwnd.Handle; + EnqueueMessage (msg); + hwnd.expose_pending = true; + } + } else { + hwnd.AddNcInvalidArea (x, y, width, height); + if (!hwnd.nc_expose_pending && hwnd.visible) { + MSG msg = new MSG (); + Region rgn = new Region (hwnd.Invalid); + IntPtr hrgn = rgn.GetHrgn (null); // Graphics object isn't needed + msg.message = Msg.WM_NCPAINT; + msg.wParam = hrgn == IntPtr.Zero ? (IntPtr)1 : hrgn; + msg.refobject = rgn; + msg.hwnd = hwnd.Handle; + EnqueueMessage (msg); + hwnd.nc_expose_pending = true; + + } + } + } + #endregion + + #region Public Methods + internal void EnqueueMessage (MSG msg) { + lock (queuelock) { + MessageQueue.Enqueue (msg); + } + } + + internal override void RaiseIdle (EventArgs e) + { + if (Idle != null) + Idle (this, e); + } + + internal override IntPtr InitializeDriver() { + return IntPtr.Zero; + } + + internal override void ShutdownDriver(IntPtr token) { + } + + internal override void EnableThemes() { + themes_enabled = true; + } + + internal override void Activate(IntPtr handle) { + if (ActiveWindow != IntPtr.Zero) { + UnactiveWindow = ActiveWindow; + ActivateWindow (HIViewGetWindow (ActiveWindow), false); + } + ActivateWindow (HIViewGetWindow (handle), true); + ActiveWindow = handle; + } + + internal override void AudibleAlert(AlertType alert) { + AlertSoundPlay (); + } + + internal override void BeginMoveResize (IntPtr handle) { + } + + internal override void CaretVisible (IntPtr hwnd, bool visible) { + if (Caret.Hwnd == hwnd) { + if (visible) { + if (Caret.Visible < 1) { + Caret.Visible++; + Caret.On = false; + if (Caret.Visible == 1) { + ShowCaret (); + Caret.Timer.Start (); + } + } + } else { + Caret.Visible--; + if (Caret.Visible == 0) { + Caret.Timer.Stop (); + HideCaret (); + } + } + } + } + + internal override bool CalculateWindowRect(ref Rectangle ClientRect, CreateParams cp, Menu menu, out Rectangle WindowRect) { + WindowRect = Hwnd.GetWindowRectangle (cp, menu, ClientRect); + return true; + } + + internal override void ClientToScreen(IntPtr handle, ref int x, ref int y) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + Point point = ConvertClientPointToScreen (hwnd.ClientWindow, new Point (x, y)); + + x = point.X; + y = point.Y; + } + + internal override void MenuToScreen(IntPtr handle, ref int x, ref int y) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + Point point = ConvertClientPointToScreen (hwnd.ClientWindow, new Point (x, y)); + + x = point.X; + y = point.Y; + } + + internal override int[] ClipboardAvailableFormats(IntPtr handle) { + ArrayList list = new ArrayList (); + DataFormats.Format f = DataFormats.Format.List; + + while (f != null) { + list.Add (f.Id); + f = f.Next; + } + + return (int [])list.ToArray (typeof (int)); + } + + internal override void ClipboardClose(IntPtr handle) { + } + + //TODO: Map our internal formats to the right os code where we can + internal override int ClipboardGetID(IntPtr handle, string format) { + return (int)__CFStringMakeConstantString (format); + } + + internal override IntPtr ClipboardOpen(bool primary_selection) { + if (primary_selection) + return Carbon.Pasteboard.Primary; + return Carbon.Pasteboard.Application; + } + + internal override object ClipboardRetrieve(IntPtr handle, int type, XplatUI.ClipboardToObject converter) { + return Carbon.Pasteboard.Retrieve (handle, type); + } + + internal override void ClipboardStore(IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter, bool copy) { + Carbon.Pasteboard.Store (handle, obj, type); + } + + internal override void CreateCaret (IntPtr hwnd, int width, int height) { + if (Caret.Hwnd != IntPtr.Zero) + DestroyCaret (Caret.Hwnd); + + Caret.Hwnd = hwnd; + Caret.Width = width; + Caret.Height = height; + Caret.Visible = 0; + Caret.On = false; + } + + internal override IntPtr CreateWindow(CreateParams cp) { + Hwnd hwnd; + Hwnd parent_hwnd = null; + int X; + int Y; + int Width; + int Height; + IntPtr ParentHandle; + IntPtr WindowHandle; + IntPtr WholeWindow; + IntPtr ClientWindow; + IntPtr WholeWindowTracking; + IntPtr ClientWindowTracking; + + hwnd = new Hwnd (); + + X = cp.X; + Y = cp.Y; + Width = cp.Width; + Height = cp.Height; + ParentHandle = IntPtr.Zero; + WindowHandle = IntPtr.Zero; + WholeWindow = IntPtr.Zero; + ClientWindow = IntPtr.Zero; + WholeWindowTracking = IntPtr.Zero; + ClientWindowTracking = IntPtr.Zero; + + if (Width < 1) Width = 1; + if (Height < 1) Height = 1; + + if (cp.Parent != IntPtr.Zero) { + parent_hwnd = Hwnd.ObjectFromHandle (cp.Parent); + ParentHandle = parent_hwnd.client_window; + } else { + if (StyleSet (cp.Style, WindowStyles.WS_CHILD)) { + HIViewFindByID (HIViewGetRoot (FosterParent), new Carbon.HIViewID (Carbon.EventHandler.kEventClassWindow, 1), ref ParentHandle); + } + } + + Point next; + if (cp.control is Form) { + next = Hwnd.GetNextStackedFormLocation (cp, parent_hwnd); + X = next.X; + Y = next.Y; + } + + hwnd.x = X; + hwnd.y = Y; + hwnd.width = Width; + hwnd.height = Height; + hwnd.Parent = Hwnd.ObjectFromHandle (cp.Parent); + hwnd.initial_style = cp.WindowStyle; + hwnd.initial_ex_style = cp.WindowExStyle; + hwnd.visible = false; + + if (StyleSet (cp.Style, WindowStyles.WS_DISABLED)) { + hwnd.enabled = false; + } + + ClientWindow = IntPtr.Zero; + + Size QWindowSize = TranslateWindowSizeToQuartzWindowSize (cp); + Rectangle QClientRect = TranslateClientRectangleToQuartzClientRectangle (hwnd, cp.control); + + SetHwndStyles(hwnd, cp); +/* FIXME */ + if (ParentHandle == IntPtr.Zero) { + IntPtr WindowView = IntPtr.Zero; + IntPtr GrowBox = IntPtr.Zero; + Carbon.WindowClass windowklass = Carbon.WindowClass.kOverlayWindowClass; + Carbon.WindowAttributes attributes = Carbon.WindowAttributes.kWindowCompositingAttribute | Carbon.WindowAttributes.kWindowStandardHandlerAttribute; + if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZEBOX)) { + attributes |= Carbon.WindowAttributes.kWindowCollapseBoxAttribute; + } + if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZEBOX)) { + attributes |= Carbon.WindowAttributes.kWindowResizableAttribute | Carbon.WindowAttributes.kWindowHorizontalZoomAttribute | Carbon.WindowAttributes.kWindowVerticalZoomAttribute; + } + if (StyleSet (cp.Style, WindowStyles.WS_SYSMENU)) { + attributes |= Carbon.WindowAttributes.kWindowCloseBoxAttribute; + } + if (StyleSet (cp.Style, WindowStyles.WS_CAPTION)) { + windowklass = Carbon.WindowClass.kDocumentWindowClass; + } + if (hwnd.border_style == FormBorderStyle.FixedToolWindow) { + windowklass = Carbon.WindowClass.kUtilityWindowClass; + } else if (hwnd.border_style == FormBorderStyle.SizableToolWindow) { + attributes |= Carbon.WindowAttributes.kWindowResizableAttribute; + windowklass = Carbon.WindowClass.kUtilityWindowClass; + } + if (windowklass == Carbon.WindowClass.kOverlayWindowClass) { + attributes = Carbon.WindowAttributes.kWindowCompositingAttribute | Carbon.WindowAttributes.kWindowStandardHandlerAttribute; + } + attributes |= Carbon.WindowAttributes.kWindowLiveResizeAttribute; + + Carbon.Rect rect = new Carbon.Rect (); + if (StyleSet (cp.Style, WindowStyles.WS_POPUP)) { + SetRect (ref rect, (short)X, (short)(Y), (short)(X + QWindowSize.Width), (short)(Y + QWindowSize.Height)); + } else { + SetRect (ref rect, (short)X, (short)(Y + MenuBarHeight), (short)(X + QWindowSize.Width), (short)(Y + MenuBarHeight + QWindowSize.Height)); + } + + CreateNewWindow (windowklass, attributes, ref rect, ref WindowHandle); + + Carbon.EventHandler.InstallWindowHandler (WindowHandle); + HIViewFindByID (HIViewGetRoot (WindowHandle), new Carbon.HIViewID (Carbon.EventHandler.kEventClassWindow, 1), ref WindowView); + HIViewFindByID (HIViewGetRoot (WindowHandle), new Carbon.HIViewID (Carbon.EventHandler.kEventClassWindow, 7), ref GrowBox); + HIGrowBoxViewSetTransparent (GrowBox, true); + SetAutomaticWidgetDragTrackingEnabledForWindow (WindowHandle, true); + ParentHandle = WindowView; + } + + HIObjectCreate (__CFStringMakeConstantString ("com.novell.mwfview"), 0, ref WholeWindow); + HIObjectCreate (__CFStringMakeConstantString ("com.novell.mwfview"), 0, ref ClientWindow); + + Carbon.EventHandler.InstallWidgetHandler (WholeWindow); + Carbon.EventHandler.InstallWidgetHandler (ClientWindow); + + // Enable embedding on Widgets + HIViewChangeFeatures (WholeWindow, 1<<1, 0); + HIViewChangeFeatures (ClientWindow, 1<<1, 0); + + HIViewNewTrackingArea (WholeWindow, IntPtr.Zero, (UInt64)WholeWindow, ref WholeWindowTracking); + HIViewNewTrackingArea (ClientWindow, IntPtr.Zero, (UInt64)ClientWindow, ref ClientWindowTracking); + Carbon.HIRect WholeRect; + if (WindowHandle != IntPtr.Zero) { + WholeRect = new Carbon.HIRect (0, 0, QWindowSize.Width, QWindowSize.Height); + } else { + WholeRect = new Carbon.HIRect (X, Y, QWindowSize.Width, QWindowSize.Height); + } + Carbon.HIRect ClientRect = new Carbon.HIRect (QClientRect.X, QClientRect.Y, QClientRect.Width, QClientRect.Height); + HIViewSetFrame (WholeWindow, ref WholeRect); + HIViewSetFrame (ClientWindow, ref ClientRect); + + HIViewAddSubview (ParentHandle, WholeWindow); + HIViewAddSubview (WholeWindow, ClientWindow); + + hwnd.WholeWindow = WholeWindow; + hwnd.ClientWindow = ClientWindow; + + if (WindowHandle != IntPtr.Zero) { + WindowMapping [hwnd.Handle] = WindowHandle; + HandleMapping [WindowHandle] = hwnd.Handle; + if (hwnd.border_style == FormBorderStyle.FixedToolWindow || hwnd.border_style == FormBorderStyle.SizableToolWindow) { + UtilityWindows.Add (WindowHandle); + } + } + + // Allow dnd on Widgets + Dnd.SetAllowDrop (hwnd, true); + + Text (hwnd.Handle, cp.Caption); + + SendMessage (hwnd.Handle, Msg.WM_CREATE, (IntPtr)1, IntPtr.Zero /* XXX unused */); + SendParentNotify (hwnd.Handle, Msg.WM_CREATE, int.MaxValue, int.MaxValue); + + if (StyleSet (cp.Style, WindowStyles.WS_VISIBLE)) { + if (WindowHandle != IntPtr.Zero) { + if (Widget.FromHandle(hwnd.Handle) is Form) { + Form f = Widget.FromHandle(hwnd.Handle) as Form; + if (f.WindowState == FormWindowState.Normal) { + SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero); + } + } + ShowWindow (WindowHandle); + WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW); + } + HIViewSetVisible (WholeWindow, true); + HIViewSetVisible (ClientWindow, true); + hwnd.visible = true; + if (!(Widget.FromHandle(hwnd.Handle) is Form)) { + SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero); + } + } + + if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZE)) { + SetWindowState(hwnd.Handle, FormWindowState.Minimized); + } else if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZE)) { + SetWindowState(hwnd.Handle, FormWindowState.Maximized); + } + + return hwnd.Handle; + } + + internal override IntPtr CreateWindow(IntPtr Parent, int X, int Y, int Width, int Height) { + CreateParams create_params = new CreateParams(); + + create_params.Caption = ""; + create_params.X = X; + create_params.Y = Y; + create_params.Width = Width; + create_params.Height = Height; + + create_params.ClassName=XplatUI.GetDefaultClassName (GetType ()); + create_params.ClassStyle = 0; + create_params.ExStyle=0; + create_params.Parent=IntPtr.Zero; + create_params.Param=0; + + return CreateWindow(create_params); + } + + internal override Bitmap DefineStdCursorBitmap (StdCursor id) { + return Carbon.Cursor.DefineStdCursorBitmap (id); + } + + internal override IntPtr DefineCursor (Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) { + return Carbon.Cursor.DefineCursor (bitmap, mask, cursor_pixel, mask_pixel, xHotSpot, yHotSpot); + } + + internal override IntPtr DefineStdCursor (StdCursor id) { + return Carbon.Cursor.DefineStdCursor (id); + } + + internal override IntPtr DefWndProc(ref Message msg) { + Hwnd hwnd = Hwnd.ObjectFromHandle (msg.HWnd); + switch ((Msg)msg.Msg) { + case Msg.WM_IME_COMPOSITION: + string s = KeyboardHandler.ComposedString; + foreach (char c in s) + SendMessage (msg.HWnd, Msg.WM_IME_CHAR, (IntPtr) c, msg.LParam); + break; + case Msg.WM_IME_CHAR: + // On Windows API it sends two WM_CHAR messages for each byte, but + // I wonder if it is worthy to emulate it (also no idea how to + // reconstruct those bytes into chars). + SendMessage (msg.HWnd, Msg.WM_CHAR, msg.WParam, msg.LParam); + return IntPtr.Zero; + case Msg.WM_QUIT: { + if (WindowMapping [hwnd.Handle] != null) + + Exit (); + break; + } + case Msg.WM_PAINT: { + hwnd.expose_pending = false; + break; + } + case Msg.WM_NCPAINT: { + hwnd.nc_expose_pending = false; + break; + } + case Msg.WM_NCCALCSIZE: { + if (msg.WParam == (IntPtr)1) { + XplatUIWin32.NCCALCSIZE_PARAMS ncp; + ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure (msg.LParam, typeof (XplatUIWin32.NCCALCSIZE_PARAMS)); + + // Add all the stuff X is supposed to draw. + Widget ctrl = Widget.FromHandle (hwnd.Handle); + if (ctrl != null) { + Hwnd.Borders rect = Hwnd.GetBorders (ctrl.GetCreateParams (), null); + + ncp.rgrc1.top += rect.top; + ncp.rgrc1.bottom -= rect.bottom; + ncp.rgrc1.left += rect.left; + ncp.rgrc1.right -= rect.right; + + Marshal.StructureToPtr (ncp, msg.LParam, true); + } + } + break; + } + case Msg.WM_SETCURSOR: { + // Pass to parent window first + while ((hwnd.parent != null) && (msg.Result == IntPtr.Zero)) { + hwnd = hwnd.parent; + msg.Result = NativeWindow.WndProc(hwnd.Handle, Msg.WM_SETCURSOR, msg.HWnd, msg.LParam); + } + + if (msg.Result == IntPtr.Zero) { + IntPtr handle; + + switch((HitTest)(msg.LParam.ToInt32() & 0xffff)) { + case HitTest.HTBOTTOM: handle = Cursors.SizeNS.handle; break; + case HitTest.HTBORDER: handle = Cursors.SizeNS.handle; break; + case HitTest.HTBOTTOMLEFT: handle = Cursors.SizeNESW.handle; break; + case HitTest.HTBOTTOMRIGHT: handle = Cursors.SizeNWSE.handle; break; + case HitTest.HTERROR: if ((msg.LParam.ToInt32() >> 16) == (int)Msg.WM_LBUTTONDOWN) { + //FIXME: AudibleAlert(); + } + handle = Cursors.Default.handle; + break; + + case HitTest.HTHELP: handle = Cursors.Help.handle; break; + case HitTest.HTLEFT: handle = Cursors.SizeWE.handle; break; + case HitTest.HTRIGHT: handle = Cursors.SizeWE.handle; break; + case HitTest.HTTOP: handle = Cursors.SizeNS.handle; break; + case HitTest.HTTOPLEFT: handle = Cursors.SizeNWSE.handle; break; + case HitTest.HTTOPRIGHT: handle = Cursors.SizeNESW.handle; break; + + #if SameAsDefault + case HitTest.HTGROWBOX: + case HitTest.HTSIZE: + case HitTest.HTZOOM: + case HitTest.HTVSCROLL: + case HitTest.HTSYSMENU: + case HitTest.HTREDUCE: + case HitTest.HTNOWHERE: + case HitTest.HTMAXBUTTON: + case HitTest.HTMINBUTTON: + case HitTest.HTMENU: + case HitTest.HSCROLL: + case HitTest.HTBOTTOM: + case HitTest.HTCAPTION: + case HitTest.HTCLIENT: + case HitTest.HTCLOSE: + #endif + default: handle = Cursors.Default.handle; break; + } + SetCursor(msg.HWnd, handle); + } + return (IntPtr)1; + } + } + return IntPtr.Zero; + } + + internal override void DestroyCaret (IntPtr hwnd) { + if (Caret.Hwnd == hwnd) { + if (Caret.Visible == 1) { + Caret.Timer.Stop (); + HideCaret (); + } + Caret.Hwnd = IntPtr.Zero; + Caret.Visible = 0; + Caret.On = false; + } + } + + [MonoTODO] + internal override void DestroyCursor(IntPtr cursor) { + throw new NotImplementedException (); + } + + internal override void DestroyWindow(IntPtr handle) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd == null) { + return; + } + + SendParentNotify (hwnd.Handle, Msg.WM_DESTROY, int.MaxValue, int.MaxValue); + + CleanupCachedWindows (hwnd); + + ArrayList windows = new ArrayList (); + + AccumulateDestroyedHandles (Widget.WidgetNativeWindow.WidgetFromHandle(hwnd.Handle), windows); + + + foreach (Hwnd h in windows) { + SendMessage (h.Handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero); + h.zombie = true; + } + + // TODO: This is crashing swf-messageboxes + /* + if (false && hwnd.whole_window != IntPtr.Zero) + CFRelease (hwnd.whole_window); + if (false && hwnd.client_window != IntPtr.Zero) + CFRelease (hwnd.client_window); + */ + + if (WindowMapping [hwnd.Handle] != null) { + DisposeWindow ((IntPtr)(WindowMapping [hwnd.Handle])); + WindowMapping.Remove (hwnd.Handle); + } + } + + internal override IntPtr DispatchMessage(ref MSG msg) { + return NativeWindow.WndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam); + } + + internal override void DoEvents() { + MSG msg = new MSG (); + + in_doevents = true; + while (PeekMessage (null, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) { + TranslateMessage (ref msg); + DispatchMessage (ref msg); + } + in_doevents = false; + + } + + internal override void EnableWindow(IntPtr handle, bool Enable) { + //Like X11 we need not do anything here + } + + internal override void EndLoop(Thread thread) { + } + + internal void Exit () { + GetMessageResult = false; + } + + internal override IntPtr GetActive() { + return ActiveWindow; + } + + internal override Region GetClipRegion(IntPtr hwnd) { + return null; + } + + [MonoTODO] + internal override void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y) { + width = 12; + height = 12; + hotspot_x = 0; + hotspot_y = 0; + } + + internal override void GetDisplaySize(out Size size) { + Carbon.HIRect bounds = CGDisplayBounds (CGMainDisplayID ()); + size = new Size ((int)bounds.size.width, (int)bounds.size.height); + } + + internal override IntPtr GetParent(IntPtr handle) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + if (hwnd != null && hwnd.Parent != null) { + return hwnd.Parent.Handle; + } + return IntPtr.Zero; + } + + internal override IntPtr GetPreviousWindow(IntPtr handle) { + return HIViewGetPreviousView(handle); + } + + internal override void GetCursorPos(IntPtr handle, out int x, out int y) { + Carbon.QDPoint pt = new Carbon.QDPoint (); + GetGlobalMouse (ref pt); + x = pt.x; + y = pt.y; + } + + internal override IntPtr GetFocus() { + return FocusWindow; + } + + + internal override bool GetFontMetrics(Graphics g, Font font, out int ascent, out int descent) { + FontFamily ff = font.FontFamily; + ascent = ff.GetCellAscent (font.Style); + descent = ff.GetCellDescent (font.Style); + return true; + } + + internal override Point GetMenuOrigin(IntPtr handle) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) { + return hwnd.MenuOrigin; + } + return Point.Empty; + } + + internal override bool GetMessage(object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax) { + IntPtr evtRef = IntPtr.Zero; + IntPtr target = GetEventDispatcherTarget(); + CheckTimers (DateTime.UtcNow); + ReceiveNextEvent (0, IntPtr.Zero, 0, true, ref evtRef); + if (evtRef != IntPtr.Zero && target != IntPtr.Zero) { + SendEventToEventTarget (evtRef, target); + ReleaseEvent (evtRef); + } + + object queueobj; + loop: + lock (queuelock) { + + if (MessageQueue.Count <= 0) { + if (Idle != null) + Idle (this, EventArgs.Empty); + else if (TimerList.Count == 0) { + ReceiveNextEvent (0, IntPtr.Zero, 0.15, true, ref evtRef); + if (evtRef != IntPtr.Zero && target != IntPtr.Zero) { + SendEventToEventTarget (evtRef, target); + ReleaseEvent (evtRef); + } + } else { + ReceiveNextEvent (0, IntPtr.Zero, NextTimeout (), true, ref evtRef); + if (evtRef != IntPtr.Zero && target != IntPtr.Zero) { + SendEventToEventTarget (evtRef, target); + ReleaseEvent (evtRef); + } + } + msg.hwnd = IntPtr.Zero; + msg.message = Msg.WM_ENTERIDLE; + return GetMessageResult; + } + queueobj = MessageQueue.Dequeue (); + } + if (queueobj is GCHandle) { + XplatUIDriverSupport.ExecuteClientMessage((GCHandle)queueobj); + goto loop; + } else { + msg = (MSG)queueobj; + } + return GetMessageResult; + } + + [MonoTODO] + internal override bool GetText(IntPtr handle, out string text) { + throw new NotImplementedException (); + } + + internal override void GetWindowPos(IntPtr handle, bool is_toplevel, out int x, out int y, out int width, out int height, out int client_width, out int client_height) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) { + x = hwnd.x; + y = hwnd.y; + width = hwnd.width; + height = hwnd.height; + + PerformNCCalc(hwnd); + + client_width = hwnd.ClientRect.Width; + client_height = hwnd.ClientRect.Height; + + return; + } + + // Should we throw an exception or fail silently? + // throw new ArgumentException("Called with an invalid window handle", "handle"); + + x = 0; + y = 0; + width = 0; + height = 0; + client_width = 0; + client_height = 0; + } + + internal override FormWindowState GetWindowState(IntPtr hwnd) { + IntPtr window = HIViewGetWindow (hwnd); + + if (IsWindowCollapsed (window)) + return FormWindowState.Minimized; + if (IsWindowInStandardState (window, IntPtr.Zero, IntPtr.Zero)) + return FormWindowState.Maximized; + + return FormWindowState.Normal; + } + + internal override void GrabInfo(out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea) { + handle = Grab.Hwnd; + GrabConfined = Grab.Confined; + GrabArea = Grab.Area; + } + + internal override void GrabWindow(IntPtr handle, IntPtr confine_to_handle) { + Grab.Hwnd = handle; + Grab.Confined = confine_to_handle != IntPtr.Zero; + /* FIXME: Set the Grab.Area */ + } + + internal override void UngrabWindow(IntPtr hwnd) { + bool was_grabbed = Grab.Hwnd != IntPtr.Zero; + + Grab.Hwnd = IntPtr.Zero; + Grab.Confined = false; + + if (was_grabbed) { + // lparam should be the handle to the window gaining the mouse capture, + // but we dont have that information like X11. + // Also only generate WM_CAPTURECHANGED if the window actually was grabbed. + SendMessage (hwnd, Msg.WM_CAPTURECHANGED, IntPtr.Zero, IntPtr.Zero); + } + } + + internal override void HandleException(Exception e) { + StackTrace st = new StackTrace(e); + Console.WriteLine("Exception '{0}'", e.Message+st.ToString()); + Console.WriteLine("{0}{1}", e.Message, st.ToString()); + } + + internal override void Invalidate (IntPtr handle, Rectangle rc, bool clear) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (clear) { + AddExpose (hwnd, true, hwnd.X, hwnd.Y, hwnd.Width, hwnd.Height); + } else { + AddExpose (hwnd, true, rc.X, rc.Y, rc.Width, rc.Height); + } + } + + internal override void InvalidateNC (IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + AddExpose (hwnd, false, 0, 0, hwnd.Width, hwnd.Height); + } + + internal override bool IsEnabled(IntPtr handle) { + return Hwnd.ObjectFromHandle(handle).Enabled; + } + + internal override bool IsVisible(IntPtr handle) { + return Hwnd.ObjectFromHandle(handle).visible; + } + + internal override void KillTimer(Timer timer) { + lock (TimerList) { + TimerList.Remove(timer); + } + } + + + internal override void OverrideCursor(IntPtr cursor) { + } + + internal override PaintEventArgs PaintEventStart(ref Message msg, IntPtr handle, bool client) { + PaintEventArgs paint_event; + Hwnd hwnd; + Hwnd paint_hwnd; + + hwnd = Hwnd.ObjectFromHandle(msg.HWnd); + if (msg.HWnd == handle) { + paint_hwnd = hwnd; + } else { + paint_hwnd = Hwnd.ObjectFromHandle (handle); + } + + if (Caret.Visible == 1) { + Caret.Paused = true; + HideCaret(); + } + + Graphics dc; + + if (client) { + dc = Graphics.FromHwnd (paint_hwnd.client_window); + + Region clip_region = new Region (); + clip_region.MakeEmpty(); + + foreach (Rectangle r in hwnd.ClipRectangles) { + /* Expand the region slightly. + * See bug 464464. + */ + Rectangle r2 = Rectangle.FromLTRB (r.Left, r.Top, r.Right, r.Bottom + 1); + clip_region.Union (r2); + } + + if (hwnd.UserClip != null) { + clip_region.Intersect(hwnd.UserClip); + } + + // FIXME: Clip region is hosed + dc.Clip = clip_region; + paint_event = new PaintEventArgs(dc, hwnd.Invalid); + hwnd.expose_pending = false; + hwnd.ClearInvalidArea(); + + hwnd.drawing_stack.Push (paint_event); + hwnd.drawing_stack.Push (dc); + } else { + dc = Graphics.FromHwnd (paint_hwnd.whole_window); + + if (!hwnd.nc_invalid.IsEmpty) { + // FIXME: Clip region is hosed + dc.SetClip (hwnd.nc_invalid); + paint_event = new PaintEventArgs(dc, hwnd.nc_invalid); + } else { + paint_event = new PaintEventArgs(dc, new Rectangle(0, 0, hwnd.width, hwnd.height)); + } + hwnd.nc_expose_pending = false; + hwnd.ClearNcInvalidArea (); + + hwnd.drawing_stack.Push (paint_event); + hwnd.drawing_stack.Push (dc); + } + + return paint_event; + } + + internal override void PaintEventEnd(ref Message msg, IntPtr handle, bool client) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + // FIXME: Pop is causing invalid stack ops sometimes; race condition? + try { + Graphics dc = (Graphics)hwnd.drawing_stack.Pop(); + dc.Flush (); + dc.Dispose (); + + PaintEventArgs pe = (PaintEventArgs)hwnd.drawing_stack.Pop(); + pe.SetGraphics (null); + pe.Dispose (); + } catch {} + + if (Caret.Visible == 1) { + ShowCaret(); + Caret.Paused = false; + } + } + + internal override bool PeekMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) { + IntPtr evtRef = IntPtr.Zero; + IntPtr target = GetEventDispatcherTarget(); + CheckTimers (DateTime.UtcNow); + ReceiveNextEvent (0, IntPtr.Zero, 0, true, ref evtRef); + if (evtRef != IntPtr.Zero && target != IntPtr.Zero) { + SendEventToEventTarget (evtRef, target); + ReleaseEvent (evtRef); + } + + lock (queuelock) { + if (MessageQueue.Count <= 0) { + return false; + } else { + object queueobj; + if (flags == (uint)PeekMessageFlags.PM_REMOVE) + queueobj = MessageQueue.Dequeue (); + else + queueobj = MessageQueue.Peek (); + + if (queueobj is GCHandle) { + XplatUIDriverSupport.ExecuteClientMessage((GCHandle)queueobj); + return false; + } + msg = (MSG)queueobj; + return true; + } + } + } + + internal override bool PostMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam) { + MSG msg = new MSG(); + msg.hwnd = hwnd; + msg.message = message; + msg.wParam = wParam; + msg.lParam = lParam; + EnqueueMessage (msg); + return true; + } + + internal override void PostQuitMessage(int exitCode) { + PostMessage (FosterParent, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero); + } + + internal override void RequestAdditionalWM_NCMessages(IntPtr hwnd, bool hover, bool leave) { + } + + internal override void RequestNCRecalc(IntPtr handle) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd == null) { + return; + } + + PerformNCCalc(hwnd); + SendMessage(handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + InvalidateNC(handle); + } + + [MonoTODO] + internal override void ResetMouseHover(IntPtr handle) { + throw new NotImplementedException(); + } + + internal override void ScreenToClient(IntPtr handle, ref int x, ref int y) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + Point point = ConvertScreenPointToClient (hwnd.ClientWindow, new Point (x, y)); + + x = point.X; + y = point.Y; + } + + internal override void ScreenToMenu(IntPtr handle, ref int x, ref int y) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + Point point = ConvertScreenPointToClient (hwnd.WholeWindow, new Point (x, y)); + + x = point.X; + y = point.Y; + } + + internal override void ScrollWindow(IntPtr handle, Rectangle area, int XAmount, int YAmount, bool clear) { + /* + * This used to use a HIViewScrollRect but this causes issues with the fact that we dont coalesce + * updates properly with our short-circuiting of the window manager. For now we'll do a less + * efficient invalidation of the entire handle which appears to fix the problem + * see bug #381084 + */ + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + Invalidate (handle, new Rectangle (0, 0, hwnd.Width, hwnd.Height), false); + } + + + internal override void ScrollWindow(IntPtr handle, int XAmount, int YAmount, bool clear) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + Invalidate (handle, new Rectangle (0, 0, hwnd.Width, hwnd.Height), false); + } + + [MonoTODO] + internal override void SendAsyncMethod (AsyncMethodData method) { + // Fake async + lock (queuelock) { + MessageQueue.Enqueue (GCHandle.Alloc (method)); + } + } + + [MonoTODO] + internal override IntPtr SendMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam) { + return NativeWindow.WndProc(hwnd, message, wParam, lParam); + } + + internal override int SendInput(IntPtr hwnd, Queue keys) { + return 0; + } + + + internal override void SetCaretPos (IntPtr hwnd, int x, int y) { + if (hwnd != IntPtr.Zero && hwnd == Caret.Hwnd) { + Caret.X = x; + Caret.Y = y; + ClientToScreen (hwnd, ref x, ref y); + SizeWindow (new Rectangle (x, y, Caret.Width, Caret.Height), CaretWindow); + Caret.Timer.Stop (); + HideCaret (); + if (Caret.Visible == 1) { + ShowCaret (); + Caret.Timer.Start (); + } + } + } + + internal override void SetClipRegion(IntPtr hwnd, Region region) { + throw new NotImplementedException(); + } + + internal override void SetCursor(IntPtr window, IntPtr cursor) { + Hwnd hwnd = Hwnd.ObjectFromHandle (window); + + hwnd.Cursor = cursor; + } + + internal override void SetCursorPos(IntPtr handle, int x, int y) { + CGDisplayMoveCursorToPoint (CGMainDisplayID (), new Carbon.CGPoint (x, y)); + } + + internal override void SetFocus(IntPtr handle) { + if (FocusWindow != IntPtr.Zero) { + PostMessage(FocusWindow, Msg.WM_KILLFOCUS, handle, IntPtr.Zero); + } + PostMessage(handle, Msg.WM_SETFOCUS, FocusWindow, IntPtr.Zero); + FocusWindow = handle; + } + + internal override void SetIcon(IntPtr handle, Icon icon) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + // FIXME: we need to map the icon for active window switches + if (WindowMapping [hwnd.Handle] != null) { + if (icon == null) { + RestoreApplicationDockTileImage (); + } else { + Bitmap bitmap; + int size; + IntPtr[] data; + int index; + + bitmap = new Bitmap (128, 128); + using (Graphics g = Graphics.FromImage (bitmap)) { + g.DrawImage (icon.ToBitmap (), 0, 0, 128, 128); + } + index = 0; + size = bitmap.Width * bitmap.Height; + data = new IntPtr[size]; + + for (int y = 0; y < bitmap.Height; y++) { + for (int x = 0; x < bitmap.Width; x++) { + int pixel = bitmap.GetPixel (x, y).ToArgb (); + if (BitConverter.IsLittleEndian) { + byte a = (byte) ((pixel >> 24) & 0xFF); + byte r = (byte) ((pixel >> 16) & 0xFF); + byte g = (byte) ((pixel >> 8) & 0xFF); + byte b = (byte) (pixel & 0xFF); + data[index++] = (IntPtr)(a + (r << 8) + (g << 16) + (b << 24)); + } else { + data[index++] = (IntPtr)pixel; + } + } + } + + IntPtr provider = CGDataProviderCreateWithData (IntPtr.Zero, data, size*4, IntPtr.Zero); + IntPtr image = CGImageCreate (128, 128, 8, 32, 4*128, CGColorSpaceCreateDeviceRGB (), 4, provider, IntPtr.Zero, 0, 0); + SetApplicationDockTileImage (image); + } + } + } + + + internal override void SetModal(IntPtr handle, bool Modal) { + IntPtr hWnd = HIViewGetWindow (Hwnd.ObjectFromHandle (handle).WholeWindow); + if (Modal) + BeginAppModalStateForWindow (hWnd); + else + EndAppModalStateForWindow (hWnd); + return; + } + + internal override IntPtr SetParent(IntPtr handle, IntPtr parent) { + IntPtr ParentHandle = IntPtr.Zero; + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + hwnd.Parent = Hwnd.ObjectFromHandle (parent); + if (HIViewGetSuperview (hwnd.whole_window) != IntPtr.Zero) { + HIViewRemoveFromSuperview (hwnd.whole_window); + } + if (hwnd.parent == null) + HIViewFindByID (HIViewGetRoot (FosterParent), new Carbon.HIViewID (Carbon.EventHandler.kEventClassWindow, 1), ref ParentHandle); + HIViewAddSubview (hwnd.parent == null ? ParentHandle : hwnd.Parent.client_window, hwnd.whole_window); + HIViewPlaceInSuperviewAt (hwnd.whole_window, hwnd.X, hwnd.Y); + HIViewAddSubview (hwnd.whole_window, hwnd.client_window); + HIViewPlaceInSuperviewAt (hwnd.client_window, hwnd.ClientRect.X, hwnd.ClientRect.Y); + + return IntPtr.Zero; + } + + internal override void SetTimer (Timer timer) { + lock (TimerList) { + TimerList.Add (timer); + } + } + + internal override bool SetTopmost(IntPtr hWnd, bool Enabled) { + HIViewSetZOrder (hWnd, 1, IntPtr.Zero); + return true; + } + + internal override bool SetOwner(IntPtr hWnd, IntPtr hWndOwner) { + // TODO: Set window owner. + return true; + } + + internal override bool SetVisible(IntPtr handle, bool visible, bool activate) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + object window = WindowMapping [hwnd.Handle]; + if (window != null) + if (visible) + ShowWindow ((IntPtr)window); + else + HideWindow ((IntPtr)window); + + if (visible) + SendMessage(handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + + HIViewSetVisible (hwnd.whole_window, visible); + HIViewSetVisible (hwnd.client_window, visible); + + hwnd.visible = visible; + hwnd.Mapped = true; + return true; + } + + internal override void SetAllowDrop (IntPtr handle, bool value) { + // Like X11 we allow drop on al windows and filter in our handler + } + + internal override DragDropEffects StartDrag (IntPtr handle, object data, DragDropEffects allowed_effects) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd == null) + throw new ArgumentException ("Attempt to begin drag from invalid window handle (" + handle.ToInt32 () + ")."); + + return Dnd.StartDrag (hwnd.client_window, data, allowed_effects); + } + + internal override void SetBorderStyle(IntPtr handle, FormBorderStyle border_style) { + Form form = Widget.FromHandle (handle) as Form; + if (form != null && form.window_manager == null && (border_style == FormBorderStyle.FixedToolWindow || + border_style == FormBorderStyle.SizableToolWindow)) { + form.window_manager = new ToolWindowManager (form); + } + + RequestNCRecalc(handle); + } + + internal override void SetMenu(IntPtr handle, Menu menu) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + hwnd.menu = menu; + + RequestNCRecalc(handle); + } + + internal override void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max) { + } + + internal override void SetWindowPos(IntPtr handle, int x, int y, int width, int height) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd == null) { + return; + } + + // Win32 automatically changes negative width/height to 0. + if (width < 0) + width = 0; + if (height < 0) + height = 0; + + // X requires a sanity check for width & height; otherwise it dies + if (hwnd.zero_sized && width > 0 && height > 0) { + if (hwnd.visible) { + HIViewSetVisible(hwnd.WholeWindow, true); + } + hwnd.zero_sized = false; + } + + if ((width < 1) || (height < 1)) { + hwnd.zero_sized = true; + HIViewSetVisible(hwnd.WholeWindow, false); + } + + // Save a server roundtrip (and prevent a feedback loop) + if ((hwnd.x == x) && (hwnd.y == y) && (hwnd.width == width) && (hwnd.height == height)) { + return; + } + + if (!hwnd.zero_sized) { + hwnd.x = x; + hwnd.y = y; + hwnd.width = width; + hwnd.height = height; + SendMessage(hwnd.client_window, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + + Widget ctrl = Widget.FromHandle (handle); + CreateParams cp = ctrl.GetCreateParams (); + Size TranslatedSize = TranslateWindowSizeToQuartzWindowSize (cp, new Size (width, height)); + Carbon.Rect rect = new Carbon.Rect (); + + if (WindowMapping [hwnd.Handle] != null) { + if (StyleSet (cp.Style, WindowStyles.WS_POPUP)) { + SetRect (ref rect, (short)x, (short)y, (short)(x+TranslatedSize.Width), (short)(y+TranslatedSize.Height)); + } else { + SetRect (ref rect, (short)x, (short)(y+MenuBarHeight), (short)(x+TranslatedSize.Width), (short)(y+MenuBarHeight+TranslatedSize.Height)); + } + SetWindowBounds ((IntPtr) WindowMapping [hwnd.Handle], 33, ref rect); + Carbon.HIRect frame_rect = new Carbon.HIRect (0, 0, TranslatedSize.Width, TranslatedSize.Height); + HIViewSetFrame (hwnd.whole_window, ref frame_rect); + SetCaretPos (Caret.Hwnd, Caret.X, Caret.Y); + } else { + Carbon.HIRect frame_rect = new Carbon.HIRect (x, y, TranslatedSize.Width, TranslatedSize.Height); + HIViewSetFrame (hwnd.whole_window, ref frame_rect); + } + PerformNCCalc(hwnd); + } + + hwnd.x = x; + hwnd.y = y; + hwnd.width = width; + hwnd.height = height; + } + + internal override void SetWindowState(IntPtr handle, FormWindowState state) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + IntPtr window = HIViewGetWindow (handle); + + switch (state) { + case FormWindowState.Minimized: { + CollapseWindow (window, true); + break; + } + case FormWindowState.Normal: { + ZoomWindow (window, 7, false); + break; + } + case FormWindowState.Maximized: { + Form form = Widget.FromHandle (hwnd.Handle) as Form; + if (form != null && form.FormBorderStyle == FormBorderStyle.None) { + Carbon.Rect rect = new Carbon.Rect (); + Carbon.HIRect bounds = CGDisplayBounds (CGMainDisplayID ()); + SetRect (ref rect, (short)0, (short)0, (short)bounds.size.width, (short)bounds.size.height); + SetWindowBounds ((IntPtr) WindowMapping [hwnd.Handle], 33, ref rect); + HIViewSetFrame (hwnd.whole_window, ref bounds); + } else { + ZoomWindow (window, 8, false); + } + break; + } + } + } + + internal override void SetWindowStyle(IntPtr handle, CreateParams cp) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + SetHwndStyles(hwnd, cp); + + if (WindowMapping [hwnd.Handle] != null) { + Carbon.WindowAttributes attributes = Carbon.WindowAttributes.kWindowCompositingAttribute | Carbon.WindowAttributes.kWindowStandardHandlerAttribute; + if ((cp.Style & ((int)WindowStyles.WS_MINIMIZEBOX)) != 0) { + attributes |= Carbon.WindowAttributes.kWindowCollapseBoxAttribute; + } + if ((cp.Style & ((int)WindowStyles.WS_MAXIMIZEBOX)) != 0) { + attributes |= Carbon.WindowAttributes.kWindowResizableAttribute | Carbon.WindowAttributes.kWindowHorizontalZoomAttribute | Carbon.WindowAttributes.kWindowVerticalZoomAttribute; + } + if ((cp.Style & ((int)WindowStyles.WS_SYSMENU)) != 0) { + attributes |= Carbon.WindowAttributes.kWindowCloseBoxAttribute; + } + if ((cp.ExStyle & ((int)WindowExStyles.WS_EX_TOOLWINDOW)) != 0) { + attributes = Carbon.WindowAttributes.kWindowStandardHandlerAttribute | Carbon.WindowAttributes.kWindowCompositingAttribute; + } + attributes |= Carbon.WindowAttributes.kWindowLiveResizeAttribute; + + Carbon.WindowAttributes outAttributes = Carbon.WindowAttributes.kWindowNoAttributes; + GetWindowAttributes ((IntPtr)WindowMapping [hwnd.Handle], ref outAttributes); + ChangeWindowAttributes ((IntPtr)WindowMapping [hwnd.Handle], attributes, outAttributes); + } + } + + internal override void SetWindowTransparency(IntPtr handle, double transparency, Color key) { + } + + internal override double GetWindowTransparency(IntPtr handle) + { + return 1.0; + } + + internal override TransparencySupport SupportsTransparency() { + return TransparencySupport.None; + } + + internal override bool SetZOrder(IntPtr handle, IntPtr after_handle, bool Top, bool Bottom) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + if (Top) { + HIViewSetZOrder (hwnd.whole_window, 2, IntPtr.Zero); + return true; + } else if (!Bottom) { + Hwnd after_hwnd = Hwnd.ObjectFromHandle (after_handle); + HIViewSetZOrder (hwnd.whole_window, 2, (after_handle == IntPtr.Zero ? IntPtr.Zero : after_hwnd.whole_window)); + } else { + HIViewSetZOrder (hwnd.whole_window, 1, IntPtr.Zero); + return true; + } + return false; + } + + internal override void ShowCursor(bool show) { + if (show) + CGDisplayShowCursor (CGMainDisplayID ()); + else + CGDisplayHideCursor (CGMainDisplayID ()); + } + + internal override object StartLoop(Thread thread) { + return new object (); + } + + [MonoTODO] + internal override bool SystrayAdd(IntPtr hwnd, string tip, Icon icon, out ToolTip tt) { + throw new NotImplementedException(); + } + + [MonoTODO] + internal override bool SystrayChange(IntPtr hwnd, string tip, Icon icon, ref ToolTip tt) { + throw new NotImplementedException(); + } + + [MonoTODO] + internal override void SystrayRemove(IntPtr hwnd, ref ToolTip tt) { + throw new NotImplementedException(); + } + + [MonoTODO] + internal override void SystrayBalloon(IntPtr hwnd, int timeout, string title, string text, ToolTipIcon icon) + { + throw new NotImplementedException (); + } + + internal override bool Text(IntPtr handle, string text) { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + if (WindowMapping [hwnd.Handle] != null) { + SetWindowTitleWithCFString ((IntPtr)(WindowMapping [hwnd.Handle]), __CFStringMakeConstantString (text)); + } + SetWidgetTitleWithCFString (hwnd.whole_window, __CFStringMakeConstantString (text)); + SetWidgetTitleWithCFString (hwnd.client_window, __CFStringMakeConstantString (text)); + return true; + } + + internal override void UpdateWindow(IntPtr handle) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (!hwnd.visible || !HIViewIsVisible (handle)) { + return; + } + + SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero); + } + + internal override bool TranslateMessage(ref MSG msg) { + return Carbon.EventHandler.TranslateMessage (ref msg); + } + + #region Reversible regions + /* + * Quartz has no concept of XOR drawing due to its compositing nature + * We fake this by mapping a overlay window on the first draw and mapping it on the second. + * This has some issues with it because its POSSIBLE for WidgetPaint.DrawReversible* to actually + * reverse two regions at once. We dont do this in MWF, but this behaviour woudn't work. + * We could in theory cache the Rectangle/Color combination to handle this behaviour. + * + * PROBLEMS: This has some flicker / banding + */ + internal void SizeWindow (Rectangle rect, IntPtr window) { + Carbon.Rect qrect = new Carbon.Rect (); + + SetRect (ref qrect, (short)rect.X, (short)rect.Y, (short)(rect.X+rect.Width), (short)(rect.Y+rect.Height)); + + SetWindowBounds (window, 33, ref qrect); + } + + internal override void DrawReversibleLine(Point start, Point end, Color backColor) { +// throw new NotImplementedException(); + } + + internal override void FillReversibleRectangle (Rectangle rectangle, Color backColor) { +// throw new NotImplementedException(); + } + + internal override void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style) { +// throw new NotImplementedException(); + } + + internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width) { + Rectangle size_rect = rect; + int new_x = 0; + int new_y = 0; + + if (ReverseWindowMapped) { + HideWindow (ReverseWindow); + ReverseWindowMapped = false; + } else { + ClientToScreen(handle, ref new_x, ref new_y); + + size_rect.X += new_x; + size_rect.Y += new_y; + + SizeWindow (size_rect, ReverseWindow); + ShowWindow (ReverseWindow); + + rect.X = 0; + rect.Y = 0; + rect.Width -= 1; + rect.Height -= 1; + + Graphics g = Graphics.FromHwnd (HIViewGetRoot (ReverseWindow)); + + for (int i = 0; i < line_width; i++) { + g.DrawRectangle (ThemeEngine.Current.ResPool.GetPen (Color.Black), rect); + rect.X += 1; + rect.Y += 1; + rect.Width -= 1; + rect.Height -= 1; + } + + g.Flush (); + g.Dispose (); + + ReverseWindowMapped = true; + } + } + #endregion + + internal override SizeF GetAutoScaleSize(Font font) { + Graphics g; + float width; + string magic_string = "The quick brown fox jumped over the lazy dog."; + double magic_number = 44.549996948242189; + + g = Graphics.FromImage (new Bitmap (1, 1)); + + width = (float) (g.MeasureString (magic_string, font).Width / magic_number); + return new SizeF(width, font.Height); + } + + internal override Point MousePosition { + get { + return mouse_position; + } + } + #endregion + + #region System information + internal override int KeyboardSpeed { get{ throw new NotImplementedException(); } } + internal override int KeyboardDelay { get{ throw new NotImplementedException(); } } + + internal override int CaptionHeight { + get { + return 19; + } + } + + internal override Size CursorSize { get{ throw new NotImplementedException(); } } + internal override bool DragFullWindows { get{ throw new NotImplementedException(); } } + internal override Size DragSize { + get { + return new Size(4, 4); + } + } + + internal override Size FrameBorderSize { + get { + return new Size (2, 2); + } + } + + internal override Size IconSize { get{ throw new NotImplementedException(); } } + internal override Size MaxWindowTrackSize { get{ throw new NotImplementedException(); } } + internal override bool MenuAccessKeysUnderlined { + get { + return false; + } + } + internal override Size MinimizedWindowSpacingSize { get{ throw new NotImplementedException(); } } + + internal override Size MinimumWindowSize { + get { + return new Size(110, 22); + } + } + + internal override Keys ModifierKeys { + get { + return KeyboardHandler.ModifierKeys; + } + } + internal override Size SmallIconSize { get{ throw new NotImplementedException(); } } + internal override int MouseButtonCount { get{ throw new NotImplementedException(); } } + internal override bool MouseButtonsSwapped { get{ throw new NotImplementedException(); } } + internal override bool MouseWheelPresent { get{ throw new NotImplementedException(); } } + + internal override MouseButtons MouseButtons { + get { + return MouseState; + } + } + + internal override Rectangle VirtualScreen { + get { + return WorkingArea; + } + } + + internal override Rectangle WorkingArea { + get { + Carbon.HIRect bounds = CGDisplayBounds (CGMainDisplayID ()); + return new Rectangle ((int)bounds.origin.x, (int)bounds.origin.y, (int)bounds.size.width, (int)bounds.size.height); + } + } + + [MonoTODO] + internal override Screen[] AllScreens { + get { + return null; + } + } + + internal override bool ThemesEnabled { + get { + return XplatUICarbon.themes_enabled; + } + } + + + #endregion + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewConvertPoint (ref Carbon.CGPoint point, IntPtr pView, IntPtr cView); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewChangeFeatures (IntPtr aView, ulong bitsin, ulong bitsout); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewFindByID (IntPtr rootWnd, Carbon.HIViewID id, ref IntPtr outPtr); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIGrowBoxViewSetTransparent (IntPtr GrowBox, bool transparency); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr HIViewGetRoot (IntPtr hWnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIObjectCreate (IntPtr cfStr, uint what, ref IntPtr hwnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIObjectRegisterSubclass (IntPtr classid, IntPtr superclassid, uint options, Carbon.EventDelegate upp, uint count, Carbon.EventTypeSpec [] list, IntPtr state, ref IntPtr cls); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewPlaceInSuperviewAt (IntPtr view, float x, float y); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewAddSubview (IntPtr parentHnd, IntPtr childHnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr HIViewGetPreviousView (IntPtr aView); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr HIViewGetSuperview (IntPtr aView); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewRemoveFromSuperview (IntPtr aView); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewSetVisible (IntPtr vHnd, bool visible); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static bool HIViewIsVisible (IntPtr vHnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewGetBounds (IntPtr vHnd, ref Carbon.HIRect r); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewScrollRect (IntPtr vHnd, ref Carbon.HIRect rect, float x, float y); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewSetZOrder (IntPtr hWnd, int cmd, IntPtr oHnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewNewTrackingArea (IntPtr inView, IntPtr inShape, UInt64 inID, ref IntPtr outRef); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr HIViewGetWindow (IntPtr aView); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int HIViewSetFrame (IntPtr view_handle, ref Carbon.HIRect bounds); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal extern static int HIViewSetNeedsDisplayInRect (IntPtr view_handle, ref Carbon.HIRect rect, bool needs_display); + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void SetRect (ref Carbon.Rect r, short left, short top, short right, short bottom); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int ActivateWindow (IntPtr windowHnd, bool inActivate); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern bool IsWindowActive (IntPtr windowHnd); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + static extern int SetAutomaticWidgetDragTrackingEnabledForWindow (IntPtr window, bool enabled); + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr GetEventDispatcherTarget (); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int SendEventToEventTarget (IntPtr evt, IntPtr target); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int ReleaseEvent (IntPtr evt); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int ReceiveNextEvent (uint evtCount, IntPtr evtTypes, double timeout, bool processEvt, ref IntPtr evt); + + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static bool IsWindowCollapsed (IntPtr hWnd); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static bool IsWindowInStandardState (IntPtr hWnd, IntPtr a, IntPtr b); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void CollapseWindow (IntPtr hWnd, bool collapse); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void ZoomWindow (IntPtr hWnd, short partCode, bool front); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int GetWindowAttributes (IntPtr hWnd, ref Carbon.WindowAttributes outAttributes); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int ChangeWindowAttributes (IntPtr hWnd, Carbon.WindowAttributes inAttributes, Carbon.WindowAttributes outAttributes); + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal extern static int GetGlobalMouse (ref Carbon.QDPoint outData); + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int BeginAppModalStateForWindow (IntPtr window); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int EndAppModalStateForWindow (IntPtr window); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int CreateNewWindow (Carbon.WindowClass klass, Carbon.WindowAttributes attributes, ref Carbon.Rect r, ref IntPtr window); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int DisposeWindow (IntPtr wHnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal extern static int ShowWindow (IntPtr wHnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal extern static int HideWindow (IntPtr wHnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal extern static bool IsWindowVisible (IntPtr wHnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int SetWindowBounds (IntPtr wHnd, uint reg, ref Carbon.Rect rect); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int GetWindowBounds (IntPtr wHnd, uint reg, ref Carbon.Rect rect); + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int SetWidgetTitleWithCFString (IntPtr hWnd, IntPtr titleCFStr); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int SetWindowTitleWithCFString (IntPtr hWnd, IntPtr titleCFStr); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal extern static IntPtr __CFStringMakeConstantString (string cString); + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + internal extern static int CFRelease (IntPtr wHnd); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static short GetMBarHeight (); + + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void AlertSoundPlay (); + + #region Cursor imports + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static Carbon.HIRect CGDisplayBounds (IntPtr displayID); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr CGMainDisplayID (); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void CGDisplayShowCursor (IntPtr display); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void CGDisplayHideCursor (IntPtr display); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void CGDisplayMoveCursorToPoint (IntPtr display, Carbon.CGPoint point); + #endregion + + #region Process imports + [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int GetCurrentProcess (ref Carbon.ProcessSerialNumber psn); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int TransformProcessType (ref Carbon.ProcessSerialNumber psn, uint type); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static int SetFrontProcess (ref Carbon.ProcessSerialNumber psn); + #endregion + + #region Dock tile imports + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr CGColorSpaceCreateDeviceRGB(); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr CGDataProviderCreateWithData (IntPtr info, IntPtr [] data, int size, IntPtr releasefunc); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static IntPtr CGImageCreate (int width, int height, int bitsPerComponent, int bitsPerPixel, int bytesPerRow, IntPtr colorspace, uint bitmapInfo, IntPtr provider, IntPtr decode, int shouldInterpolate, int intent); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void SetApplicationDockTileImage(IntPtr imageRef); + [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")] + extern static void RestoreApplicationDockTileImage(); + #endregion + } +} diff --git a/source/ShiftUI/Internal/XplatUICosmos.cs b/source/ShiftUI/Internal/XplatUICosmos.cs new file mode 100644 index 0000000..55f30df --- /dev/null +++ b/source/ShiftUI/Internal/XplatUICosmos.cs @@ -0,0 +1,2916 @@ +/* Cosmos XplatUI driver + * + * Author: Michael VanOverbeek + * Based off: XplatUIWin32 driver (ShiftUI\Internal\XplatUIWin32.cs), copyright info can be found there. + * + * Cosmos is a C# open source managed operating system, capable of basic graphics using either + * VGA or VESA BIOS Extensions, it can do full console IO, has a working FAT driver, and is + * written entirely in C# and their homebrewed high-level assembly language, X#. + * + * ShiftUI cannot access Cosmos APIs directly, so to compensate, the CosmosInterface + * class exists. This is an interface between ShiftUI and Cosmos, and it is used + * to tell the operating system where to draw pixels, what colors to use, and when + * something happens, like a window opening or closing, or an error occurring. + * + * This makes it so that ShiftUI doesn't care what graphics driver you use, as long as it + * supports 32bit RGB and you are capable of converting RGB values thrown by ShiftUI + * to the values that your graphics driver wants. + * + * This also means that your OS can deal with actually drawing windows, much like how + * Win32 and X11 does it. It's sort of a "you be the puppet, ShiftUI'll pull the strings" + * situation. + * + * The Cosmos driver is UNFINISHED, and many Win32 code remains. So, if you can continue + * on, or you want to use Cosmos features when I'm done, simply uncomment this: + */ + + //#define COSMOS + + /* + * and the C# compiler and Visual Studio will compile all of the Cosmos stuff. + * + * If you're planning on using ShiftUI for a Windows application or even Linux/Mac, + * DO NOT UNCOMMENT THAT #DEFINE. YOU WILL BREAK LOTS OF THINGS. There is a lot of + * platform-dependent stuff in Mono Winforms which is what ShiftUI is HEAVILY based + * off of, for example, when the app starts, it detects if you're on Windows, Mac or + * Linux, so that it knows whether to use Win32, X11, or Carbon. Cosmos can't really + * determine what OS it's running on because it IS an OS, so the COSMOS #define is + * used to bypass the platform-dependent stuff and make ShiftUI work specifically on + * Cosmos. + * + * Michael VanOverbeek out. + */ + +#if COSMOS +using ShiftUI; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace ShiftUI.Internal +{ + public struct CosmosScreen + { + public int Width { get; set; } + public int Height { get; set; } + public CosmosGfxDriver Driver { get; set; } + } + + public enum CosmosGfxDriver + { + VGA, + VESA, + VMware, + Dummy + } + + public enum CosmosWindowState + { + Maximized, + Minimized, + Normal, + } + + public enum CosmosWindowHint + { + MESSAGEBOX, + TOPLEVEL, + DEFAULT, + BORDERLESS, + DESKTOP, + TOOL, + } + + public class CosmosWindow + { + public IntPtr Handle { get; set; } + public Hwnd Hwnd { get; set; } + public string Title { get; set; } + public CosmosWindowState WindowState { get; set; } + public CosmosWindowHint Style { get; set; } + } + + /// + /// Because Cosmos cannot do dynamic loading and therefore + /// can't do P/Invokes, I'll let the operating system developer + /// use this interface as a backbone for letting XplatUI actually + /// interact with their operating system. + /// + /// ShiftOS won't use this, however Memphis will, and it's entire window manager + /// will reside in a class deriving from this class. + /// + public abstract class CosmosInterface + { + public abstract void SetPixel(int x, int y, Color col); + public abstract Color GetPixel(int x, int y); + public abstract CosmosScreen GetScreenInfo(); + public abstract int MouseX { get; } + public abstract int MouseY { get; } + public abstract bool MouseWheelPressed { get; } + internal List Windows = null; + public abstract void Redraw(); + + + + public bool IsWindow(IntPtr handle) + { + if(Windows == null) + { + Windows = new List(); + return false; + } + foreach(var win in Windows) + { + if (win.Handle == handle) + return true; + } + return false; + } + + /// + /// Clears the screen with a specified color. + /// + /// The color to clear to. + public void Clear(Color c) { + var scr = GetScreenInfo(); + int w = scr.Width; + int h = scr.Height; + DrawRectangle(c, new Rectangle(0, 0, w, h)); + } + + /// + /// Draws a rectangle with the specified Rectangle and color. + /// + /// The color to use. (Note that depending on the graphics config of the current OS, color quality may be reduced. + /// The Rectangle struct containing the X and Y coordinates and the width and height. + public void DrawRectangle(Color c, Rectangle rect) + { + int x = rect.X; + int y = rect.Y; + int max_width = rect.Width; + int max_height = rect.Height; + for(int i = x; i < max_width; i++) + { + for(int i2 = y; i2 < max_height; i2++) + { + if (GetPixel(i, i2) != c) + SetPixel(i, i2, c); + } + } + } + + /// + /// Draws an unfilled rectangle using the specified Rectangle, line width and color. + /// + public void DrawUnfilledRectangle(Rectangle rect, int width, Color c) + { + //top & bottom border + for(int x = rect.X; x < rect.Width; x++) + { + //top + for(int y = rect.Y; y < rect.Y + width; y++) + { + if (GetPixel(x, y) != c) + SetPixel(x, y, c); + } + + //bottom + for(int y = rect.Height - width; y < rect.Height; y++) + { + if (GetPixel(x, y) != c) + SetPixel(x, y, c); + } + } + + //In theory that code should work for left & right. + for (int y = rect.Y; y < rect.Height; y++) + { + //left + for (int x = rect.X; x < rect.X + width; x++) + { + if (GetPixel(x, y) != c) + SetPixel(x, y, c); + } + + //right + for (int x = rect.Width - width; x < rect.Width; x++) + { + if (GetPixel(x, y) != c) + SetPixel(x, y, c); + } + } + + } + } + + public class DefaultCosmosInterface : CosmosInterface + { + public const string SUI_ERR_NODRIVER = "[ShiftUI] You cannot use ShiftUI yet. You still need to load in a proper CosmosInterface."; + + public override bool MouseWheelPressed + { + get + { + Console.WriteLine(SUI_ERR_NODRIVER); + } + } + + public override int MouseX + { + get + { + Console.WriteLine(SUI_ERR_NODRIVER); + } + } + + public override int MouseY + { + get + { + Console.WriteLine(SUI_ERR_NODRIVER); + } + } + + public override Color GetPixel(int x, int y) + { + Console.WriteLine(SUI_ERR_NODRIVER); + return Color.Empty; + } + + public override CosmosScreen GetScreenInfo() + { + Console.WriteLine(SUI_ERR_NODRIVER); + var s = new CosmosScreen(); + s.Driver = CosmosGfxDriver.Dummy; + s.Width = 0; + s.Height = 0; + return s; + } + + public override void Redraw() + { + Console.WriteLine(SUI_ERR_NODRIVER); + } + + public override void SetPixel(int x, int y, Color col) + { + Console.WriteLine(SUI_ERR_NODRIVER); + } + } + + internal class XplatUICosmos : XplatUIDriver + { +#region Local Variables + private CosmosInterface cosmos = new DefaultCosmosInterface(); + private static XplatUICosmos instance; + private static int ref_count; + private static IntPtr FosterParentLast; + + internal static MouseButtons mouse_state; + internal static Point mouse_position; + internal static bool grab_confined; + internal static IntPtr grab_hwnd; + internal static Rectangle grab_area; + internal static WndProc wnd_proc; + internal static IntPtr prev_mouse_hwnd; + internal static bool caret_visible; + + internal static bool themes_enabled; + private Hashtable timer_list; + private static Queue message_queue; + private static IntPtr clip_magic = new IntPtr(27051977); + private static int scroll_width; + private static int scroll_height; + private static Hashtable wm_nc_registered; + private static Rectangle clipped_cursor_rect; + private Hashtable registered_classes; + private Hwnd HwndCreating; // the Hwnd we are currently creating (see CreateWindow) + +#endregion // Local Variables + +#region Constructor & Destructor + private XplatUICosmos() + { + // Handle singleton stuff first + ref_count = 0; + + mouse_state = MouseButtons.None; + mouse_position = Point.Empty; + + grab_confined = false; + grab_area = Rectangle.Empty; + + message_queue = new List(); + + themes_enabled = true; + + FosterParentLast = IntPtr.Zero; + + scroll_height = 25; + scroll_width = 25; + + timer_list = new Hashtable(); + registered_classes = new Hashtable(); + } +#endregion // Constructor & Destructor + +#region Private Support Methods + + private IntPtr GetFosterParent() + { + if (!cosmos.IsWindow(FosterParentLast)) + { + FosterParentLast = cosmos.CreateWindow("Foster Parent", BorderStyle.None, 0, 0, 0, 0, IntPtr.Zero); + + if (FosterParentLast == IntPtr.Zero) + { + MessageBox.Show("Could not create foster window, system error \"" + cosmos.GetLastError().ToString() = "\".", "Fatal error."); + } + } + return FosterParentLast; + } + +#region Static Properties + internal override int ActiveWindowTrackingDelay + { + get { return 0; } + } + + internal override int CaretWidth + { + get + { + return Application.CurrentSkin.CaretWidth; + } + } + + internal override int FontSmoothingContrast + { + get + { + return 0; + } + } + + internal override int FontSmoothingType + { + get + { + return 0; + } + } + + internal override int HorizontalResizeBorderThickness + { + get { return 5; } + } + + internal override bool IsActiveWindowTrackingEnabled + { + get { return false; } + } + + internal override bool IsComboBoxAnimationEnabled + { + get { return false; } + } + + internal override bool IsDropShadowEnabled + { + get + { + return false; + } + } + + internal override bool IsFontSmoothingEnabled + { + get { return false; } + } + + internal override bool IsHotTrackingEnabled + { + get { return true; } + } + + internal override bool IsIconTitleWrappingEnabled + { + get { return true; } + } + + internal override bool IsKeyboardPreferred + { + get { return false; } + } + + internal override bool IsListBoxSmoothScrollingEnabled + { + get { return false; } + } + + internal override bool IsMenuAnimationEnabled + { + get { return false; } + } + + internal override bool IsMenuFadeEnabled + { + get { return false; } + } + + internal override bool IsMinimizeRestoreAnimationEnabled + { + get + { + return false; + } + } + + internal override bool IsSelectionFadeEnabled + { + get { return false; } + } + + internal override bool IsSnapToDefaultEnabled + { + get { return false; } + } + + internal override bool IsTitleBarGradientEnabled + { + get { return false; } + } + + internal override bool IsToolTipAnimationEnabled + { + get { return false; } + } + + internal override Size MenuBarButtonSize + { + get + { + return new Size(32, 32); + } + } + + public override Size MenuButtonSize + { + get + { + return new Size(32, 32); + } + } + + internal override int MenuShowDelay + { + get { return 0; } + } + + internal override int MouseSpeed + { + get { return Application.CurrentSkin.MouseSpeed; } + } + + internal override LeftRightAlignment PopupMenuAlignment + { + get { return LeftRightAlignment.Left; } + } + + internal override PowerStatus PowerStatus + { + get + { + //Cosmos doesn't have power management. Sadly. + return new PowerStatus(BatteryChargeStatus.Unknown, "No power status for you.".Length, 0.0, 0, PowerLineStatus.Unknown); + } + } + + internal override int SizingBorderWidth + { + get { return Application.CurrentSkin.SizeBorderWidth; } + } + + internal override Size SmallCaptionButtonSize + { + get + { + return new Size(32, 32); + } + } + + internal override bool UIEffectsEnabled + { + get { return false; } + } + + internal override int VerticalResizeBorderThickness + { + get { return 5; } + } + + internal override void RaiseIdle(EventArgs e) + { + if (Idle != null) + Idle(this, e); + } + + internal override Keys ModifierKeys + { + get + { + short state; + Keys key_state; + + key_state = Keys.None; + + return key_state; + } + } + + internal override MouseButtons MouseButtons + { + get + { + return cosmos.MouseState; + } + } + + internal override Point MousePosition + { + get + { + return new Point(cosmos.MouseX, cosmos.MouseY); + } + } + + internal override Size MouseHoverSize + { + get + { + int width = 4; + int height = 4; + return new Size(width, height); + } + } + + internal override int MouseHoverTime + { + get + { + int time = 500; + return time; + } + } + + internal override int MouseWheelScrollDelta + { + get + { + int delta = 120; + return delta; + } + } + + internal override int HorizontalScrollBarHeight + { + get + { + return scroll_height; + } + } + + internal override bool UserClipWontExposeParent + { + get + { + return false; + } + } + + + internal override int VerticalScrollBarWidth + { + get + { + return scroll_width; + } + } + + internal override int MenuHeight + { + get + { + return 32; + } + } + + internal override Size Border3DSize + { + get + { + return new Size(2, 2); + } + } + + internal override Size BorderSize + { + get + { + return new Size(2, 2); + } + } + + internal override bool DropTarget + { + get + { + return false; + } + + set + { + if (value) + { + //throw new NotImplementedException("Need to figure out D'n'D for Win32"); + } + } + } + + internal override Size CaptionButtonSize + { + get + { + return new Size(64, 32); + } + } + + internal override int CaptionHeight + { + get + { + return 35; + } + } + + internal override Size CursorSize + { + get + { + return new Size(32, 32); + } + } + + internal override bool DragFullWindows + { + get + { + return false; + } + } + + internal override Size DragSize + { + get + { + return new Size(32, 32); + } + } + + internal override Size DoubleClickSize + { + get + { + return new Size(36, 36); //thanks to @InternetUnexploder from the Cosmos Gitter chat, I know the raw value I need to put here :P + } + } + + internal override int DoubleClickTime + { + get + { + return 1000; + } + } + + internal override Size FixedFrameBorderSize + { + get + { + return new Size(2, 2); + } + } + + internal override Size FrameBorderSize + { + get + { + return new Size(4, 4); + } + } + + internal override Size IconSize + { + get + { + return new Size(16, 16); + } + } + + internal override Size MaxWindowTrackSize + { + get + { + return new Size(59, 60); + } + } + + internal override bool MenuAccessKeysUnderlined + { + get + { + return false; + } + } + + internal override Size MinimizedWindowSize + { + get + { + return new Size(0, 0); + } + } + + internal override Size MinimizedWindowSpacingSize + { + get + { + return new Size(0, 0); + } + } + + internal override Size MinimumWindowSize + { + get + { + return new Size(50, 50); + } + } + + internal override Size MinWindowTrackSize + { + get + { + return new Size(50, 50); + } + } + + internal override Size SmallIconSize + { + get + { + return new Size(8, 8); + } + } + + internal override int MouseButtonCount + { + get + { + return 3; + } + } + + internal override bool MouseButtonsSwapped + { + get + { + return false; + } + } + + internal override bool MouseWheelPresent + { + get + { + return cosmos.MouseWheelPressed; + } + } + + internal override Rectangle VirtualScreen + { + get + { + var s = cosmos.GetScreenInfo(); + return new Rectangle(s.X, s.Y, s.Width, s.Height); + } + } + + internal override Rectangle WorkingArea + { + get + { + return VirtualScreen; + } + } + + [MonoTODO] + internal override Screen[] AllScreens + { + get + { + // Can't use this sadly. + return null; + } + } + + internal override bool ThemesEnabled + { + get + { + return true; + } + } + + internal override bool RequiresPositiveClientAreaSize + { + get + { + return false; + } + } + + public override int ToolWindowCaptionHeight + { + get + { + return 35; //Drawing will be done entirely by the developer itself. Do we really care about the tool window size? + } + } + + public override Size ToolWindowCaptionButtonSize + { + get + { + return new Size(32, 32); + } + } +#endregion // Static Properties + +#region Singleton Specific Code + public static XplatUICosmos GetInstance() + { + if (instance == null) + { + instance = new XplatUICosmos(); + } + ref_count++; + return instance; + } + + public int Reference + { + get + { + return ref_count; + } + } +#endregion + +#region Public Static Methods + internal override IntPtr InitializeDriver() + { + cosmos.OnInit(); + return IntPtr.Zero; + } + + internal override void ShutdownDriver(IntPtr token) + { + Console.WriteLine("[ShiftUI] Stopping Cosmos driver..."); + cosmos.OnShutdown(); + } + + + internal void Version() + { + Console.WriteLine($"ShiftUI version {Application.ShiftUIVersionString}, running in the cosmos, on {cosmos.OSName} version {cosmos.OSVersionString}."); + } + + string GetSoundAlias(AlertType alert) + { + return ""; + } + + internal override void AudibleAlert(AlertType alert) + { + //Cosmos cannot do audio. + } + + internal override void BeginMoveResize(IntPtr handle) + { + //If the Mono devs that worked on the Win32 driver didn't know what this did, what + //makes you think I will? + } + + internal override void GetDisplaySize(out Size size) + { + //get screen metrics from OS + var screen = cosmos.GetScreenInfo(); + //push the data out. + size = new Size(screen.Width, screen.Height); + } + + internal override void EnableThemes() + { + //Themes will forever be enabled. + } + + //[MichaelComment(Message = "Yay. I just LOVE messing with Win32 stuff and porting it to Cosmos.")] + internal override IntPtr CreateWindow(CreateParams cp) + { + //I think I'll let this do it's thing it's own way but just change where the new Hwnd gets placed. + if (cosmos.Windows == null) + cosmos.Windows = new List(); + IntPtr WindowHandle; + IntPtr ParentHandle; + Hwnd hwnd; + + hwnd = new Hwnd(); + + ParentHandle = cp.Parent; + + if ((ParentHandle == IntPtr.Zero) && (cp.Style & (int)(WindowStyles.WS_CHILD)) != 0) + { + // We need to use our foster parent window until this poor child gets it's parent assigned + ParentHandle = GetFosterParent(); + } + + if (((cp.Style & (int)(WindowStyles.WS_CHILD | WindowStyles.WS_POPUP)) == 0) && ((cp.ExStyle & (int)WindowExStyles.WS_EX_APPWINDOW) == 0)) + { + // If we want to be hidden from the taskbar we need to be 'owned' by + // something not on the taskbar. FosterParent is just that + ParentHandle = GetFosterParent(); + } + + Point location; + if (cp.HasWindowManager) + { + location = Hwnd.GetNextStackedFormLocation(cp, Hwnd.ObjectFromHandle(cp.Parent)); + } + else + { + location = new Point(cp.X, cp.Y); + } + + string class_name = RegisterWindowClass(cp.ClassStyle); + HwndCreating = hwnd; + + // We cannot actually send the WS_EX_MDICHILD flag to Windows because we + // are faking MDI, not uses Windows' version. + if ((cp.WindowExStyle & WindowExStyles.WS_EX_MDICHILD) == WindowExStyles.WS_EX_MDICHILD) + cp.WindowExStyle ^= WindowExStyles.WS_EX_MDICHILD; + + WindowHandle = cosmos.Windows.Count + 1; + + HwndCreating = null; + + if (WindowHandle == IntPtr.Zero) + { + MessageBox.Show("An error happened while showing a window... Fascinating.", "Fatal error."); + } + + hwnd.ClientWindow = WindowHandle; + hwnd.Mapped = true; + cosmos.Windows.Add(hwnd); + + return WindowHandle; + } + + internal override IntPtr CreateWindow(IntPtr Parent, int X, int Y, int Width, int Height) + { + CreateParams create_params = new CreateParams(); + + create_params.Caption = ""; + create_params.X = X; + create_params.Y = Y; + create_params.Width = Width; + create_params.Height = Height; + + create_params.ClassName = XplatUI.GetDefaultClassName(GetType()); + create_params.ClassStyle = 0; + create_params.ExStyle = 0; + create_params.Parent = IntPtr.Zero; + create_params.Param = 0; + + return CreateWindow(create_params); + } + + internal override void DestroyWindow(IntPtr handle) + { + Hwnd hwnd; + + foreach(var win in cosmos.Windows) + { + if (win.Handle == handle) + hwnd = win; + } + if (hwnd == null) + MessageBox.Show("An error occurred while destroying a window.", "Fatal error."); + cosmos.Windows.Remove(hwnd); + cosmos.OnDestroyWindow(hwnd); //tell the OS to redraw that area... + hwnd.Dispose(); + return; + } + + internal override void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max) + { + // We do nothing, Form has to handle WM_GETMINMAXINFO + } + + + internal override FormWindowState GetWindowState(IntPtr handle) + { + CosmosWindowStyle style; + + style = cosmos.GetWindowState(handle); + switch(style) + { + case CosmosWindowStyle.Maximized: + return FormWindowState.Maximized; + case CosmosWindowStyle.Minimized: + return FormWindowState.Minimized; + } + return FormWindowState.Normal; + } + + internal override void SetWindowState(IntPtr hwnd, FormWindowState state) + { + switch (state) + { + case FormWindowState.Normal: + { + Win32ShowWindow(hwnd, WindowPlacementFlags.SW_RESTORE); + return; + } + + case FormWindowState.Minimized: + { + Win32ShowWindow(hwnd, WindowPlacementFlags.SW_MINIMIZE); + return; + } + + case FormWindowState.Maximized: + { + Win32ShowWindow(hwnd, WindowPlacementFlags.SW_MAXIMIZE); + return; + } + } + } + + internal override void SetWindowStyle(IntPtr handle, CreateParams cp) + { + + Win32SetWindowLong(handle, WindowLong.GWL_STYLE, (uint)cp.Style); + Win32SetWindowLong(handle, WindowLong.GWL_EXSTYLE, (uint)cp.ExStyle); + + // From MSDN: + // Certain window data is cached, so changes you make using SetWindowLong + // will not take effect until you call the SetWindowPos function. Specifically, + // if you change any of the frame styles, you must call SetWindowPos with + // the SWP_FRAMECHANGED flag for the cache to be updated properly. + if (cp.control is Form) + XplatUI.RequestNCRecalc(handle); + } + + internal override double GetWindowTransparency(IntPtr handle) + { + LayeredWindowAttributes lwa; + COLORREF clrRef; + byte alpha; + + if (0 == Win32GetLayeredWindowAttributes(handle, out clrRef, out alpha, out lwa)) + return 1.0; + + return ((double)alpha) / 255.0; + } + + internal override void SetWindowTransparency(IntPtr handle, double transparency, Color key) + { + LayeredWindowAttributes lwa = LayeredWindowAttributes.LWA_ALPHA; + byte opacity = (byte)(transparency * 255); + COLORREF clrRef = new COLORREF(); + if (key != Color.Empty) + { + clrRef.R = key.R; + clrRef.G = key.G; + clrRef.B = key.B; + lwa = (LayeredWindowAttributes)((int)lwa | (int)LayeredWindowAttributes.LWA_COLORKEY); + } + RECT rc; + rc.right = 1000; + rc.bottom = 1000; + Win32SetLayeredWindowAttributes(handle, clrRef, opacity, lwa); + } + + TransparencySupport support; + bool queried_transparency_support; + internal override TransparencySupport SupportsTransparency() + { + if (queried_transparency_support) + return support; + + bool flag; + support = TransparencySupport.None; + + flag = true; + try + { + Win32SetLayeredWindowAttributes(IntPtr.Zero, new COLORREF(), 255, LayeredWindowAttributes.LWA_ALPHA); + } + catch (EntryPointNotFoundException) { flag = false; } + catch { /* swallow everything else */ } + + if (flag) support |= TransparencySupport.Set; + + flag = true; + try + { + LayeredWindowAttributes lwa; + COLORREF clrRef; + byte alpha; + + Win32GetLayeredWindowAttributes(IntPtr.Zero, out clrRef, out alpha, out lwa); + } + catch (EntryPointNotFoundException) { flag = false; } + catch { /* swallow everything else */ } + + if (flag) support |= TransparencySupport.Get; + + queried_transparency_support = true; + return support; + } + + internal override void UpdateWindow(IntPtr handle) + { + Win32UpdateWindow(handle); + } + + internal override PaintEventArgs PaintEventStart(ref Message msg, IntPtr handle, bool client) + { + IntPtr hdc; + PAINTSTRUCT ps; + PaintEventArgs paint_event; + RECT rect; + Rectangle clip_rect; + Hwnd hwnd; + + clip_rect = new Rectangle(); + rect = new RECT(); + ps = new PAINTSTRUCT(); + + hwnd = Hwnd.ObjectFromHandle(msg.HWnd); + + if (client) + { + if (Win32GetUpdateRect(msg.HWnd, ref rect, false)) + { + if (handle != msg.HWnd) + { + // We need to validate the window where the paint message + // was generated, otherwise we'll never stop getting paint + // messages. + Win32GetClientRect(msg.HWnd, out rect); + Win32ValidateRect(msg.HWnd, ref rect); + hdc = Win32GetDC(handle); + } + else + { + hdc = Win32BeginPaint(handle, ref ps); + rect = ps.rcPaint; + } + } + else + { + hdc = Win32GetDC(handle); + } + clip_rect = rect.ToRectangle(); + } + else + { + hdc = Win32GetWindowDC(handle); + + // HACK this in for now + Win32GetWindowRect(handle, out rect); + clip_rect = new Rectangle(0, 0, rect.Width, rect.Height); + } + + // If we called BeginPaint, store the PAINTSTRUCT, + // otherwise store hdc, so that PaintEventEnd can know + // whether to call EndPaint or ReleaseDC. + if (ps.hdc != IntPtr.Zero) + { + hwnd.drawing_stack.Push(ps); + } + else + { + hwnd.drawing_stack.Push(hdc); + } + + Graphics dc = Graphics.FromHdc(hdc); + hwnd.drawing_stack.Push(dc); + + paint_event = new PaintEventArgs(dc, clip_rect); + + return paint_event; + } + + internal override void PaintEventEnd(ref Message m, IntPtr handle, bool client) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(m.HWnd); + + Graphics dc = (Graphics)hwnd.drawing_stack.Pop(); + dc.Dispose(); + + object o = hwnd.drawing_stack.Pop(); + if (o is IntPtr) + { + IntPtr hdc = (IntPtr)o; + Win32ReleaseDC(handle, hdc); + } + else if (o is PAINTSTRUCT) + { + PAINTSTRUCT ps = (PAINTSTRUCT)o; + Win32EndPaint(handle, ref ps); + } + } + + + internal override void SetWindowPos(IntPtr handle, int x, int y, int width, int height) + { + Win32MoveWindow(handle, x, y, width, height, true); + return; + } + + internal override void GetWindowPos(IntPtr handle, bool is_toplevel, out int x, out int y, out int width, out int height, out int client_width, out int client_height) + { + IntPtr parent; + RECT rect; + POINT pt; + + Win32GetWindowRect(handle, out rect); + width = rect.right - rect.left; + height = rect.bottom - rect.top; + + pt.x = rect.left; + pt.y = rect.top; + + parent = Win32GetAncestor(handle, AncestorType.GA_PARENT); + if (parent != IntPtr.Zero && parent != Win32GetDesktopWindow()) + Win32ScreenToClient(parent, ref pt); + + x = pt.x; + y = pt.y; + + Win32GetClientRect(handle, out rect); + client_width = rect.right - rect.left; + client_height = rect.bottom - rect.top; + return; + } + + internal override void Activate(IntPtr handle) + { + Win32SetActiveWindow(handle); + // delayed timer enabled + lock (timer_list) + { + foreach (Timer t in timer_list.Values) + { + if (t.Enabled && t.window == IntPtr.Zero) + { + t.window = handle; + int id = t.GetHashCode(); + Win32SetTimer(handle, id, (uint)t.Interval, IntPtr.Zero); + } + } + } + } + + internal override void Invalidate(IntPtr handle, Rectangle rc, bool clear) + { + cosmos.Redraw(); //I don't want to make it too hard for devs to deal with this... + } + + + internal override void InvalidateNC(IntPtr handle) + { + cosmos.Redraw(); + } + + private IntPtr InternalWndProc(IntPtr hWnd, Msg msg, IntPtr wParam, IntPtr lParam) + { + if (HwndCreating != null && HwndCreating.ClientWindow == IntPtr.Zero) + HwndCreating.ClientWindow = hWnd; + return NativeWindow.WndProc(hWnd, msg, wParam, lParam); + } + + internal override IntPtr DefWndProc(ref Message msg) + { + msg.Result = Win32DefWindowProc(msg.HWnd, (Msg)msg.Msg, msg.WParam, msg.LParam); + return msg.Result; + } + + internal override void HandleException(Exception e) + { + StackTrace st = new StackTrace(e); + Win32MessageBox(IntPtr.Zero, e.Message + st.ToString(), "Exception", 0); + Console.WriteLine("{0}{1}", e.Message, st.ToString()); + } + + internal override void DoEvents() + { + MSG msg = new MSG(); + + while (GetMessage(ref msg, IntPtr.Zero, 0, 0, false)) + { + Message m = Message.Create(msg.hwnd, (int)msg.message, msg.wParam, msg.lParam); + + if (Application.FilterMessage(ref m)) + continue; + + XplatUI.TranslateMessage(ref msg); + XplatUI.DispatchMessage(ref msg); + } + } + + internal override bool PeekMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) + { + return Win32PeekMessage(ref msg, hWnd, wFilterMin, wFilterMax, flags); + } + + internal override void PostQuitMessage(int exitCode) + { + Win32PostQuitMessage(exitCode); + } + + internal override void RequestAdditionalWM_NCMessages(IntPtr hwnd, bool hover, bool leave) + { + if (wm_nc_registered == null) + wm_nc_registered = new Hashtable(); + + TMEFlags flags = TMEFlags.TME_NONCLIENT; + if (hover) + flags |= TMEFlags.TME_HOVER; + if (leave) + flags |= TMEFlags.TME_LEAVE; + + if (flags == TMEFlags.TME_NONCLIENT) + { + if (wm_nc_registered.Contains(hwnd)) + { + wm_nc_registered.Remove(hwnd); + } + } + else + { + if (!wm_nc_registered.Contains(hwnd)) + { + wm_nc_registered.Add(hwnd, flags); + } + else + { + wm_nc_registered[hwnd] = flags; + } + } + } + + internal override void RequestNCRecalc(IntPtr handle) + { + Win32SetWindowPos(handle, IntPtr.Zero, 0, 0, 0, 0, SetWindowPosFlags.SWP_FRAMECHANGED | SetWindowPosFlags.SWP_NOOWNERZORDER | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE); + } + + internal override void ResetMouseHover(IntPtr handle) + { + TRACKMOUSEEVENT tme; + + tme = new TRACKMOUSEEVENT(); + tme.size = Marshal.SizeOf(tme); + tme.hWnd = handle; + tme.dwFlags = TMEFlags.TME_LEAVE | TMEFlags.TME_HOVER; + Win32TrackMouseEvent(ref tme); + } + + + internal override bool GetMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax) + { + return GetMessage(ref msg, hWnd, wFilterMin, wFilterMax, true); + } + + private bool GetMessage(ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, bool blocking) + { + bool result; + + msg.refobject = 0; + if (RetrieveMessage(ref msg)) + { + return true; + } + + if (blocking) + { + result = Win32GetMessage(ref msg, hWnd, wFilterMin, wFilterMax); + } + else + { + result = Win32PeekMessage(ref msg, hWnd, wFilterMin, wFilterMax, (uint)PeekMessageFlags.PM_REMOVE); + if (!result) + { + return false; + } + } + + // We need to fake WM_MOUSE_ENTER + switch (msg.message) + { + case Msg.WM_LBUTTONDOWN: + { + mouse_state |= MouseButtons.Left; + break; + } + + case Msg.WM_MBUTTONDOWN: + { + mouse_state |= MouseButtons.Middle; + break; + } + + case Msg.WM_RBUTTONDOWN: + { + mouse_state |= MouseButtons.Right; + break; + } + + case Msg.WM_LBUTTONUP: + { + mouse_state &= ~MouseButtons.Left; + break; + } + + case Msg.WM_MBUTTONUP: + { + mouse_state &= ~MouseButtons.Middle; + break; + } + + case Msg.WM_RBUTTONUP: + { + mouse_state &= ~MouseButtons.Right; + break; + } + + case Msg.WM_ASYNC_MESSAGE: + { + XplatUIDriverSupport.ExecuteClientMessage((GCHandle)msg.lParam); + break; + } + + case Msg.WM_MOUSEMOVE: + { + if (msg.hwnd != prev_mouse_hwnd) + { + TRACKMOUSEEVENT tme; + + mouse_state = Widget.FromParamToMouseButtons((int)msg.lParam.ToInt32()); + + // The current message will be sent out next time around + StoreMessage(ref msg); + + // This is the message we want to send at this point + msg.message = Msg.WM_MOUSE_ENTER; + + prev_mouse_hwnd = msg.hwnd; + + tme = new TRACKMOUSEEVENT(); + tme.size = Marshal.SizeOf(tme); + tme.hWnd = msg.hwnd; + tme.dwFlags = TMEFlags.TME_LEAVE | TMEFlags.TME_HOVER; + Win32TrackMouseEvent(ref tme); + return result; + } + break; + } + + case Msg.WM_NCMOUSEMOVE: + { + if (wm_nc_registered == null || !wm_nc_registered.Contains(msg.hwnd)) + break; + + mouse_state = Widget.FromParamToMouseButtons((int)msg.lParam.ToInt32()); + + TRACKMOUSEEVENT tme; + + tme = new TRACKMOUSEEVENT(); + tme.size = Marshal.SizeOf(tme); + tme.hWnd = msg.hwnd; + tme.dwFlags = (TMEFlags)wm_nc_registered[msg.hwnd]; + Win32TrackMouseEvent(ref tme); + return result; + } + + case Msg.WM_DROPFILES: + { + return Win32DnD.HandleWMDropFiles(ref msg); + } + + case Msg.WM_MOUSELEAVE: + { + prev_mouse_hwnd = IntPtr.Zero; + break; + } + + case Msg.WM_TIMER: + { + Timer timer = (Timer)timer_list[(int)msg.wParam]; + + if (timer != null) + { + timer.FireTick(); + } + break; + } + } + + return result; + } + + internal override bool TranslateMessage(ref MSG msg) + { + return Win32TranslateMessage(ref msg); + } + + internal override IntPtr DispatchMessage(ref MSG msg) + { + return Win32DispatchMessage(ref msg); + } + + internal override bool SetZOrder(IntPtr hWnd, IntPtr AfterhWnd, bool Top, bool Bottom) + { + if (Top) + { + Win32SetWindowPos(hWnd, SetWindowPosZOrder.HWND_TOP, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE); + return true; + } + else if (!Bottom) + { + Win32SetWindowPos(hWnd, AfterhWnd, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE); + } + else + { + Win32SetWindowPos(hWnd, (IntPtr)SetWindowPosZOrder.HWND_BOTTOM, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE); + return true; + } + return false; + } + + internal override bool SetTopmost(IntPtr hWnd, bool Enabled) + { + if (Enabled) + { + Win32SetWindowPos(hWnd, SetWindowPosZOrder.HWND_TOPMOST, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE); + return true; + } + else + { + Win32SetWindowPos(hWnd, SetWindowPosZOrder.HWND_NOTOPMOST, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE); + return true; + } + } + + internal override bool SetOwner(IntPtr hWnd, IntPtr hWndOwner) + { + Win32SetWindowLong(hWnd, WindowLong.GWL_HWNDPARENT, (uint)hWndOwner); + return true; + } + + internal override bool Text(IntPtr handle, string text) + { + Win32SetWindowText(handle, text); + return true; + } + + internal override bool GetText(IntPtr handle, out string text) + { + StringBuilder sb; + + sb = new StringBuilder(256); + Win32GetWindowText(handle, sb, sb.Capacity); + text = sb.ToString(); + return true; + } + + internal override bool SetVisible(IntPtr handle, bool visible, bool activate) + { + if (visible) + { + Widget c = Widget.FromHandle(handle); + if (c is Form) + { + Form f; + + f = (Form)Widget.FromHandle(handle); + WindowPlacementFlags flags = WindowPlacementFlags.SW_SHOWNORMAL; + switch (f.WindowState) + { + case FormWindowState.Normal: flags = WindowPlacementFlags.SW_SHOWNORMAL; break; + case FormWindowState.Minimized: flags = WindowPlacementFlags.SW_MINIMIZE; break; + case FormWindowState.Maximized: flags = WindowPlacementFlags.SW_MAXIMIZE; break; + } + + if (!f.ActivateOnShow) + flags = WindowPlacementFlags.SW_SHOWNOACTIVATE; + + Win32ShowWindow(handle, flags); + } + else + { + if (c.ActivateOnShow) + Win32ShowWindow(handle, WindowPlacementFlags.SW_SHOWNORMAL); + else + Win32ShowWindow(handle, WindowPlacementFlags.SW_SHOWNOACTIVATE); + } + } + else + { + Win32ShowWindow(handle, WindowPlacementFlags.SW_HIDE); + } + return true; + } + + internal override bool IsEnabled(IntPtr handle) + { + return IsWindowEnabled(handle); + } + + internal override bool IsKeyLocked(VirtualKeys key) + { + return (Win32GetKeyState(key) & 1) == 1; + } + + internal override bool IsVisible(IntPtr handle) + { + return IsWindowVisible(handle); + } + + internal override IntPtr SetParent(IntPtr handle, IntPtr parent) + { + Widget c = Widget.FromHandle(handle); + if (parent == IntPtr.Zero) + { + if (!(c is Form)) + { + Win32ShowWindow(handle, WindowPlacementFlags.SW_HIDE); + } + } + else + { + if (!(c is Form)) + { + SetVisible(handle, c.is_visible, true); + } + } + // The Win32SetParent is lame, it can very well move the window + // ref: http://groups.google.com/group/microsoft.public.vb.winapi/browse_thread/thread/1b82ccc54231ecee/afa82835bfc0422a%23afa82835bfc0422a + // Here we save the position before changing the parent, and if it has changed afterwards restore it. + // Another possibility would be to intercept WM_WINDOWPOSCHANGING and restore the coords there, but this would require plumbing in weird places + // (either inside Widget or add handling to InternalWndProc) + // We also need to remove WS_CHILD if making the window parent-less, and add it if we're parenting it. + RECT rect, rect2; + IntPtr result; + WindowStyles style, new_style; + + Win32GetWindowRect(handle, out rect); + style = (WindowStyles)Win32GetWindowLong(handle, WindowLong.GWL_STYLE); + + if (parent == IntPtr.Zero) + { + new_style = style & ~WindowStyles.WS_CHILD; + result = Win32SetParent(handle, GetFosterParent()); + } + else + { + new_style = style | WindowStyles.WS_CHILD; + result = Win32SetParent(handle, parent); + } + if (style != new_style && c is Form) + { + Win32SetWindowLong(handle, WindowLong.GWL_STYLE, (uint)new_style); + } + Win32GetWindowRect(handle, out rect2); + if (rect.top != rect2.top && rect.left != rect2.left && c is Form) + { + Win32SetWindowPos(handle, IntPtr.Zero, rect.top, rect.left, rect.Width, rect.Height, SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOREDRAW | SetWindowPosFlags.SWP_NOOWNERZORDER | SetWindowPosFlags.SWP_NOENDSCHANGING | SetWindowPosFlags.SWP_NOACTIVATE); + } + return result; + } + + // If we ever start using this, we should probably replace FosterParent with IntPtr.Zero + internal override IntPtr GetParent(IntPtr handle) + { + return Win32GetParent(handle); + } + + // This is a nop on win32 and x11 + internal override IntPtr GetPreviousWindow(IntPtr handle) + { + return handle; + } + + internal override void GrabWindow(IntPtr hWnd, IntPtr ConfineToHwnd) + { + grab_hwnd = hWnd; + Win32SetCapture(hWnd); + + if (ConfineToHwnd != IntPtr.Zero) + { + RECT window_rect; + Win32GetWindowRect(ConfineToHwnd, out window_rect); + Win32GetClipCursor(out clipped_cursor_rect); + Win32ClipCursor(ref window_rect); + } + } + + internal override void GrabInfo(out IntPtr hWnd, out bool GrabConfined, out Rectangle GrabArea) + { + hWnd = grab_hwnd; + GrabConfined = grab_confined; + GrabArea = grab_area; + } + + internal override void UngrabWindow(IntPtr hWnd) + { + if (!(clipped_cursor_rect.top == 0 && clipped_cursor_rect.bottom == 0 && clipped_cursor_rect.left == 0 && clipped_cursor_rect.right == 0)) + { + Win32ClipCursor(ref clipped_cursor_rect); + clipped_cursor_rect = new RECT(); + } + + Win32ReleaseCapture(); + grab_hwnd = IntPtr.Zero; + } + + internal override bool CalculateWindowRect(ref Rectangle ClientRect, CreateParams cp, Menu menu, out Rectangle WindowRect) + { + RECT rect; + + rect.left = ClientRect.Left; + rect.top = ClientRect.Top; + rect.right = ClientRect.Right; + rect.bottom = ClientRect.Bottom; + + if (!Win32AdjustWindowRectEx(ref rect, cp.Style, menu != null, cp.ExStyle)) + { + WindowRect = new Rectangle(ClientRect.Left, ClientRect.Top, ClientRect.Width, ClientRect.Height); + return false; + } + + WindowRect = new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); + return true; + } + + internal override void SetCursor(IntPtr window, IntPtr cursor) + { + Win32SetCursor(cursor); + return; + } + + internal override void ShowCursor(bool show) + { + Win32ShowCursor(show); + } + + internal override void OverrideCursor(IntPtr cursor) + { + Win32SetCursor(cursor); + } + + internal override IntPtr DefineCursor(Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) + { + IntPtr cursor; + Bitmap cursor_bitmap; + Bitmap cursor_mask; + Byte[] cursor_bits; + Byte[] mask_bits; + Color pixel; + int width; + int height; + + // Win32 only allows creation cursors of a certain size + if ((bitmap.Width != Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR)) || (bitmap.Width != Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR))) + { + cursor_bitmap = new Bitmap(bitmap, new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR), Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR))); + cursor_mask = new Bitmap(mask, new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR), Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR))); + } + else + { + cursor_bitmap = bitmap; + cursor_mask = mask; + } + + width = cursor_bitmap.Width; + height = cursor_bitmap.Height; + + cursor_bits = new Byte[(width / 8) * height]; + mask_bits = new Byte[(width / 8) * height]; + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + pixel = cursor_bitmap.GetPixel(x, y); + + if (pixel == cursor_pixel) + { + cursor_bits[y * width / 8 + x / 8] |= (byte)(0x80 >> (x % 8)); + } + + pixel = cursor_mask.GetPixel(x, y); + + if (pixel == mask_pixel) + { + mask_bits[y * width / 8 + x / 8] |= (byte)(0x80 >> (x % 8)); + } + } + } + + cursor = Win32CreateCursor(IntPtr.Zero, xHotSpot, yHotSpot, width, height, mask_bits, cursor_bits); + + return cursor; + } + + internal override Bitmap DefineStdCursorBitmap(StdCursor id) + { + // We load the cursor, create a bitmap, draw the cursor onto the bitmap and return the bitmap. + IntPtr cursor = DefineStdCursor(id); + // Windows only have one possible cursor size! + int width = Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR); + int height = Win32GetSystemMetrics(SystemMetrics.SM_CYCURSOR); + Bitmap bmp = new Bitmap(width, height); + Graphics gc = Graphics.FromImage(bmp); + IntPtr hdc = gc.GetHdc(); + Win32DrawIcon(hdc, 0, 0, cursor); + gc.ReleaseHdc(hdc); + gc.Dispose(); + return bmp; + } + + [MonoTODO("Define the missing cursors")] + internal override IntPtr DefineStdCursor(StdCursor id) + { + switch (id) + { + case StdCursor.AppStarting: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_APPSTARTING); + case StdCursor.Arrow: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); + case StdCursor.Cross: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_CROSS); + case StdCursor.Default: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); + case StdCursor.Hand: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_HAND); + case StdCursor.Help: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_HELP); + case StdCursor.HSplit: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.IBeam: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_IBEAM); + case StdCursor.No: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_NO); + case StdCursor.NoMove2D: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.NoMoveHoriz: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.NoMoveVert: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.PanEast: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.PanNE: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.PanNorth: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.PanNW: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.PanSE: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.PanSouth: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.PanSW: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.PanWest: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.SizeAll: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZEALL); + case StdCursor.SizeNESW: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZENESW); + case StdCursor.SizeNS: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZENS); + case StdCursor.SizeNWSE: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZENWSE); + case StdCursor.SizeWE: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZEWE); + case StdCursor.UpArrow: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_UPARROW); + case StdCursor.VSplit: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.WaitCursor: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_WAIT); + } + throw new NotImplementedException(); + } + + internal override void DestroyCursor(IntPtr cursor) + { + if ((cursor.ToInt32() < (int)LoadCursorType.First) || (cursor.ToInt32() > (int)LoadCursorType.Last)) + { + Win32DestroyCursor(cursor); + } + } + + [MonoTODO] + internal override void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y) + { + ICONINFO ii = new ICONINFO(); + + if (!Win32GetIconInfo(cursor, out ii)) + throw new Win32Exception(); + + width = 20; + height = 20; + hotspot_x = ii.xHotspot; + hotspot_y = ii.yHotspot; + } + + internal override void SetCursorPos(IntPtr handle, int x, int y) + { + Win32SetCursorPos(x, y); + } + + internal override Region GetClipRegion(IntPtr hwnd) + { + Region region; + + region = new Region(); + + Win32GetWindowRgn(hwnd, region.GetHrgn(Graphics.FromHwnd(hwnd))); + + return region; + } + + internal override void SetClipRegion(IntPtr hwnd, Region region) + { + if (region == null) + Win32SetWindowRgn(hwnd, IntPtr.Zero, true); + else + Win32SetWindowRgn(hwnd, region.GetHrgn(Graphics.FromHwnd(hwnd)), true); + } + + internal override void EnableWindow(IntPtr handle, bool Enable) + { + Win32EnableWindow(handle, Enable); + } + + internal override void EndLoop(System.Threading.Thread thread) + { + // Nothing to do + } + + internal override object StartLoop(System.Threading.Thread thread) + { + return null; + } + + internal override void SetModal(IntPtr handle, bool Modal) + { + // we do nothing on Win32 + } + + internal override void GetCursorPos(IntPtr handle, out int x, out int y) + { + POINT pt; + + Win32GetCursorPos(out pt); + + if (handle != IntPtr.Zero) + { + Win32ScreenToClient(handle, ref pt); + } + + x = pt.x; + y = pt.y; + } + + internal override void ScreenToClient(IntPtr handle, ref int x, ref int y) + { + POINT pnt = new POINT(); + + pnt.x = x; + pnt.y = y; + Win32ScreenToClient(handle, ref pnt); + + x = pnt.x; + y = pnt.y; + } + + internal override void ClientToScreen(IntPtr handle, ref int x, ref int y) + { + POINT pnt = new POINT(); + + pnt.x = x; + pnt.y = y; + + Win32ClientToScreen(handle, ref pnt); + + x = pnt.x; + y = pnt.y; + } + + internal override void ScreenToMenu(IntPtr handle, ref int x, ref int y) + { + RECT rect; + + Win32GetWindowRect(handle, out rect); + x -= rect.left + SystemInformation.FrameBorderSize.Width; + y -= rect.top + SystemInformation.FrameBorderSize.Height; + + WindowStyles style = (WindowStyles)Win32GetWindowLong(handle, WindowLong.GWL_STYLE); + if (CreateParams.IsSet(style, WindowStyles.WS_CAPTION)) + { + y -= ThemeEngine.Current.CaptionHeight; + } + } + + internal override void MenuToScreen(IntPtr handle, ref int x, ref int y) + { + RECT rect; + + Win32GetWindowRect(handle, out rect); + x += rect.left + SystemInformation.FrameBorderSize.Width; + y += rect.top + SystemInformation.FrameBorderSize.Height + ThemeEngine.Current.CaptionHeight; + return; + } + + internal override void SendAsyncMethod(AsyncMethodData method) + { + Win32PostMessage(GetFosterParent(), Msg.WM_ASYNC_MESSAGE, IntPtr.Zero, (IntPtr)GCHandle.Alloc(method)); + } + + internal override void SetTimer(Timer timer) + { + IntPtr FosterParent = GetFosterParent(); + int index; + + index = timer.GetHashCode(); + + lock (timer_list) + { + timer_list[index] = timer; + } + + if (Win32SetTimer(FosterParent, index, (uint)timer.Interval, IntPtr.Zero) != IntPtr.Zero) + timer.window = FosterParent; + else + timer.window = IntPtr.Zero; + } + + internal override void KillTimer(Timer timer) + { + int index; + + index = timer.GetHashCode(); + + Win32KillTimer(timer.window, index); + + lock (timer_list) + { + timer_list.Remove(index); + } + } + + internal override void CreateCaret(IntPtr hwnd, int width, int height) + { + Win32CreateCaret(hwnd, IntPtr.Zero, width, height); + caret_visible = false; + } + + internal override void DestroyCaret(IntPtr hwnd) + { + Win32DestroyCaret(); + } + + internal override void SetCaretPos(IntPtr hwnd, int x, int y) + { + Win32SetCaretPos(x, y); + } + + internal override void CaretVisible(IntPtr hwnd, bool visible) + { + if (visible) + { + if (!caret_visible) + { + Win32ShowCaret(hwnd); + caret_visible = true; + } + } + else + { + if (caret_visible) + { + Win32HideCaret(hwnd); + caret_visible = false; + } + } + } + + internal override IntPtr GetFocus() + { + return Win32GetFocus(); + } + + internal override void SetFocus(IntPtr hwnd) + { + Win32SetFocus(hwnd); + } + + internal override IntPtr GetActive() + { + return Win32GetActiveWindow(); + } + + internal override bool GetFontMetrics(Graphics g, Font font, out int ascent, out int descent) + { + IntPtr dc; + IntPtr prevobj; + TEXTMETRIC tm; + + tm = new TEXTMETRIC(); + + dc = Win32GetDC(IntPtr.Zero); + prevobj = Win32SelectObject(dc, font.ToHfont()); + + if (Win32GetTextMetrics(dc, ref tm) == false) + { + prevobj = Win32SelectObject(dc, prevobj); + Win32DeleteObject(prevobj); + Win32ReleaseDC(IntPtr.Zero, dc); + ascent = 0; + descent = 0; + return false; + } + prevobj = Win32SelectObject(dc, prevobj); + Win32DeleteObject(prevobj); + Win32ReleaseDC(IntPtr.Zero, dc); + + ascent = tm.tmAscent; + descent = tm.tmDescent; + + return true; + } + + internal override void ScrollWindow(IntPtr hwnd, Rectangle rectangle, int XAmount, int YAmount, bool with_children) + { + RECT rect; + + rect = new RECT(); + rect.left = rectangle.X; + rect.top = rectangle.Y; + rect.right = rectangle.Right; + rect.bottom = rectangle.Bottom; + + Win32ScrollWindowEx(hwnd, XAmount, YAmount, IntPtr.Zero, ref rect, IntPtr.Zero, IntPtr.Zero, ScrollWindowExFlags.SW_INVALIDATE | ScrollWindowExFlags.SW_ERASE | (with_children ? ScrollWindowExFlags.SW_SCROLLCHILDREN : ScrollWindowExFlags.SW_NONE)); + Win32UpdateWindow(hwnd); + } + + internal override void ScrollWindow(IntPtr hwnd, int XAmount, int YAmount, bool with_children) + { + Win32ScrollWindowEx(hwnd, XAmount, YAmount, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ScrollWindowExFlags.SW_INVALIDATE | ScrollWindowExFlags.SW_ERASE | (with_children ? ScrollWindowExFlags.SW_SCROLLCHILDREN : ScrollWindowExFlags.SW_NONE)); + } + + internal override bool SystrayAdd(IntPtr hwnd, string tip, Icon icon, out ToolTip tt) + { + NOTIFYICONDATA nid; + + nid = new NOTIFYICONDATA(); + + nid.cbSize = (uint)Marshal.SizeOf(nid); + nid.hWnd = hwnd; + nid.uID = 1; + nid.uCallbackMessage = (uint)Msg.WM_USER; + nid.uFlags = NotifyIconFlags.NIF_MESSAGE; + + if (tip != null) + { + nid.szTip = tip; + nid.uFlags |= NotifyIconFlags.NIF_TIP; + } + + if (icon != null) + { + nid.hIcon = icon.Handle; + nid.uFlags |= NotifyIconFlags.NIF_ICON; + } + + tt = null; + + return Win32Shell_NotifyIcon(NotifyIconMessage.NIM_ADD, ref nid); + } + + internal override bool SystrayChange(IntPtr hwnd, string tip, Icon icon, ref ToolTip tt) + { + NOTIFYICONDATA nid; + + nid = new NOTIFYICONDATA(); + + nid.cbSize = (uint)Marshal.SizeOf(nid); + nid.hIcon = icon.Handle; + nid.hWnd = hwnd; + nid.uID = 1; + nid.uCallbackMessage = (uint)Msg.WM_USER; + nid.uFlags = NotifyIconFlags.NIF_MESSAGE; + + if (tip != null) + { + nid.szTip = tip; + nid.uFlags |= NotifyIconFlags.NIF_TIP; + } + + if (icon != null) + { + nid.hIcon = icon.Handle; + nid.uFlags |= NotifyIconFlags.NIF_ICON; + } + + return Win32Shell_NotifyIcon(NotifyIconMessage.NIM_MODIFY, ref nid); + } + + internal override void SystrayRemove(IntPtr hwnd, ref ToolTip tt) + { + NOTIFYICONDATA nid; + + nid = new NOTIFYICONDATA(); + + nid.cbSize = (uint)Marshal.SizeOf(nid); + nid.hWnd = hwnd; + nid.uID = 1; + nid.uFlags = 0; + + Win32Shell_NotifyIcon(NotifyIconMessage.NIM_DELETE, ref nid); + } + + internal override void SystrayBalloon(IntPtr hwnd, int timeout, string title, string text, ToolTipIcon icon) + { + NOTIFYICONDATA nid; + + nid = new NOTIFYICONDATA(); + + nid.cbSize = (uint)Marshal.SizeOf(nid); + nid.hWnd = hwnd; + nid.uID = 1; + nid.uFlags = NotifyIconFlags.NIF_INFO; + nid.uTimeoutOrVersion = timeout; + nid.szInfoTitle = title; + nid.szInfo = text; + nid.dwInfoFlags = icon; + + Win32Shell_NotifyIcon(NotifyIconMessage.NIM_MODIFY, ref nid); + } + + internal override void SetBorderStyle(IntPtr handle, FormBorderStyle border_style) + { + // Nothing to do on Win32 + } + + internal override void SetMenu(IntPtr handle, Menu menu) + { + // Trigger WM_NCCALC + Win32SetWindowPos(handle, IntPtr.Zero, 0, 0, 0, 0, SetWindowPosFlags.SWP_FRAMECHANGED | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE); + } + + internal override Point GetMenuOrigin(IntPtr handle) + { + Form form = Widget.FromHandle(handle) as Form; + + if (form != null) + { + if (form.FormBorderStyle == FormBorderStyle.None) + return Point.Empty; + + int bordersize = (form.Width - form.ClientSize.Width) / 2; + + if (form.FormBorderStyle == FormBorderStyle.FixedToolWindow || form.FormBorderStyle == FormBorderStyle.SizableToolWindow) + return new Point(bordersize, bordersize + SystemInformation.ToolWindowCaptionHeight); + else + return new Point(bordersize, bordersize + SystemInformation.CaptionHeight); + } + + return new Point(SystemInformation.FrameBorderSize.Width, SystemInformation.FrameBorderSize.Height + ThemeEngine.Current.CaptionHeight); + } + + internal override void SetIcon(IntPtr hwnd, Icon icon) + { + Win32SendMessage(hwnd, Msg.WM_SETICON, (IntPtr)1, icon == null ? IntPtr.Zero : icon.Handle); // 1 = large icon (0 would be small) + } + + internal override void ClipboardClose(IntPtr handle) + { + if (handle != clip_magic) + { + throw new ArgumentException("handle is not a valid clipboard handle"); + } + Win32CloseClipboard(); + } + + internal override int ClipboardGetID(IntPtr handle, string format) + { + if (handle != clip_magic) + { + throw new ArgumentException("handle is not a valid clipboard handle"); + } + if (format == "Text") return 1; + else if (format == "Bitmap") return 2; + else if (format == "MetaFilePict") return 3; + else if (format == "SymbolicLink") return 4; + else if (format == "DataInterchangeFormat") return 5; + else if (format == "Tiff") return 6; + else if (format == "OEMText") return 7; + else if (format == "DeviceIndependentBitmap") return 8; + else if (format == "Palette") return 9; + else if (format == "PenData") return 10; + else if (format == "RiffAudio") return 11; + else if (format == "WaveAudio") return 12; + else if (format == "UnicodeText") return 13; + else if (format == "EnhancedMetafile") return 14; + else if (format == "FileDrop") return 15; + else if (format == "Locale") return 16; + + return (int)Win32RegisterClipboardFormat(format); + } + + internal override IntPtr ClipboardOpen(bool primary_selection) + { + // Win32 does not have primary selection + Win32OpenClipboard(GetFosterParent()); + return clip_magic; + } + + internal override int[] ClipboardAvailableFormats(IntPtr handle) + { + uint format; + int[] result; + int count; + + if (handle != clip_magic) + { + return null; + } + + // Count first + count = 0; + format = 0; + do + { + format = Win32EnumClipboardFormats(format); + if (format != 0) + { + count++; + } + } while (format != 0); + + // Now assign + result = new int[count]; + count = 0; + format = 0; + do + { + format = Win32EnumClipboardFormats(format); + if (format != 0) + { + result[count++] = (int)format; + } + } while (format != 0); + + return result; + } + + + internal override object ClipboardRetrieve(IntPtr handle, int type, XplatUI.ClipboardToObject converter) + { + IntPtr hmem; + IntPtr data; + object obj; + + if (handle != clip_magic) + { + throw new ArgumentException("handle is not a valid clipboard handle"); + } + + hmem = Win32GetClipboardData((uint)type); + if (hmem == IntPtr.Zero) + { + return null; + } + + data = Win32GlobalLock(hmem); + if (data == IntPtr.Zero) + { + uint error = Win32GetLastError(); + Console.WriteLine("Error: {0}", error); + return null; + } + + obj = null; + + if (type == DataFormats.GetFormat(DataFormats.Rtf).Id) + { + obj = AnsiToString(data); + } + else switch ((ClipboardFormats)type) + { + case ClipboardFormats.CF_TEXT: + { + obj = AnsiToString(data); + break; + } + + case ClipboardFormats.CF_DIB: + { + obj = DIBtoImage(data); + break; + } + + case ClipboardFormats.CF_UNICODETEXT: + { + obj = UnicodeToString(data); + break; + } + + default: + { + if (converter != null && !converter(type, data, out obj)) + { + obj = null; + } + break; + } + } + Win32GlobalUnlock(hmem); + + return obj; + + } + + internal override void ClipboardStore(IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter, bool copy) + { + byte[] data = null; + + if (handle != clip_magic) + { + throw new ArgumentException("handle is not a valid clipboard handle"); + } + + if (obj == null) + { + // Just clear it + if (!Win32EmptyClipboard()) + throw new ExternalException("Win32EmptyClipboard"); + return; + } + + if (type == -1) + { + if (obj is string) + { + type = (int)ClipboardFormats.CF_UNICODETEXT; + } + else if (obj is Image) + { + type = (int)ClipboardFormats.CF_DIB; + } + } + + if (type == DataFormats.GetFormat(DataFormats.Rtf).Id) + { + data = StringToAnsi((string)obj); + } + else switch ((ClipboardFormats)type) + { + case ClipboardFormats.CF_UNICODETEXT: + { + data = StringToUnicode((string)obj); + break; + } + + case ClipboardFormats.CF_TEXT: + { + data = StringToAnsi((string)obj); + break; + } + + case ClipboardFormats.CF_BITMAP: + case ClipboardFormats.CF_DIB: + { + data = ImageToDIB((Image)obj); + type = (int)ClipboardFormats.CF_DIB; + break; + } + + default: + { + if (converter != null && !converter(ref type, obj, out data)) + { + data = null; // ensure that a failed conversion leaves null. + } + break; + } + } + if (data != null) + { + SetClipboardData((uint)type, data); + } + } + + internal static byte[] StringToUnicode(string text) + { + return Encoding.Unicode.GetBytes(text + "\0"); + } + + internal static byte[] StringToAnsi(string text) + { + // FIXME, follow the behaviour of the previous code using UTF-8, + // but this should be 'ANSI' on Windows, i.e. the current code page. + // Does Encoding.Default work on Windows? + return Encoding.UTF8.GetBytes(text + "\0"); + } + + private void SetClipboardData(uint type, byte[] data) + { + if (data.Length == 0) + // Shouldn't call Win32SetClipboard with NULL, as, from MSDN: + // "This parameter can be NULL, indicating that the window provides data + // in the specified clipboard format (renders the format) upon request." + // and I don't think we support that... + // Note this is unrelated to the fact that passing a null obj to + // ClipboardStore is actually a request to empty the clipboard! + return; + IntPtr hmem = CopyToMoveableMemory(data); + if (hmem == IntPtr.Zero) + // As above, should not call with null. + // (Not that CopyToMoveableMemory should ever return null!) + throw new ExternalException("CopyToMoveableMemory failed."); + if (Win32SetClipboardData(type, hmem) == IntPtr.Zero) + throw new ExternalException("Win32SetClipboardData"); + } + + /// + /// Creates a memory block with GlobalAlloc(GMEM_MOVEABLE), copies the data + /// into it, and returns the handle to the memory. + /// + /// - + /// The data. Must not be null or zero-length — + /// see the exception notes. + /// - + /// The *handle* to the allocated GMEM_MOVEABLE block. + /// - + /// The data was null or zero + /// length. This is disallowed since a zero length allocation can't be made + /// + /// The allocation, + /// or locking (handle->pointer) failed. + /// Either out of memory or the handle table is full (256 max currently). + /// Note Win32Exception is a subclass of ExternalException so this is OK in + /// the documented Clipboard interface. + /// + internal static IntPtr CopyToMoveableMemory(byte[] data) + { + if (data == null || data.Length == 0) + // detect this before GlobalAlloc does. + throw new ArgumentException("Can't create a zero length memory block."); + + IntPtr hmem = Win32GlobalAlloc(GAllocFlags.GMEM_MOVEABLE | GAllocFlags.GMEM_DDESHARE, data.Length); + if (hmem == IntPtr.Zero) + throw new Win32Exception(); + IntPtr hmem_ptr = Win32GlobalLock(hmem); + if (hmem_ptr == IntPtr.Zero) // If the allocation was valid this shouldn't occur. + throw new Win32Exception(); + Marshal.Copy(data, 0, hmem_ptr, data.Length); + Win32GlobalUnlock(hmem); + return hmem; + } + + + internal override void SetAllowDrop(IntPtr hwnd, bool allowed) + { + if (allowed) + { + Win32DnD.RegisterDropTarget(hwnd); + } + else + { + Win32DnD.UnregisterDropTarget(hwnd); + } + } + + internal override DragDropEffects StartDrag(IntPtr hwnd, object data, DragDropEffects allowedEffects) + { + return Win32DnD.StartDrag(hwnd, data, allowedEffects); + } + + // XXX this doesn't work at all for FrameStyle.Dashed - it draws like Thick, and in the Thick case + // the corners are drawn incorrectly. + internal override void DrawReversibleFrame(Rectangle rectangle, Color backColor, FrameStyle style) + { + IntPtr hdc; + IntPtr pen; + IntPtr oldpen; + COLORREF clrRef = new COLORREF(); + + // If we want the standard hatch pattern we would + // need to create a brush + + clrRef.R = backColor.R; + clrRef.G = backColor.G; + clrRef.B = backColor.B; + + // Grab a pen + pen = Win32CreatePen(style == FrameStyle.Thick ? PenStyle.PS_SOLID : PenStyle.PS_DASH, + style == FrameStyle.Thick ? 4 : 2, ref clrRef); + + hdc = Win32GetDC(IntPtr.Zero); + Win32SetROP2(hdc, ROP2DrawMode.R2_NOT); + oldpen = Win32SelectObject(hdc, pen); + + Win32MoveToEx(hdc, rectangle.Left, rectangle.Top, IntPtr.Zero); + if ((rectangle.Width > 0) && (rectangle.Height > 0)) + { + Win32LineTo(hdc, rectangle.Right, rectangle.Top); + Win32LineTo(hdc, rectangle.Right, rectangle.Bottom); + Win32LineTo(hdc, rectangle.Left, rectangle.Bottom); + Win32LineTo(hdc, rectangle.Left, rectangle.Top); + } + else + { + if (rectangle.Width > 0) + { + Win32LineTo(hdc, rectangle.Right, rectangle.Top); + } + else + { + Win32LineTo(hdc, rectangle.Left, rectangle.Bottom); + } + } + + Win32SelectObject(hdc, oldpen); + Win32DeleteObject(pen); + + Win32ReleaseDC(IntPtr.Zero, hdc); + } + + internal override void DrawReversibleLine(Point start, Point end, Color backColor) + { + IntPtr hdc; + IntPtr pen; + IntPtr oldpen; + POINT pt; + COLORREF clrRef = new COLORREF(); + + pt = new POINT(); + pt.x = 0; + pt.y = 0; + Win32ClientToScreen(IntPtr.Zero, ref pt); + + // If we want the standard hatch pattern we would + // need to create a brush + + clrRef.R = backColor.R; + clrRef.G = backColor.G; + clrRef.B = backColor.B; + + // Grab a pen + pen = Win32CreatePen(PenStyle.PS_SOLID, 1, ref clrRef); + + hdc = Win32GetDC(IntPtr.Zero); + Win32SetROP2(hdc, ROP2DrawMode.R2_NOT); + oldpen = Win32SelectObject(hdc, pen); + + Win32MoveToEx(hdc, pt.x + start.X, pt.y + start.Y, IntPtr.Zero); + Win32LineTo(hdc, pt.x + end.X, pt.y + end.Y); + + Win32SelectObject(hdc, oldpen); + Win32DeleteObject(pen); + + Win32ReleaseDC(IntPtr.Zero, hdc); + } + + internal override void FillReversibleRectangle(Rectangle rectangle, Color backColor) + { + RECT rect; + + rect = new RECT(); + rect.left = rectangle.Left; + rect.top = rectangle.Top; + rect.right = rectangle.Right; + rect.bottom = rectangle.Bottom; + + IntPtr hdc; + IntPtr brush; + IntPtr oldbrush; + COLORREF clrRef = new COLORREF(); + + clrRef.R = backColor.R; + clrRef.G = backColor.G; + clrRef.B = backColor.B; + + // Grab a brush + brush = Win32CreateSolidBrush(clrRef); + + hdc = Win32GetDC(IntPtr.Zero); + oldbrush = Win32SelectObject(hdc, brush); + + Win32PatBlt(hdc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height, PatBltRop.DSTINVERT); + + Win32SelectObject(hdc, oldbrush); + Win32DeleteObject(brush); + + Win32ReleaseDC(IntPtr.Zero, hdc); + } + + internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width) + { + IntPtr hdc; + IntPtr pen; + IntPtr oldpen; + POINT pt; + + pt = new POINT(); + pt.x = 0; + pt.y = 0; + Win32ClientToScreen(handle, ref pt); + + // If we want the standard hatch pattern we would + // need to create a brush + + // Grab a pen + pen = Win32CreatePen(PenStyle.PS_SOLID, line_width, IntPtr.Zero); + + hdc = Win32GetDC(IntPtr.Zero); + Win32SetROP2(hdc, ROP2DrawMode.R2_NOT); + oldpen = Win32SelectObject(hdc, pen); + + Widget c = Widget.FromHandle(handle); + if (c != null) + { + RECT window_rect; + Win32GetWindowRect(c.Handle, out window_rect); + Region r = new Region(new Rectangle(window_rect.left, window_rect.top, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top)); + Win32ExtSelectClipRgn(hdc, r.GetHrgn(Graphics.FromHdc(hdc)), (int)ClipCombineMode.RGN_AND); + } + + Win32MoveToEx(hdc, pt.x + rect.Left, pt.y + rect.Top, IntPtr.Zero); + if ((rect.Width > 0) && (rect.Height > 0)) + { + Win32LineTo(hdc, pt.x + rect.Right, pt.y + rect.Top); + Win32LineTo(hdc, pt.x + rect.Right, pt.y + rect.Bottom); + Win32LineTo(hdc, pt.x + rect.Left, pt.y + rect.Bottom); + Win32LineTo(hdc, pt.x + rect.Left, pt.y + rect.Top); + } + else + { + if (rect.Width > 0) + { + Win32LineTo(hdc, pt.x + rect.Right, pt.y + rect.Top); + } + else + { + Win32LineTo(hdc, pt.x + rect.Left, pt.y + rect.Bottom); + } + } + + Win32SelectObject(hdc, oldpen); + Win32DeleteObject(pen); + if (c != null) + Win32ExtSelectClipRgn(hdc, IntPtr.Zero, (int)ClipCombineMode.RGN_COPY); + + Win32ReleaseDC(IntPtr.Zero, hdc); + } + + internal override SizeF GetAutoScaleSize(Font font) + { + Graphics g; + float width; + string magic_string = "The quick brown fox jumped over the lazy dog."; + double magic_number = 44.549996948242189; + + g = Graphics.FromHwnd(GetFosterParent()); + + width = (float)(g.MeasureString(magic_string, font).Width / magic_number); + return new SizeF(width, font.Height); + } + + internal override IntPtr SendMessage(IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam) + { + return Win32SendMessage(hwnd, message, wParam, lParam); + } + + internal override bool PostMessage(IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam) + { + return Win32PostMessage(hwnd, message, wParam, lParam); + } + + internal override int SendInput(IntPtr hwnd, Queue keys) + { + INPUT[] inputs = new INPUT[keys.Count]; + const Int32 INPUT_KEYBOARD = 1; + uint returns = 0; + int i = 0; + while (keys.Count > 0) + { + MSG msg = (MSG)keys.Dequeue(); + + + inputs[i].ki.wScan = 0; + inputs[i].ki.time = 0; + inputs[i].ki.dwFlags = (Int32)(msg.message == Msg.WM_KEYUP ? InputFlags.KEYEVENTF_KEYUP : 0); + inputs[i].ki.wVk = (short)msg.wParam.ToInt32(); + inputs[i].type = INPUT_KEYBOARD; + i++; + } + returns = Win32SendInput((UInt32)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT))); + + return (int)returns; + } + + internal override int KeyboardSpeed + { + get + { + int speed = 0; + Win32SystemParametersInfo(SPIAction.SPI_GETKEYBOARDSPEED, 0, ref speed, 0); + // + // Return values range from 0 to 31 which map to 2.5 to 30 repetitions per second. + // + return speed; + } + } + + internal override int KeyboardDelay + { + get + { + int delay = 1; + Win32SystemParametersInfo(SPIAction.SPI_GETKEYBOARDDELAY, 0, ref delay, 0); + // + // Return values must range from 0 to 4, 0 meaning 250ms, + // and 4 meaning 1000 ms. + // + return delay; + } + } + + private class WinBuffer + { + public IntPtr hdc; + public IntPtr bitmap; + + public WinBuffer(IntPtr hdc, IntPtr bitmap) + { + this.hdc = hdc; + this.bitmap = bitmap; + } + } + + internal override void CreateOffscreenDrawable(IntPtr handle, int width, int height, out object offscreen_drawable) + { + Graphics destG = Graphics.FromHwnd(handle); + IntPtr destHdc = destG.GetHdc(); + + IntPtr srcHdc = Win32CreateCompatibleDC(destHdc); + IntPtr srcBmp = Win32CreateCompatibleBitmap(destHdc, width, height); + Win32SelectObject(srcHdc, srcBmp); + + offscreen_drawable = new WinBuffer(srcHdc, srcBmp); + + destG.ReleaseHdc(destHdc); + } + + internal override Graphics GetOffscreenGraphics(object offscreen_drawable) + { + return Graphics.FromHdc(((WinBuffer)offscreen_drawable).hdc); + } + + internal override void BlitFromOffscreen(IntPtr dest_handle, Graphics dest_dc, object offscreen_drawable, Graphics offscreen_dc, Rectangle r) + { + WinBuffer wb = (WinBuffer)offscreen_drawable; + + IntPtr destHdc = dest_dc.GetHdc(); + Win32BitBlt(destHdc, r.Left, r.Top, r.Width, r.Height, wb.hdc, r.Left, r.Top, TernaryRasterOperations.SRCCOPY); + dest_dc.ReleaseHdc(destHdc); + } + + internal override void DestroyOffscreenDrawable(object offscreen_drawable) + { + WinBuffer wb = (WinBuffer)offscreen_drawable; + + Win32DeleteObject(wb.bitmap); + Win32DeleteDC(wb.hdc); + } + + internal override void SetForegroundWindow(IntPtr handle) + { + Win32SetForegroundWindow(handle); + } + + internal override event EventHandler Idle; +#endregion // Public Static Methods + + } +} +#endregion +#endif \ No newline at end of file diff --git a/source/ShiftUI/Internal/XplatUIDriver.cs b/source/ShiftUI/Internal/XplatUIDriver.cs new file mode 100644 index 0000000..c3f5e0d --- /dev/null +++ b/source/ShiftUI/Internal/XplatUIDriver.cs @@ -0,0 +1,532 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// Sebastien Pouliot sebastien@ximian.com +// + +// COMPLETE + +using System.Drawing; +using System.Threading; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + internal abstract class XplatUIDriver { + internal abstract IntPtr InitializeDriver(); + internal abstract void ShutdownDriver(IntPtr token); + internal delegate IntPtr WndProc(IntPtr hwnd, Msg msg, IntPtr wParam, IntPtr lParam); + + + #region XplatUI Driver Properties + internal virtual int ActiveWindowTrackingDelay { get { return 0; } } + + internal virtual Color ForeColor { + get { + return ThemeEngine.Current.DefaultWindowForeColor; + } + } + + internal virtual Color BackColor { + get { + return ThemeEngine.Current.DefaultWindowBackColor; + } + } + + internal virtual Size Border3DSize { + get { + return new Size (2, 2); + } + } + + internal virtual Size BorderSize { + get { + return new Size (1, 1); + } + } + + internal virtual Size CaptionButtonSize { + get { + return new Size (18, 18); + } + } + + internal virtual int CaretBlinkTime { get { return 530; } } + internal virtual int CaretWidth { get { return 10; } } + + internal virtual Size DoubleClickSize { + get { + return new Size (4, 4); + } + } + + internal virtual int DoubleClickTime { + get { + return 500; + } + } + + internal virtual Size FixedFrameBorderSize { + get { + return new Size (3, 3); + } + } + + internal virtual Font Font { + get { + return ThemeEngine.Current.DefaultFont; + } + } + + internal virtual int FontSmoothingContrast { get { return 1400; } } + internal virtual int FontSmoothingType { get { return 1; } } + internal virtual int HorizontalResizeBorderThickness { get { return 8; } } + internal virtual bool IsActiveWindowTrackingEnabled { get { return false; } } + internal virtual bool IsComboBoxAnimationEnabled { get { return false; } } + internal virtual bool IsDropShadowEnabled { get { return false; } } + internal virtual bool IsFontSmoothingEnabled { get { return true; } } + internal virtual bool IsHotTrackingEnabled { get { return false; } } + internal virtual bool IsIconTitleWrappingEnabled { get { return true; } } + internal virtual bool IsKeyboardPreferred { get { return false; } } + internal virtual bool IsListBoxSmoothScrollingEnabled { get { return true; } } + internal virtual bool IsMenuAnimationEnabled { get { return false; } } + internal virtual bool IsMenuFadeEnabled { get { return true; } } + internal virtual bool IsMinimizeRestoreAnimationEnabled { get { return false; } } + internal virtual bool IsSelectionFadeEnabled { get { return false; } } + internal virtual bool IsSnapToDefaultEnabled { get { return false; } } + internal virtual bool IsTitleBarGradientEnabled { get { return false; } } + internal virtual bool IsToolTipAnimationEnabled { get { return false; } } + internal virtual Size MenuBarButtonSize { get { return new Size (19, 19); } } + public virtual Size MenuButtonSize { + get { + return new Size(18, 18); + } + } + internal virtual int MenuShowDelay { get { return 0; } } + + internal virtual Keys ModifierKeys { + get { + return Keys.None; + } + } + + internal virtual MouseButtons MouseButtons { + get { + return MouseButtons.None; + } + } + + internal virtual Size MouseHoverSize { + get { + return new Size (1, 1); + } + } + + internal virtual int MouseHoverTime { + get { + return 500; + } + } + + internal virtual int MouseSpeed { + get { return 10; } + } + + internal virtual int MouseWheelScrollDelta { + get { + return 120; + } + } + + internal virtual Point MousePosition { + get { + return Point.Empty; + } + } + + internal virtual int MenuHeight { + get { + return 19; + } + } + + internal virtual LeftRightAlignment PopupMenuAlignment { + get { return LeftRightAlignment.Left; } + } + + internal virtual PowerStatus PowerStatus { + get { throw new NotImplementedException ("Has not been implemented yet for this platform."); } + } + + internal virtual int SizingBorderWidth { + get { return 4; } + } + + internal virtual Size SmallCaptionButtonSize { + get { return new Size (15, 15); } + } + + internal virtual bool UIEffectsEnabled { + get { return false; } + } + + internal virtual bool DropTarget { + get { + return false; + } + + set { + } + } + + internal virtual int HorizontalScrollBarHeight { + get { + return 16; + } + } + + internal virtual bool UserClipWontExposeParent { + get { + return true; + } + } + + internal virtual int VerticalResizeBorderThickness { get { return 8; } } + + internal virtual int VerticalScrollBarWidth { + get { + return 16; + } + } + + internal abstract int CaptionHeight { get; } + internal abstract Size CursorSize { get; } + internal abstract bool DragFullWindows { get; } + internal abstract Size DragSize { get; } + internal abstract Size FrameBorderSize { get; } + internal abstract Size IconSize { get; } + internal abstract Size MaxWindowTrackSize { get; } + internal abstract bool MenuAccessKeysUnderlined { get; } + internal virtual Size MinimizedWindowSize { + get { + const int BorderWidth = 3; + return new Size (154 + 2 * BorderWidth, SystemInformation.CaptionHeight + 2 * BorderWidth - 1); + } + } + internal abstract Size MinimizedWindowSpacingSize { get; } + internal abstract Size MinimumWindowSize { get; } + internal virtual Size MinimumFixedToolWindowSize { get { return Size.Empty; } } + internal virtual Size MinimumSizeableToolWindowSize { get { return Size.Empty; } } + internal virtual Size MinimumNoBorderWindowSize { get { return Size.Empty; } } + internal virtual Size MinWindowTrackSize { + get { + return new Size (112, 27); + } + } + internal abstract Size SmallIconSize { get; } + internal abstract int MouseButtonCount { get; } + internal abstract bool MouseButtonsSwapped { get; } + internal abstract bool MouseWheelPresent { get; } + internal abstract Rectangle VirtualScreen { get; } + internal abstract Rectangle WorkingArea { get; } + internal abstract Screen[] AllScreens { get; } + internal abstract bool ThemesEnabled { get; } + + internal virtual bool RequiresPositiveClientAreaSize { + get { + return true; + } + } + + public virtual int ToolWindowCaptionHeight { + get { + return 16; + } + } + + public virtual Size ToolWindowCaptionButtonSize { + get { + return new Size (15, 15); + } + } + #endregion // XplatUI Driver Properties + + internal abstract event EventHandler Idle; + + #region XplatUI Driver Methods + internal abstract void AudibleAlert(AlertType alert); + + internal abstract void BeginMoveResize (IntPtr handle); // init a window manager driven resize event + + internal abstract void EnableThemes(); + + internal abstract void GetDisplaySize(out Size size); + + internal abstract IntPtr CreateWindow(CreateParams cp); + internal abstract IntPtr CreateWindow(IntPtr Parent, int X, int Y, int Width, int Height); + internal abstract void DestroyWindow(IntPtr handle); + + internal abstract FormWindowState GetWindowState(IntPtr handle); + internal abstract void SetWindowState(IntPtr handle, FormWindowState state); + internal abstract void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max); + + internal abstract void SetWindowStyle(IntPtr handle, CreateParams cp); + + internal abstract double GetWindowTransparency(IntPtr handle); + internal abstract void SetWindowTransparency(IntPtr handle, double transparency, Color key); + internal abstract TransparencySupport SupportsTransparency(); + + internal virtual void SetAllowDrop (IntPtr handle, bool value) + { + Console.Error.WriteLine ("Drag and Drop is currently " + + "not supported on this platform"); + } + + internal virtual DragDropEffects StartDrag(IntPtr handle, object data, DragDropEffects allowedEffects) { + Console.Error.WriteLine ("Drag and Drop is currently " + + "not supported on this platform"); + return DragDropEffects.None; + } + + internal abstract void SetBorderStyle(IntPtr handle, FormBorderStyle border_style); + internal abstract void SetMenu(IntPtr handle, Menu menu); + + internal abstract bool GetText(IntPtr handle, out string text); + internal abstract bool Text(IntPtr handle, string text); + internal abstract bool SetVisible(IntPtr handle, bool visible, bool activate); + internal abstract bool IsVisible(IntPtr handle); + internal abstract bool IsEnabled(IntPtr handle); + internal virtual bool IsKeyLocked (VirtualKeys key) { return false; } + internal abstract IntPtr SetParent(IntPtr handle, IntPtr parent); + internal abstract IntPtr GetParent(IntPtr handle); + + internal abstract void UpdateWindow(IntPtr handle); + internal abstract PaintEventArgs PaintEventStart (ref Message msg, IntPtr handle, bool client); + internal abstract void PaintEventEnd (ref Message msg, IntPtr handle, bool client); + + internal abstract void SetWindowPos(IntPtr handle, int x, int y, int width, int height); + internal abstract void GetWindowPos(IntPtr handle, bool is_toplevel, out int x, out int y, out int width, out int height, out int client_width, out int client_height); + internal abstract void Activate(IntPtr handle); + internal abstract void EnableWindow(IntPtr handle, bool Enable); + internal abstract void SetModal(IntPtr handle, bool Modal); + internal abstract void Invalidate(IntPtr handle, Rectangle rc, bool clear); + internal abstract void InvalidateNC(IntPtr handle); + internal abstract IntPtr DefWndProc(ref Message msg); + internal abstract void HandleException(Exception e); + internal abstract void DoEvents(); + internal abstract bool PeekMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags); + internal abstract void PostQuitMessage(int exitCode); + internal abstract bool GetMessage(object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax); + internal abstract bool TranslateMessage(ref MSG msg); + internal abstract IntPtr DispatchMessage(ref MSG msg); + + internal abstract bool SetZOrder(IntPtr hWnd, IntPtr AfterhWnd, bool Top, bool Bottom); + internal abstract bool SetTopmost(IntPtr hWnd, bool Enabled); + internal abstract bool SetOwner(IntPtr hWnd, IntPtr hWndOwner); + + internal abstract bool CalculateWindowRect(ref Rectangle ClientRect, CreateParams cp, Menu menu, out Rectangle WindowRect); + + internal abstract Region GetClipRegion(IntPtr hwnd); + internal abstract void SetClipRegion(IntPtr hwnd, Region region); + + internal abstract void SetCursor(IntPtr hwnd, IntPtr cursor); + internal abstract void ShowCursor(bool show); + internal abstract void OverrideCursor(IntPtr cursor); + internal abstract IntPtr DefineCursor(Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot); + internal abstract IntPtr DefineStdCursor(StdCursor id); + internal abstract Bitmap DefineStdCursorBitmap(StdCursor id); + internal abstract void DestroyCursor(IntPtr cursor); + internal abstract void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y); + + internal abstract void GetCursorPos(IntPtr hwnd, out int x, out int y); + internal abstract void SetCursorPos(IntPtr hwnd, int x, int y); + + internal abstract void ScreenToClient(IntPtr hwnd, ref int x, ref int y); + internal abstract void ClientToScreen(IntPtr hwnd, ref int x, ref int y); + + internal abstract void GrabWindow(IntPtr hwnd, IntPtr ConfineToHwnd); + internal abstract void GrabInfo(out IntPtr hwnd, out bool GrabConfined, out Rectangle GrabArea); + internal abstract void UngrabWindow(IntPtr hwnd); + + internal abstract void SendAsyncMethod (AsyncMethodData method); + internal abstract void SetTimer (Timer timer); + internal abstract void KillTimer (Timer timer); + + internal abstract void CreateCaret(IntPtr hwnd, int width, int height); + internal abstract void DestroyCaret(IntPtr hwnd); + internal abstract void SetCaretPos(IntPtr hwnd, int x, int y); + internal abstract void CaretVisible(IntPtr hwnd, bool visible); + + internal abstract IntPtr GetFocus(); + internal abstract void SetFocus(IntPtr hwnd); + internal abstract IntPtr GetActive(); + internal abstract IntPtr GetPreviousWindow(IntPtr hwnd); + + internal abstract void ScrollWindow(IntPtr hwnd, Rectangle rectangle, int XAmount, int YAmount, bool with_children); + internal abstract void ScrollWindow(IntPtr hwnd, int XAmount, int YAmount, bool with_children); + + internal abstract bool GetFontMetrics(Graphics g, Font font, out int ascent, out int descent); + + internal abstract bool SystrayAdd(IntPtr hwnd, string tip, Icon icon, out ToolTip tt); + internal abstract bool SystrayChange(IntPtr hwnd, string tip, Icon icon, ref ToolTip tt); + internal abstract void SystrayRemove(IntPtr hwnd, ref ToolTip tt); + internal abstract void SystrayBalloon(IntPtr hwnd, int timeout, string title, string text, ToolTipIcon icon); + + internal abstract Point GetMenuOrigin(IntPtr hwnd); + internal abstract void MenuToScreen(IntPtr hwnd, ref int x, ref int y); + internal abstract void ScreenToMenu(IntPtr hwnd, ref int x, ref int y); + + internal abstract void SetIcon(IntPtr handle, Icon icon); + + internal abstract void ClipboardClose(IntPtr handle); + internal abstract IntPtr ClipboardOpen (bool primary_selection); + internal abstract int ClipboardGetID(IntPtr handle, string format); + internal abstract void ClipboardStore(IntPtr handle, object obj, int id, XplatUI.ObjectToClipboard converter, bool copy); + internal abstract int[] ClipboardAvailableFormats(IntPtr handle); + internal abstract object ClipboardRetrieve(IntPtr handle, int id, XplatUI.ClipboardToObject converter); + + internal abstract void DrawReversibleLine(Point start, Point end, Color backColor); + internal abstract void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width); + internal abstract void FillReversibleRectangle (Rectangle rectangle, Color backColor); + internal abstract void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style); + + internal abstract SizeF GetAutoScaleSize(Font font); + + internal abstract IntPtr SendMessage(IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam); + internal abstract bool PostMessage(IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam); + internal abstract int SendInput(IntPtr hwnd, System.Collections.Queue keys); + + internal abstract object StartLoop(Thread thread); + internal abstract void EndLoop(Thread thread); + + internal abstract void RequestNCRecalc(IntPtr hwnd); + internal abstract void ResetMouseHover(IntPtr hwnd); + internal abstract void RequestAdditionalWM_NCMessages(IntPtr hwnd, bool hover, bool leave); + + internal abstract void RaiseIdle (EventArgs e); + + // System information + internal abstract int KeyboardSpeed { get; } + internal abstract int KeyboardDelay { get; } + + + // Double buffering + internal virtual void CreateOffscreenDrawable (IntPtr handle, + int width, int height, + out object offscreen_drawable) + { + Bitmap bmp = new Bitmap (width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + + offscreen_drawable = bmp; + } + + internal virtual void DestroyOffscreenDrawable (object offscreen_drawable) + { + Bitmap bmp = (Bitmap)offscreen_drawable; + + bmp.Dispose (); + } + + internal virtual Graphics GetOffscreenGraphics (object offscreen_drawable) + { + Bitmap bmp = (Bitmap)offscreen_drawable; + return Graphics.FromImage (bmp); + } + + internal virtual void BlitFromOffscreen (IntPtr dest_handle, + Graphics dest_dc, + object offscreen_drawable, + Graphics offscreen_dc, + Rectangle r) + { + dest_dc.DrawImage ((Bitmap)offscreen_drawable, r, r, GraphicsUnit.Pixel); + } + + internal virtual void SetForegroundWindow (IntPtr handle) + { + } + +#endregion // XplatUI Driver Methods + } + + static class XplatUIDriverSupport { + #region XplatUI Driver Support Methods + internal static void ExecutionCallback (AsyncMethodData data) + { + AsyncMethodResult result = data.Result; + + object ret; + try { + ret = data.Method.DynamicInvoke (data.Args); + } catch (Exception ex) { + if (result != null) { + result.CompleteWithException (ex); + return; + } + + throw; + } + + if (result != null) { + result.Complete (ret); + } + } + + static void ExecutionCallbackInContext (object state) + { + AsyncMethodData data = (AsyncMethodData) state; + + if (data.SyncContext == null) { + ExecutionCallback (data); + return; + } + + var oldContext = SynchronizationContext.Current; + SynchronizationContext.SetSynchronizationContext (data.SyncContext); + + try { + ExecutionCallback (data); + } finally { + SynchronizationContext.SetSynchronizationContext (oldContext); + } + } + + internal static void ExecuteClientMessage (GCHandle gchandle) + { + AsyncMethodData data = (AsyncMethodData) gchandle.Target; + try { + if (data.Context == null) { + ExecutionCallback (data); + } else { + data.SyncContext = SynchronizationContext.Current; + ExecutionContext.Run (data.Context, new ContextCallback (ExecutionCallbackInContext), data); + } + } + finally { + gchandle.Free (); + } + } + + #endregion // XplatUI Driver Support Methods + } +} diff --git a/source/ShiftUI/Internal/XplatUIStructs.cs b/source/ShiftUI/Internal/XplatUIStructs.cs new file mode 100644 index 0000000..f0c3bc5 --- /dev/null +++ b/source/ShiftUI/Internal/XplatUIStructs.cs @@ -0,0 +1,1042 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// *** When you make some changes to this file, dont forget to update Tests/TestHelper class *** + +// NOT COMPLETE + +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +#if PUBLIC_TYPES +namespace Mono.Winforms +#else +namespace ShiftUI +#endif +{ + [Flags] +#if PUBLIC_TYPES + public +#else + internal +#endif + enum WindowStyles : int { + WS_OVERLAPPED = 0x00000000, + WS_POPUP = unchecked((int)0x80000000), + WS_CHILD = 0x40000000, + WS_MINIMIZE = 0x20000000, + WS_VISIBLE = 0x10000000, + WS_DISABLED = 0x08000000, + WS_CLIPSIBLINGS = 0x04000000, + WS_CLIPCHILDREN = 0x02000000, + WS_MAXIMIZE = 0x01000000, + WS_CAPTION = 0x00C00000, // == WS_BORDER | WS_DLGFRAME + WS_BORDER = 0x00800000, + WS_DLGFRAME = 0x00400000, + WS_VSCROLL = 0x00200000, + WS_HSCROLL = 0x00100000, + WS_SYSMENU = 0x00080000, + WS_THICKFRAME = 0x00040000, + WS_GROUP = 0x00020000, + WS_TABSTOP = 0x00010000, + WS_MINIMIZEBOX = 0x00020000, + WS_MAXIMIZEBOX = 0x00010000, + WS_TILED = 0x00000000, + WS_ICONIC = 0x20000000, + WS_SIZEBOX = 0x00040000, + WS_POPUPWINDOW = unchecked((int)0x80880000), + WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, + WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW, + WS_CHILDWINDOW = WS_CHILD, + } + + [Flags] +#if PUBLIC_TYPES + public +#else + internal +#endif + enum WindowExStyles : int { + // Extended Styles + WS_EX_DLGMODALFRAME = 0x00000001, + WS_EX_DRAGDETECT = 0x00000002, + WS_EX_NOPARENTNOTIFY = 0x00000004, + WS_EX_TOPMOST = 0x00000008, + WS_EX_ACCEPTFILES = 0x00000010, + WS_EX_TRANSPARENT = 0x00000020, + + WS_EX_MDICHILD = 0x00000040, + WS_EX_TOOLWINDOW = 0x00000080, + WS_EX_WINDOWEDGE = 0x00000100, + WS_EX_CLIENTEDGE = 0x00000200, + WS_EX_CONTEXTHELP = 0x00000400, + + WS_EX_RIGHT = 0x00001000, + WS_EX_LEFT = 0x00000000, + WS_EX_RTLREADING = 0x00002000, + WS_EX_LTRREADING = 0x00000000, + WS_EX_LEFTSCROLLBAR = 0x00004000, + WS_EX_LAYERED = 0x00080000, + WS_EX_RIGHTSCROLLBAR = 0x00000000, + + WS_EX_WidgetPARENT = 0x00010000, + WS_EX_STATICEDGE = 0x00020000, + WS_EX_APPWINDOW = 0x00040000, + WS_EX_NOINHERITLAYOUT = 0x00100000, + WS_EX_LAYOUTRTL = 0x00400000, + WS_EX_COMPOSITED = 0x02000000, + WS_EX_NOACTIVATE = 0x08000000, + + WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE, + WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST + } + + [Flags] +#if PUBLIC_TYPES + public +#else + internal +#endif + enum ToolBarStyles : int { + TBSTYLE_TOOLTIPS = 0x100, + TBSTYLE_FLAT = 0x800, + TBSTYLE_LIST = 0x1000, + TBSTYLE_TRANSPARENT = 0x8000 + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum Msg { + WM_NULL = 0x0000, + WM_CREATE = 0x0001, + WM_DESTROY = 0x0002, + WM_MOVE = 0x0003, + WM_SIZE = 0x0005, + WM_ACTIVATE = 0x0006, + WM_SETFOCUS = 0x0007, + WM_KILLFOCUS = 0x0008, + // public const uint WM_SETVISIBLE = 0x0009; + WM_ENABLE = 0x000A, + WM_SETREDRAW = 0x000B, + WM_SETTEXT = 0x000C, + WM_GETTEXT = 0x000D, + WM_GETTEXTLENGTH = 0x000E, + WM_PAINT = 0x000F, + WM_CLOSE = 0x0010, + WM_QUERYENDSESSION = 0x0011, + WM_QUIT = 0x0012, + WM_QUERYOPEN = 0x0013, + WM_ERASEBKGND = 0x0014, + WM_SYSCOLORCHANGE = 0x0015, + WM_ENDSESSION = 0x0016, + // public const uint WM_SYSTEMERROR = 0x0017; + WM_SHOWWINDOW = 0x0018, + WM_CTLCOLOR = 0x0019, + WM_WININICHANGE = 0x001A, + WM_SETTINGCHANGE = 0x001A, + WM_DEVMODECHANGE = 0x001B, + WM_ACTIVATEAPP = 0x001C, + WM_FONTCHANGE = 0x001D, + WM_TIMECHANGE = 0x001E, + WM_CANCELMODE = 0x001F, + WM_SETCURSOR = 0x0020, + WM_MOUSEACTIVATE = 0x0021, + WM_CHILDACTIVATE = 0x0022, + WM_QUEUESYNC = 0x0023, + WM_GETMINMAXINFO = 0x0024, + WM_PAINTICON = 0x0026, + WM_ICONERASEBKGND = 0x0027, + WM_NEXTDLGCTL = 0x0028, + // public const uint WM_ALTTABACTIVE = 0x0029; + WM_SPOOLERSTATUS = 0x002A, + WM_DRAWITEM = 0x002B, + WM_MEASUREITEM = 0x002C, + WM_DELETEITEM = 0x002D, + WM_VKEYTOITEM = 0x002E, + WM_CHARTOITEM = 0x002F, + WM_SETFONT = 0x0030, + WM_GETFONT = 0x0031, + WM_SETHOTKEY = 0x0032, + WM_GETHOTKEY = 0x0033, + // public const uint WM_FILESYSCHANGE = 0x0034; + // public const uint WM_ISACTIVEICON = 0x0035; + // public const uint WM_QUERYPARKICON = 0x0036; + WM_QUERYDRAGICON = 0x0037, + WM_COMPAREITEM = 0x0039, + // public const uint WM_TESTING = 0x003a; + // public const uint WM_OTHERWINDOWCREATED = 0x003c; + WM_GETOBJECT = 0x003D, + // public const uint WM_ACTIVATESHELLWINDOW = 0x003e; + WM_COMPACTING = 0x0041, + WM_COMMNOTIFY = 0x0044 , + WM_WINDOWPOSCHANGING = 0x0046, + WM_WINDOWPOSCHANGED = 0x0047, + WM_POWER = 0x0048, + WM_COPYDATA = 0x004A, + WM_CANCELJOURNAL = 0x004B, + WM_NOTIFY = 0x004E, + WM_INPUTLANGCHANGEREQUEST = 0x0050, + WM_INPUTLANGCHANGE = 0x0051, + WM_TCARD = 0x0052, + WM_HELP = 0x0053, + WM_USERCHANGED = 0x0054, + WM_NOTIFYFORMAT = 0x0055, + WM_CONTEXTMENU = 0x007B, + WM_STYLECHANGING = 0x007C, + WM_STYLECHANGED = 0x007D, + WM_DISPLAYCHANGE = 0x007E, + WM_GETICON = 0x007F, + + // Non-Client messages + WM_SETICON = 0x0080, + WM_NCCREATE = 0x0081, + WM_NCDESTROY = 0x0082, + WM_NCCALCSIZE = 0x0083, + WM_NCHITTEST = 0x0084, + WM_NCPAINT = 0x0085, + WM_NCACTIVATE = 0x0086, + WM_GETDLGCODE = 0x0087, + WM_SYNCPAINT = 0x0088, + // public const uint WM_SYNCTASK = 0x0089; + WM_NCMOUSEMOVE = 0x00A0, + WM_NCLBUTTONDOWN = 0x00A1, + WM_NCLBUTTONUP = 0x00A2, + WM_NCLBUTTONDBLCLK = 0x00A3, + WM_NCRBUTTONDOWN = 0x00A4, + WM_NCRBUTTONUP = 0x00A5, + WM_NCRBUTTONDBLCLK = 0x00A6, + WM_NCMBUTTONDOWN = 0x00A7, + WM_NCMBUTTONUP = 0x00A8, + WM_NCMBUTTONDBLCLK = 0x00A9, + // public const uint WM_NCXBUTTONDOWN = 0x00ab; + // public const uint WM_NCXBUTTONUP = 0x00ac; + // public const uint WM_NCXBUTTONDBLCLK = 0x00ad; + WM_KEYDOWN = 0x0100, + WM_KEYFIRST = 0x0100, + WM_KEYUP = 0x0101, + WM_CHAR = 0x0102, + WM_DEADCHAR = 0x0103, + WM_SYSKEYDOWN = 0x0104, + WM_SYSKEYUP = 0x0105, + WM_SYSCHAR = 0x0106, + WM_SYSDEADCHAR = 0x0107, + WM_KEYLAST = 0x0108, + WM_IME_STARTCOMPOSITION = 0x010D, + WM_IME_ENDCOMPOSITION = 0x010E, + WM_IME_COMPOSITION = 0x010F, + WM_IME_KEYLAST = 0x010F, + WM_INITDIALOG = 0x0110, + WM_COMMAND = 0x0111, + WM_SYSCOMMAND = 0x0112, + WM_TIMER = 0x0113, + WM_HSCROLL = 0x0114, + WM_VSCROLL = 0x0115, + WM_INITMENU = 0x0116, + WM_INITMENUPOPUP = 0x0117, + // public const uint WM_SYSTIMER = 0x0118; + WM_MENUSELECT = 0x011F, + WM_MENUCHAR = 0x0120, + WM_ENTERIDLE = 0x0121, + WM_MENURBUTTONUP = 0x0122, + WM_MENUDRAG = 0x0123, + WM_MENUGETOBJECT = 0x0124, + WM_UNINITMENUPOPUP = 0x0125, + WM_MENUCOMMAND = 0x0126, + + WM_CHANGEUISTATE = 0x0127, + WM_UPDATEUISTATE = 0x0128, + WM_QUERYUISTATE = 0x0129, + + // public const uint WM_LBTRACKPOINT = 0x0131; + WM_CTLCOLORMSGBOX = 0x0132, + WM_CTLCOLOREDIT = 0x0133, + WM_CTLCOLORLISTBOX = 0x0134, + WM_CTLCOLORBTN = 0x0135, + WM_CTLCOLORDLG = 0x0136, + WM_CTLCOLORSCROLLBAR = 0x0137, + WM_CTLCOLORSTATIC = 0x0138, + WM_MOUSEMOVE = 0x0200, + WM_MOUSEFIRST = 0x0200, + WM_LBUTTONDOWN = 0x0201, + WM_LBUTTONUP = 0x0202, + WM_LBUTTONDBLCLK = 0x0203, + WM_RBUTTONDOWN = 0x0204, + WM_RBUTTONUP = 0x0205, + WM_RBUTTONDBLCLK = 0x0206, + WM_MBUTTONDOWN = 0x0207, + WM_MBUTTONUP = 0x0208, + WM_MBUTTONDBLCLK = 0x0209, + WM_MOUSEWHEEL = 0x020A, + WM_MOUSELAST = 0x020D, + // public const uint WM_XBUTTONDOWN = 0x020B; + // public const uint WM_XBUTTONUP = 0x020C; + // public const uint WM_XBUTTONDBLCLK = 0x020D; + WM_PARENTNOTIFY = 0x0210, + WM_ENTERMENULOOP = 0x0211, + WM_EXITMENULOOP = 0x0212, + WM_NEXTMENU = 0x0213, + WM_SIZING = 0x0214, + WM_CAPTURECHANGED = 0x0215, + WM_MOVING = 0x0216, + // public const uint WM_POWERBROADCAST = 0x0218; + WM_DEVICECHANGE = 0x0219, + WM_MDICREATE = 0x0220, + WM_MDIDESTROY = 0x0221, + WM_MDIACTIVATE = 0x0222, + WM_MDIRESTORE = 0x0223, + WM_MDINEXT = 0x0224, + WM_MDIMAXIMIZE = 0x0225, + WM_MDITILE = 0x0226, + WM_MDICASCADE = 0x0227, + WM_MDIICONARRANGE = 0x0228, + WM_MDIGETACTIVE = 0x0229, + /* D&D messages */ + // public const uint WM_DROPOBJECT = 0x022A; + // public const uint WM_QUERYDROPOBJECT = 0x022B; + // public const uint WM_BEGINDRAG = 0x022C; + // public const uint WM_DRAGLOOP = 0x022D; + // public const uint WM_DRAGSELECT = 0x022E; + // public const uint WM_DRAGMOVE = 0x022F; + WM_MDISETMENU = 0x0230, + WM_ENTERSIZEMOVE = 0x0231, + WM_EXITSIZEMOVE = 0x0232, + WM_DROPFILES = 0x0233, + WM_MDIREFRESHMENU = 0x0234, + WM_IME_SETCONTEXT = 0x0281, + WM_IME_NOTIFY = 0x0282, + WM_IME_Widget = 0x0283, + WM_IME_COMPOSITIONFULL = 0x0284, + WM_IME_SELECT = 0x0285, + WM_IME_CHAR = 0x0286, + WM_IME_REQUEST = 0x0288, + WM_IME_KEYDOWN = 0x0290, + WM_IME_KEYUP = 0x0291, + WM_NCMOUSEHOVER = 0x02A0, + WM_MOUSEHOVER = 0x02A1, + WM_NCMOUSELEAVE = 0x02A2, + WM_MOUSELEAVE = 0x02A3, + WM_CUT = 0x0300, + WM_COPY = 0x0301, + WM_PASTE = 0x0302, + WM_CLEAR = 0x0303, + WM_UNDO = 0x0304, + WM_RENDERFORMAT = 0x0305, + WM_RENDERALLFORMATS = 0x0306, + WM_DESTROYCLIPBOARD = 0x0307, + WM_DRAWCLIPBOARD = 0x0308, + WM_PAINTCLIPBOARD = 0x0309, + WM_VSCROLLCLIPBOARD = 0x030A, + WM_SIZECLIPBOARD = 0x030B, + WM_ASKCBFORMATNAME = 0x030C, + WM_CHANGECBCHAIN = 0x030D, + WM_HSCROLLCLIPBOARD = 0x030E, + WM_QUERYNEWPALETTE = 0x030F, + WM_PALETTEISCHANGING = 0x0310, + WM_PALETTECHANGED = 0x0311, + WM_HOTKEY = 0x0312, + WM_PRINT = 0x0317, + WM_PRINTCLIENT = 0x0318, + WM_HANDHELDFIRST = 0x0358, + WM_HANDHELDLAST = 0x035F, + WM_AFXFIRST = 0x0360, + WM_AFXLAST = 0x037F, + WM_PENWINFIRST = 0x0380, + WM_PENWINLAST = 0x038F, + WM_APP = 0x8000, + WM_USER = 0x0400, + + // Our "private" ones + WM_MOUSE_ENTER = 0x0401, + WM_ASYNC_MESSAGE = 0x0403, + WM_REFLECT = WM_USER + 0x1c00, + WM_CLOSE_INTERNAL = WM_USER + 0x1c01, + + // private messages to support on-the-spot IME editing. + WM_XIM_PREEDITSTART = WM_USER + 0x1d00, + WM_XIM_PREEDITDONE = WM_USER + 0x1d01, + WM_XIM_PREEDITDRAW = WM_USER + 0x1d02, + WM_XIM_PREEDITCARET = WM_USER + 0x1d03, + + // NotifyIcon (Systray) Balloon messages + NIN_BALLOONSHOW = WM_USER + 0x0002, + NIN_BALLOONHIDE = WM_USER + 0x0003, + NIN_BALLOONTIMEOUT = WM_USER + 0x0004, + NIN_BALLOONUSERCLICK = WM_USER + 0x0005 + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum MsgButtons { + MK_LBUTTON = 0x0001, + MK_RBUTTON = 0x0002, + MK_SHIFT = 0x0004, + MK_CONTROL = 0x0008, + MK_MBUTTON = 0x0010, + MK_XBUTTON1 = 0x0020, + MK_XBUTTON2 = 0x0040, + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum MsgUIState { + UIS_SET = 1, + UIS_CLEAR = 2, + UIS_INITIALIZE = 3, + UISF_HIDEFOCUS = 0x1, + UISF_HIDEACCEL = 0x2, + UISF_ACTIVE = 0x4 + } + + [StructLayout(LayoutKind.Sequential)] +#if PUBLIC_TYPES + public +#else + internal +#endif + struct POINT { + public int x; + public int y; + + public POINT (int x, int y) + { + this.x = x; + this.y = y; + } + + public Point ToPoint () + { + return new Point (x, y); + } + + public override string ToString () + { + return "Point {" + x.ToString () + ", " + y.ToString () + "}"; + } + } + + [StructLayout(LayoutKind.Sequential)] +#if PUBLIC_TYPES + public +#else + internal +#endif + struct MSG { + internal IntPtr hwnd; + internal Msg message; + internal IntPtr wParam; + internal IntPtr lParam; + internal uint time; + internal POINT pt; + internal object refobject; + + public override string ToString () + { + return String.Format ("msg=0x{0:x} ({1}) hwnd=0x{2:x} wparam=0x{3:x} lparam=0x{4:x} pt={5}", (int) message, message.ToString (), hwnd.ToInt32 (), wParam.ToInt32 (), lParam.ToInt32 (), pt); + } + } + + [Flags] +#if PUBLIC_TYPES + public +#else + internal +#endif + enum TransparencySupport { + None = 0x00, + Get = 0x01, + Set = 0x02, + GetSet = 0x03 + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum WindowActiveFlags { + WA_INACTIVE = 0, + WA_ACTIVE = 1, + WA_CLICKACTIVE = 2 + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum KeybdEventFlags { + None = 0, + ExtendedKey = 0x0001, + KeyUp = 0x0002 + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum VirtualKeys { + VK_LBUTTON = 0x01, + VK_RBUTTON = 0x02, + VK_CANCEL = 0x03, + VK_MBUTTON = 0x04, + VK_XBUTTON1 = 0x05, + VK_XBUTTON2 = 0x06, + VK_BACK = 0x08, + VK_TAB = 0x09, + VK_CLEAR = 0x0C, + VK_RETURN = 0x0D, + VK_SHIFT = 0x10, + VK_CONTROL = 0x11, + VK_MENU = 0x12, + VK_PAUSE = 0x13, + VK_CAPITAL = 0x14, + VK_ESCAPE = 0x1B, + VK_CONVERT = 0x1C, + VK_NONCONVERT = 0x1D, + VK_SPACE = 0x20, + VK_PRIOR = 0x21, + VK_NEXT = 0x22, + VK_END = 0x23, + VK_HOME = 0x24, + VK_LEFT = 0x25, + VK_UP = 0x26, + VK_RIGHT = 0x27, + VK_DOWN = 0x28, + VK_SELECT = 0x29, + VK_PRINT = 0x2A, + VK_EXECUTE = 0x2B, + VK_SNAPSHOT = 0x2C, + VK_INSERT = 0x2D, + VK_DELETE = 0x2E, + VK_HELP = 0x2F, + VK_0 = 0x30, + VK_1 = 0x31, + VK_2 = 0x32, + VK_3 = 0x33, + VK_4 = 0x34, + VK_5 = 0x35, + VK_6 = 0x36, + VK_7 = 0x37, + VK_8 = 0x38, + VK_9 = 0x39, + VK_A = 0x41, + VK_B = 0x42, + VK_C = 0x43, + VK_D = 0x44, + VK_E = 0x45, + VK_F = 0x46, + VK_G = 0x47, + VK_H = 0x48, + VK_I = 0x49, + VK_J = 0x4A, + VK_K = 0x4B, + VK_L = 0x4C, + VK_M = 0x4D, + VK_N = 0x4E, + VK_O = 0x4F, + VK_P = 0x50, + VK_Q = 0x51, + VK_R = 0x52, + VK_S = 0x53, + VK_T = 0x54, + VK_U = 0x55, + VK_V = 0x56, + VK_W = 0x57, + VK_X = 0x58, + VK_Y = 0x59, + VK_Z = 0x5A, + VK_LWIN = 0x5B, + VK_RWIN = 0x5C, + VK_APPS = 0x5D, + VK_NUMPAD0 = 0x60, + VK_NUMPAD1 = 0x61, + VK_NUMPAD2 = 0x62, + VK_NUMPAD3 = 0x63, + VK_NUMPAD4 = 0x64, + VK_NUMPAD5 = 0x65, + VK_NUMPAD6 = 0x66, + VK_NUMPAD7 = 0x67, + VK_NUMPAD8 = 0x68, + VK_NUMPAD9 = 0x69, + VK_MULTIPLY = 0x6A, + VK_ADD = 0x6B, + VK_SEPARATOR = 0x6C, + VK_SUBTRACT = 0x6D, + VK_DECIMAL = 0x6E, + VK_DIVIDE = 0x6F, + VK_F1 = 0x70, + VK_F2 = 0x71, + VK_F3 = 0x72, + VK_F4 = 0x73, + VK_F5 = 0x74, + VK_F6 = 0x75, + VK_F7 = 0x76, + VK_F8 = 0x77, + VK_F9 = 0x78, + VK_F10 = 0x79, + VK_F11 = 0x7A, + VK_F12 = 0x7B, + VK_F13 = 0x7C, + VK_F14 = 0x7D, + VK_F15 = 0x7E, + VK_F16 = 0x7F, + VK_F17 = 0x80, + VK_F18 = 0x81, + VK_F19 = 0x82, + VK_F20 = 0x83, + VK_F21 = 0x84, + VK_F22 = 0x85, + VK_F23 = 0x86, + VK_F24 = 0x87, + VK_NUMLOCK = 0x90, + VK_SCROLL = 0x91, + VK_LSHIFT = 0xA0, + VK_RSHIFT = 0xA1, + VK_LWidget = 0xA2, + VK_RWidget = 0xA3, + VK_LMENU = 0xA4, + VK_RMENU = 0xA5, + VK_OEM_1 = 0xBA, + VK_OEM_PLUS = 0xBB, + VK_OEM_COMMA = 0xBC, + VK_OEM_MINUS = 0xBD, + VK_OEM_PERIOD = 0xBE, + VK_OEM_2 = 0xBF, + VK_OEM_3 = 0xC0, + VK_OEM_4 = 0xDB, + VK_OEM_5 = 0xDC, + VK_OEM_6 = 0xDD, + VK_OEM_7 = 0xDE, + VK_OEM_8 = 0xDF, + VK_OEM_AX = 0xE1, + VK_OEM_102 = 0xE2, + VK_ICO_HELP = 0xE3, + VK_ICO_00 = 0xE4, + VK_PROCESSKEY = 0xE5, + VK_OEM_ATTN = 0xF0, + VK_OEM_COPY = 0xF2, + VK_OEM_AUTO = 0xF3, + VK_OEM_ENLW = 0xF4, + VK_OEM_BACKTAB = 0xF5, + VK_ATTN = 0xF6, + VK_CRSEL = 0xF7, + VK_EXSEL = 0xF8, + VK_EREOF = 0xF9, + VK_PLAY = 0xFA, + VK_ZOOM = 0xFB, + VK_NONAME = 0xFC, + VK_PA1 = 0xFD, + VK_OEM_CLEAR = 0xFE, + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum TtyKeys { + XK_BackSpace = 0xff08, /* Back space, back char */ + XK_Tab = 0xff09, + XK_Linefeed = 0xff0a, /* Linefeed, LF */ + XK_Clear = 0xff0b, + XK_Return = 0xff0d, /* Return, enter */ + XK_Pause = 0xff13, /* Pause, hold */ + XK_Scroll_Lock = 0xff14, + XK_Sys_Req = 0xff15, + XK_Escape = 0xff1b, + XK_Delete = 0xffff /* Delete, rubout */ + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum MiscKeys { + XK_ISO_Lock = 0xfe01, + XK_ISO_Last_Group_Lock = 0xfe0f, + XK_Select = 0xff60, + XK_Print = 0xff61, + XK_Execute = 0xff62, + XK_Insert = 0xff63, + XK_Undo = 0xff65, + XK_Redo = 0xff66, + XK_Menu = 0xff67, + XK_Find = 0xff68, + XK_Cancel = 0xff69, + XK_Help = 0xff6a, + XK_Break = 0xff6b, + XK_Mode_switch = 0xff7e, + XK_script_switch = 0xff7e, + XK_Num_Lock = 0xff7f + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum KeypadKeys { + XK_KP_Space = 0xff80, + XK_KP_Tab = 0xff89, + XK_KP_Enter = 0xff8d, /* Enter */ + XK_KP_F1 = 0xff91, /* PF1, KP_A, ... */ + XK_KP_F2 = 0xff92, + XK_KP_F3 = 0xff93, + XK_KP_F4 = 0xff94, + XK_KP_Home = 0xff95, + XK_KP_Left = 0xff96, + XK_KP_Up = 0xff97, + XK_KP_Right = 0xff98, + XK_KP_Down = 0xff99, + XK_KP_Prior = 0xff9a, + XK_KP_Page_Up = 0xff9a, + XK_KP_Next = 0xff9b, + XK_KP_Page_Down = 0xff9b, + XK_KP_End = 0xff9c, + XK_KP_Begin = 0xff9d, + XK_KP_Insert = 0xff9e, + XK_KP_Delete = 0xff9f, + XK_KP_Equal = 0xffbd, /* Equals */ + XK_KP_Multiply = 0xffaa, + XK_KP_Add = 0xffab, + XK_KP_Separator = 0xffac, /* Separator, often comma */ + XK_KP_Subtract = 0xffad, + XK_KP_Decimal = 0xffae, + XK_KP_Divide = 0xffaf, + + XK_KP_0 = 0xffb0, + XK_KP_1 = 0xffb1, + XK_KP_2 = 0xffb2, + XK_KP_3 = 0xffb3, + XK_KP_4 = 0xffb4, + XK_KP_5 = 0xffb5, + XK_KP_6 = 0xffb6, + XK_KP_7 = 0xffb7, + XK_KP_8 = 0xffb8, + XK_KP_9 = 0xffb9 + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum DeadKeys { + XK_dead_grave = 0xfe50, + XK_dead_acute = 0xfe51, + XK_dead_circumflex = 0xfe52, + XK_dead_tilde = 0xfe53, + XK_dead_macron = 0xfe54, + XK_dead_breve = 0xfe55, + XK_dead_abovedot = 0xfe56, + XK_dead_diaeresis = 0xfe57, + XK_dead_abovering = 0xfe58, + XK_dead_doubleacute = 0xfe59, + XK_dead_caron = 0xfe5a, + XK_dead_cedilla = 0xfe5b, + XK_dead_ogonek = 0xfe5c, + XK_dead_iota = 0xfe5d, + XK_dead_voiced_sound = 0xfe5e, + XK_dead_semivoiced_sound = 0xfe5f, + XK_dead_belowdot = 0xfe60, + XK_dead_hook = 0xfe61, + XK_dead_horn = 0xfe62 + + } + + [StructLayout(LayoutKind.Sequential)] +#if PUBLIC_TYPES + public +#else + internal +#endif + struct HELPINFO { + internal uint cbSize; + internal int iContextType; + internal int iCtrlId; + internal IntPtr hItemHandle; + internal uint dwContextId; + internal POINT MousePos; + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum PeekMessageFlags { + PM_NOREMOVE = 0x00000000, + PM_REMOVE = 0x00000001, + PM_NOYIELD = 0x00000002 + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum StdCursor { + Default = 0, + AppStarting = 1, + Arrow = 2, + Cross = 3, + Hand = 4, + Help = 5, + HSplit = 6, + IBeam = 7, + No = 8, + NoMove2D = 9, + NoMoveHoriz = 10, + NoMoveVert = 11, + PanEast = 12, + PanNE = 13, + PanNorth = 14, + PanNW = 15, + PanSE = 16, + PanSouth = 17, + PanSW = 18, + PanWest = 19, + SizeAll = 20, + SizeNESW = 21, + SizeNS = 22, + SizeNWSE = 23, + SizeWE = 24, + UpArrow = 25, + VSplit = 26, + WaitCursor = 27 + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum HitTest { + HTERROR = -2, + HTTRANSPARENT = -1, + HTNOWHERE = 0, + HTCLIENT = 1, + HTCAPTION = 2, + HTSYSMENU = 3, + HTGROWBOX = 4, + HTSIZE = HTGROWBOX, + HTMENU = 5, + HTHSCROLL = 6, + HTVSCROLL = 7, + HTMINBUTTON = 8, + HTMAXBUTTON = 9, + HTLEFT = 10, + HTRIGHT = 11, + HTTOP = 12, + HTTOPLEFT = 13, + HTTOPRIGHT = 14, + HTBOTTOM = 15, + HTBOTTOMLEFT = 16, + HTBOTTOMRIGHT = 17, + HTBORDER = 18, + HTREDUCE = HTMINBUTTON, + HTZOOM = HTMAXBUTTON, + HTSIZEFIRST = HTLEFT, + HTSIZELAST = HTBOTTOMRIGHT, + HTOBJECT = 19, + HTCLOSE = 20, + HTHELP = 21 + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum TitleStyle { + None = 0, + Normal = 1, + Tool = 2 + } + + [StructLayout(LayoutKind.Sequential)] +#if PUBLIC_TYPES + public +#else + internal +#endif + struct BITMAPINFOHEADER { + internal uint biSize; + internal int biWidth; + internal int biHeight; + internal ushort biPlanes; + internal ushort biBitCount; + internal uint biCompression; + internal uint biSizeImage; + internal int biXPelsPerMeter; + internal int biYPelsPerMeter; + internal uint biClrUsed; + internal uint biClrImportant; + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum ClipboardFormats : ushort { + CF_TEXT = 1, + CF_BITMAP = 2, + CF_METAFILEPICT = 3, + CF_SYLK = 4, + CF_DIF = 5, + CF_TIFF = 6, + CF_OEMTEXT = 7, + CF_DIB = 8, + CF_PALETTE = 9, + CF_PENDATA = 10, + CF_RIFF = 11, + CF_WAVE = 12, + CF_UNICODETEXT = 13, + CF_ENHMETAFILE = 14, + CF_HDROP = 15, + CF_LOCALE = 16, + CF_DIBV5 = 17 + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] +#if PUBLIC_TYPES + public +#else + internal +#endif + struct MINMAXINFO { + internal POINT ptReserved; + internal POINT ptMaxSize; + internal POINT ptMaxPosition; + internal POINT ptMinTrackSize; + internal POINT ptMaxTrackSize; + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] +#if PUBLIC_TYPES + public +#else + internal +#endif + struct KeyFilterData { + internal bool Down; + internal int keycode; + internal int keysym; + internal Keys ModifierKeys; + internal String str; + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum ScrollBarCommands { + SB_LINEUP = 0, + SB_LINELEFT = 0, + SB_LINEDOWN = 1, + SB_LINERIGHT = 1, + SB_PAGEUP = 2, + SB_PAGELEFT = 2, + SB_PAGEDOWN = 3, + SB_PAGERIGHT = 3, + SB_THUMBPOSITION = 4, + SB_THUMBTRACK = 5, + SB_TOP = 6, + SB_LEFT = 6, + SB_BOTTOM = 7, + SB_RIGHT = 7, + SB_ENDSCROLL = 8 + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum ClipCombineMode { + RGN_AND = 1, + RGN_OR, + RGN_XOR, + RGN_DIFF, + RGN_COPY, + + RGN_MIN = RGN_AND, + RGN_MAX = RGN_COPY + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum SystemCommands { + SC_SIZE = 0xF000, + SC_MOVE = 0xF010, + SC_MINIMIZE = 0xF020, + SC_MAXIMIZE = 0xF030, + SC_NEXTWINDOW = 0xF040, + SC_PREVWINDOW = 0xF050, + SC_CLOSE = 0xF060, + SC_VSCROLL = 0xF070, + SC_HSCROLL = 0xF080, + SC_MOUSEMENU = 0xF090, + SC_KEYMENU = 0xF100, + SC_ARRANGE = 0xF110, + SC_RESTORE = 0xF120, + SC_TASKLIST = 0xF130, + SC_SCREENSAVE = 0xF140, + SC_HOTKEY = 0xF150, + SC_DEFAULT = 0xF160, + SC_MONITORPOWER = 0xF170, + SC_CONTEXTHELP = 0xF180 + } + +#if PUBLIC_TYPES + public +#else + internal +#endif + enum AlertType { + Default = 1, + Error = 2, + Question = 3, + Warning = 4, + Information = 5 + } +} + diff --git a/source/ShiftUI/Internal/XplatUIWin32.cs b/source/ShiftUI/Internal/XplatUIWin32.cs new file mode 100644 index 0000000..a741a46 --- /dev/null +++ b/source/ShiftUI/Internal/XplatUIWin32.cs @@ -0,0 +1,3751 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +// NOT COMPLETE + +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.ComponentModel; +using System.Collections; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + + +/// Win32 Version +namespace ShiftUI { + internal class XplatUIWin32 : XplatUIDriver { + #region Local Variables + private static XplatUIWin32 instance; + private static int ref_count; + private static IntPtr FosterParentLast; + + internal static MouseButtons mouse_state; + internal static Point mouse_position; + internal static bool grab_confined; + internal static IntPtr grab_hwnd; + internal static Rectangle grab_area; + internal static WndProc wnd_proc; + internal static IntPtr prev_mouse_hwnd; + internal static bool caret_visible; + + internal static bool themes_enabled; + private Hashtable timer_list; + private static Queue message_queue; + private static IntPtr clip_magic = new IntPtr(27051977); + private static int scroll_width; + private static int scroll_height; + private static Hashtable wm_nc_registered; + private static RECT clipped_cursor_rect; + private Hashtable registered_classes; + private Hwnd HwndCreating; // the Hwnd we are currently creating (see CreateWindow) + + #endregion // Local Variables + + #region Private Structs + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + private struct WNDCLASS { + internal int style; + internal WndProc lpfnWndProc; + internal int cbClsExtra; + internal int cbWndExtra; + internal IntPtr hInstance; + internal IntPtr hIcon; + internal IntPtr hCursor; + internal IntPtr hbrBackground; + [MarshalAs(UnmanagedType.LPWStr)] + internal string lpszMenuName; + [MarshalAs(UnmanagedType.LPWStr)] + internal string lpszClassName; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct RECT { + internal int left; + internal int top; + internal int right; + internal int bottom; + + public RECT (int left, int top, int right, int bottom) + { + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + + #region Instance Properties + public int Height { get { return bottom - top; } } + public int Width { get { return right - left; } } + public Size Size { get { return new Size (Width, Height); } } + public Point Location { get { return new Point (left, top); } } + #endregion + + #region Instance Methods + public Rectangle ToRectangle () + { + return Rectangle.FromLTRB (left, top, right, bottom); + } + + public static RECT FromRectangle (Rectangle rectangle) + { + return new RECT (rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom); + } + + public override int GetHashCode () + { + return left ^ ((top << 13) | (top >> 0x13)) + ^ ((Width << 0x1a) | (Width >> 6)) + ^ ((Height << 7) | (Height >> 0x19)); + } + + public override string ToString () + { + return String.Format("RECT left={0}, top={1}, right={2}, bottom={3}, width={4}, height={5}", left, top, right, bottom, right-left, bottom-top); + } + #endregion + + #region Operator overloads + public static implicit operator Rectangle (RECT rect) + { + return Rectangle.FromLTRB (rect.left, rect.top, rect.right, rect.bottom); + } + + public static implicit operator RECT (Rectangle rect) + { + return new RECT (rect.Left, rect.Top, rect.Right, rect.Bottom); + } + #endregion + } + + internal enum SPIAction { + SPI_GETACTIVEWINDOWTRACKING = 0x1000, + SPI_GETACTIVEWNDTRKTIMEOUT = 0x2002, + SPI_GETANIMATION = 0x0048, + SPI_GETCARETWIDTH = 0x2006, + SPI_GETCOMBOBOXANIMATION = 0x1004, + SPI_GETDRAGFULLWINDOWS = 0x0026, + SPI_GETDROPSHADOW = 0x1024, + SPI_GETFONTSMOOTHING = 0x004A, + SPI_GETFONTSMOOTHINGCONTRAST = 0x200C, + SPI_GETFONTSMOOTHINGTYPE = 0x200A, + SPI_GETGRADIENTCAPTIONS = 0x1008, + SPI_GETHOTTRACKING = 0x100E, + SPI_GETICONTITLEWRAP = 0x0019, + SPI_GETKEYBOARDSPEED = 0x000A, + SPI_GETKEYBOARDDELAY = 0x0016, + SPI_GETKEYBOARDCUES = 0x100A, + SPI_GETKEYBOARDPREF = 0x0044, + SPI_GETLISTBOXSMOOTHSCROLLING = 0x1006, + SPI_GETMENUANIMATION = 0x1002, + SPI_GETMENUDROPALIGNMENT = 0x001B, + SPI_GETMENUFADE = 0x1012, + SPI_GETMENUSHOWDELAY = 0x006A, + SPI_GETMOUSESPEED = 0x0070, + SPI_GETSELECTIONFADE = 0x1014, + SPI_GETSNAPTODEFBUTTON = 0x005F, + SPI_GETTOOLTIPANIMATION = 0x1016, + SPI_GETWORKAREA = 0x0030, + SPI_GETMOUSEHOVERWIDTH = 0x0062, + SPI_GETMOUSEHOVERHEIGHT = 0x0064, + SPI_GETMOUSEHOVERTIME = 0x0066, + SPI_GETUIEFFECTS = 0x103E, + SPI_GETWHEELSCROLLLINES = 0x0068 + } + + internal enum WindowPlacementFlags { + SW_HIDE = 0, + SW_SHOWNORMAL = 1, + SW_NORMAL = 1, + SW_SHOWMINIMIZED = 2, + SW_SHOWMAXIMIZED = 3, + SW_MAXIMIZE = 3, + SW_SHOWNOACTIVATE = 4, + SW_SHOW = 5, + SW_MINIMIZE = 6, + SW_SHOWMINNOACTIVE = 7, + SW_SHOWNA = 8, + SW_RESTORE = 9, + SW_SHOWDEFAULT = 10, + SW_FORCEMINIMIZE = 11, + SW_MAX = 11 + } + + [StructLayout(LayoutKind.Sequential)] + private struct WINDOWPLACEMENT { + internal uint length; + internal uint flags; + internal WindowPlacementFlags showCmd; + internal POINT ptMinPosition; + internal POINT ptMaxPosition; + internal RECT rcNormalPosition; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct NCCALCSIZE_PARAMS { + internal RECT rgrc1; + internal RECT rgrc2; + internal RECT rgrc3; + internal IntPtr lppos; + } + + [Flags] + private enum TMEFlags { + TME_HOVER = 0x00000001, + TME_LEAVE = 0x00000002, + TME_NONCLIENT = 0x00000010, + TME_QUERY = unchecked((int)0x40000000), + TME_CANCEL = unchecked((int)0x80000000) + } + + [StructLayout(LayoutKind.Sequential)] + private struct TRACKMOUSEEVENT { + internal int size; + internal TMEFlags dwFlags; + internal IntPtr hWnd; + internal int dwHoverTime; + } + + [StructLayout(LayoutKind.Sequential)] + private struct PAINTSTRUCT { + internal IntPtr hdc; + internal int fErase; + internal RECT rcPaint; + internal int fRestore; + internal int fIncUpdate; + internal int Reserved1; + internal int Reserved2; + internal int Reserved3; + internal int Reserved4; + internal int Reserved5; + internal int Reserved6; + internal int Reserved7; + internal int Reserved8; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct KEYBDINPUT { + internal short wVk; + internal short wScan; + internal Int32 dwFlags; + internal Int32 time; + internal UIntPtr dwExtraInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MOUSEINPUT { + internal Int32 dx; + internal Int32 dy; + internal Int32 mouseData; + internal Int32 dwFlags; + internal Int32 time; + internal UIntPtr dwExtraInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HARDWAREINPUT { + internal Int32 uMsg; + internal short wParamL; + internal short wParamH; + } + + [StructLayout (LayoutKind.Sequential)] + internal struct ICONINFO { + internal bool fIcon; + internal Int32 xHotspot; + internal Int32 yHotspot; + internal IntPtr hbmMask; + internal IntPtr hbmColor; + } + + [StructLayout(LayoutKind.Explicit)] + internal struct INPUT { + [FieldOffset(0)] + internal Int32 type; + + [FieldOffset(4)] + internal MOUSEINPUT mi; + + [FieldOffset(4)] + internal KEYBDINPUT ki; + + [FieldOffset(4)] + internal HARDWAREINPUT hi; + } + + [StructLayout (LayoutKind.Sequential)] + public struct ANIMATIONINFO { + internal uint cbSize; + internal int iMinAnimate; + } + + internal enum InputFlags { + KEYEVENTF_EXTENDEDKEY = 0x0001, + KEYEVENTF_KEYUP = 0x0002, + KEYEVENTF_SCANCODE = 0x0003, + KEYEVENTF_UNICODE = 0x0004, + } + + internal enum ClassStyle { + CS_VREDRAW = 0x00000001, + CS_HREDRAW = 0x00000002, + CS_KEYCVTWINDOW = 0x00000004, + CS_DBLCLKS = 0x00000008, + CS_OWNDC = 0x00000020, + CS_CLASSDC = 0x00000040, + CS_PARENTDC = 0x00000080, + CS_NOKEYCVT = 0x00000100, + CS_NOCLOSE = 0x00000200, + CS_SAVEBITS = 0x00000800, + CS_BYTEALIGNCLIENT = 0x00001000, + CS_BYTEALIGNWINDOW = 0x00002000, + CS_GLOBALCLASS = 0x00004000, + CS_IME = 0x00010000, + // Windows XP+ + CS_DROPSHADOW = 0x00020000 + } + + internal enum SetWindowPosZOrder { + HWND_TOP = 0, + HWND_BOTTOM = 1, + HWND_TOPMOST = -1, + HWND_NOTOPMOST = -2 + } + + [Flags] + internal enum SetWindowPosFlags { + SWP_ASYNCWINDOWPOS = 0x4000, + SWP_DEFERERASE = 0x2000, + SWP_DRAWFRAME = 0x0020, + SWP_FRAMECHANGED = 0x0020, + SWP_HIDEWINDOW = 0x0080, + SWP_NOACTIVATE = 0x0010, + SWP_NOCOPYBITS = 0x0100, + SWP_NOMOVE = 0x0002, + SWP_NOOWNERZORDER = 0x0200, + SWP_NOREDRAW = 0x0008, + SWP_NOREPOSITION = 0x0200, + SWP_NOENDSCHANGING = 0x0400, + SWP_NOSIZE = 0x0001, + SWP_NOZORDER = 0x0004, + SWP_SHOWWINDOW = 0x0040 + } + + internal enum GetSysColorIndex { + COLOR_SCROLLBAR = 0, + COLOR_BACKGROUND = 1, + COLOR_ACTIVECAPTION = 2, + COLOR_INACTIVECAPTION = 3, + COLOR_MENU = 4, + COLOR_WINDOW = 5, + COLOR_WINDOWFRAME = 6, + COLOR_MENUTEXT = 7, + COLOR_WINDOWTEXT = 8, + COLOR_CAPTIONTEXT = 9, + COLOR_ACTIVEBORDER = 10, + COLOR_INACTIVEBORDER = 11, + COLOR_APPWORKSPACE = 12, + COLOR_HIGHLIGHT = 13, + COLOR_HIGHLIGHTTEXT = 14, + COLOR_BTNFACE = 15, + COLOR_BTNSHADOW = 16, + COLOR_GRAYTEXT = 17, + COLOR_BTNTEXT = 18, + COLOR_INACTIVECAPTIONTEXT = 19, + COLOR_BTNHIGHLIGHT = 20, + COLOR_3DDKSHADOW = 21, + COLOR_3DLIGHT = 22, + COLOR_INFOTEXT = 23, + COLOR_INFOBK = 24, + + COLOR_HOTLIGHT = 26, + COLOR_GRADIENTACTIVECAPTION = 27, + COLOR_GRADIENTINACTIVECAPTION = 28, + COLOR_MENUHIGHLIGHT = 29, + COLOR_MENUBAR = 30, + + COLOR_DESKTOP = 1, + COLOR_3DFACE = 16, + COLOR_3DSHADOW = 16, + COLOR_3DHIGHLIGHT = 20, + COLOR_3DHILIGHT = 20, + COLOR_BTNHILIGHT = 20, + COLOR_MAXVALUE = 24,/* Maximum value */ + } + + private enum LoadCursorType { + First = 32512, + IDC_ARROW = 32512, + IDC_IBEAM = 32513, + IDC_WAIT = 32514, + IDC_CROSS = 32515, + IDC_UPARROW = 32516, + IDC_SIZE = 32640, + IDC_ICON = 32641, + IDC_SIZENWSE = 32642, + IDC_SIZENESW = 32643, + IDC_SIZEWE = 32644, + IDC_SIZENS = 32645, + IDC_SIZEALL = 32646, + IDC_NO = 32648, + IDC_HAND = 32649, + IDC_APPSTARTING = 32650, + IDC_HELP = 32651, + Last = 32651 + } + + private enum AncestorType { + GA_PARENT = 1, + GA_ROOT = 2, + GA_ROOTOWNER = 3 + } + + [Flags] + private enum WindowLong { + GWL_WNDPROC = -4, + GWL_HINSTANCE = -6, + GWL_HWNDPARENT = -8, + GWL_STYLE = -16, + GWL_EXSTYLE = -20, + GWL_USERDATA = -21, + GWL_ID = -12 + } + + [Flags] + private enum LogBrushStyle { + BS_SOLID = 0, + BS_NULL = 1, + BS_HATCHED = 2, + BS_PATTERN = 3, + BS_INDEXED = 4, + BS_DIBPATTERN = 5, + BS_DIBPATTERNPT = 6, + BS_PATTERN8X8 = 7, + BS_DIBPATTERN8X8 = 8, + BS_MONOPATTERN = 9 + } + + [Flags] + private enum LogBrushHatch { + HS_HORIZONTAL = 0, /* ----- */ + HS_VERTICAL = 1, /* ||||| */ + HS_FDIAGONAL = 2, /* \\\\\ */ + HS_BDIAGONAL = 3, /* ///// */ + HS_CROSS = 4, /* +++++ */ + HS_DIAGCROSS = 5, /* xxxxx */ + } + + internal struct COLORREF { + internal byte R; + internal byte G; + internal byte B; + internal byte A; + } + + [StructLayout(LayoutKind.Sequential)] + private struct LOGBRUSH { + internal LogBrushStyle lbStyle; + internal COLORREF lbColor; + internal LogBrushHatch lbHatch; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct TEXTMETRIC { + internal int tmHeight; + internal int tmAscent; + internal int tmDescent; + internal int tmInternalLeading; + internal int tmExternalLeading; + internal int tmAveCharWidth; + internal int tmMaxCharWidth; + internal int tmWeight; + internal int tmOverhang; + internal int tmDigitizedAspectX; + internal int tmDigitizedAspectY; + internal short tmFirstChar; + internal short tmLastChar; + internal short tmDefaultChar; + internal short tmBreakChar; + internal byte tmItalic; + internal byte tmUnderlined; + internal byte tmStruckOut; + internal byte tmPitchAndFamily; + internal byte tmCharSet; + } + + public enum TernaryRasterOperations : uint + { + SRCCOPY = 0x00CC0020, + SRCPAINT = 0x00EE0086, + SRCAND = 0x008800C6, + SRCINVERT = 0x00660046, + SRCERASE = 0x00440328, + NOTSRCCOPY = 0x00330008, + NOTSRCERASE = 0x001100A6, + MERGECOPY = 0x00C000CA, + MERGEPAINT = 0x00BB0226, + PATCOPY = 0x00F00021, + PATPAINT = 0x00FB0A09, + PATINVERT = 0x005A0049, + DSTINVERT = 0x00550009, + BLACKNESS = 0x00000042, + WHITENESS = 0x00FF0062 + } + + [Flags] + private enum ScrollWindowExFlags { + SW_NONE = 0x0000, + SW_SCROLLCHILDREN = 0x0001, + SW_INVALIDATE = 0x0002, + SW_ERASE = 0x0004, + SW_SMOOTHSCROLL = 0x0010 + } + + internal enum SystemMetrics { + SM_CXSCREEN = 0, + SM_CYSCREEN = 1, + SM_CXVSCROLL = 2, + SM_CYHSCROLL = 3, + SM_CYCAPTION = 4, + SM_CXBORDER = 5, + SM_CYBORDER = 6, + SM_CXDLGFRAME = 7, + SM_CYDLGFRAME = 8, + SM_CYVTHUMB = 9, + SM_CXHTHUMB = 10, + SM_CXICON = 11, + SM_CYICON = 12, + SM_CXCURSOR = 13, + SM_CYCURSOR = 14, + SM_CYMENU = 15, + SM_CXFULLSCREEN = 16, + SM_CYFULLSCREEN = 17, + SM_CYKANJIWINDOW = 18, + SM_MOUSEPRESENT = 19, + SM_CYVSCROLL = 20, + SM_CXHSCROLL = 21, + SM_DEBUG = 22, + SM_SWAPBUTTON = 23, + SM_RESERVED1 = 24, + SM_RESERVED2 = 25, + SM_RESERVED3 = 26, + SM_RESERVED4 = 27, + SM_CXMIN = 28, + SM_CYMIN = 29, + SM_CXSIZE = 30, + SM_CYSIZE = 31, + SM_CXFRAME = 32, + SM_CYFRAME = 33, + SM_CXMINTRACK = 34, + SM_CYMINTRACK = 35, + SM_CXDOUBLECLK = 36, + SM_CYDOUBLECLK = 37, + SM_CXICONSPACING = 38, + SM_CYICONSPACING = 39, + SM_MENUDROPALIGNMENT = 40, + SM_PENWINDOWS = 41, + SM_DBCSENABLED = 42, + SM_CMOUSEBUTTONS = 43, + SM_CXFIXEDFRAME = SM_CXDLGFRAME, + SM_CYFIXEDFRAME = SM_CYDLGFRAME, + SM_CXSIZEFRAME = SM_CXFRAME, + SM_CYSIZEFRAME = SM_CYFRAME, + SM_SECURE = 44, + SM_CXEDGE = 45, + SM_CYEDGE = 46, + SM_CXMINSPACING = 47, + SM_CYMINSPACING = 48, + SM_CXSMICON = 49, + SM_CYSMICON = 50, + SM_CYSMCAPTION = 51, + SM_CXSMSIZE = 52, + SM_CYSMSIZE = 53, + SM_CXMENUSIZE = 54, + SM_CYMENUSIZE = 55, + SM_ARRANGE = 56, + SM_CXMINIMIZED = 57, + SM_CYMINIMIZED = 58, + SM_CXMAXTRACK = 59, + SM_CYMAXTRACK = 60, + SM_CXMAXIMIZED = 61, + SM_CYMAXIMIZED = 62, + SM_NETWORK = 63, + SM_CLEANBOOT = 67, + SM_CXDRAG = 68, + SM_CYDRAG = 69, + SM_SHOWSOUNDS = 70, + SM_CXMENUCHECK = 71, + SM_CYMENUCHECK = 72, + SM_SLOWMACHINE = 73, + SM_MIDEASTENABLED = 74, + SM_MOUSEWHEELPRESENT = 75, + SM_XVIRTUALSCREEN = 76, + SM_YVIRTUALSCREEN = 77, + SM_CXVIRTUALSCREEN = 78, + SM_CYVIRTUALSCREEN = 79, + SM_CMONITORS = 80, + SM_SAMEDISPLAYFORMAT = 81, + SM_IMMENABLED = 82, + SM_CXFOCUSBORDER = 83, + SM_CYFOCUSBORDER = 84, + SM_TABLETPC = 86, + SM_MEDIACENTER = 87, + SM_CMETRICS = 88 + } + + // We'll only support _WIN32_IE < 0x0500 for now + internal enum NotifyIconMessage { + NIM_ADD = 0x00000000, + NIM_MODIFY = 0x00000001, + NIM_DELETE = 0x00000002, + } + + [Flags] + internal enum NotifyIconFlags { + NIF_MESSAGE = 0x00000001, + NIF_ICON = 0x00000002, + NIF_TIP = 0x00000004, + NIF_STATE = 0x00000008, + NIF_INFO = 0x00000010 + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + internal struct NOTIFYICONDATA { + internal uint cbSize; + internal IntPtr hWnd; + internal uint uID; + internal NotifyIconFlags uFlags; + internal uint uCallbackMessage; + internal IntPtr hIcon; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)] + internal string szTip; + internal int dwState; + internal int dwStateMask; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] + internal string szInfo; + internal int uTimeoutOrVersion; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst=64)] + internal string szInfoTitle; + internal ToolTipIcon dwInfoFlags; + } + + [Flags] + internal enum DCExFlags { + DCX_WINDOW = 0x00000001, + DCX_CACHE = 0x00000002, + DCX_NORESETATTRS = 0x00000004, + DCX_CLIPCHILDREN = 0x00000008, + DCX_CLIPSIBLINGS = 0x00000010, + DCX_PARENTCLIP = 0x00000020, + DCX_EXCLUDERGN = 0x00000040, + DCX_INTERSECTRGN = 0x00000080, + DCX_EXCLUDEUPDATE = 0x00000100, + DCX_INTERSECTUPDATE = 0x00000200, + DCX_LOCKWINDOWUPDATE = 0x00000400, + DCX_USESTYLE = 0x00010000, + DCX_VALIDATE = 0x00200000 + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + internal struct CLIENTCREATESTRUCT { + internal IntPtr hWindowMenu; + internal uint idFirstChild; + } + + private enum ClassLong : int { + GCL_MENUNAME = -8, + GCL_HBRBACKGROUND = -10, + GCL_HCURSOR = -12, + GCL_HICON = -14, + GCL_HMODULE = -16, + GCL_CBWNDEXTRA = -18, + GCL_CBCLSEXTRA = -20, + GCL_WNDPROC = -24, + GCL_STYLE = -26, + GCW_ATOM = -32, + GCL_HICONSM = -34 + } + + [Flags] + internal enum GAllocFlags : uint { + GMEM_FIXED = 0x0000, + GMEM_MOVEABLE = 0x0002, + GMEM_NOCOMPACT = 0x0010, + GMEM_NODISCARD = 0x0020, + GMEM_ZEROINIT = 0x0040, + GMEM_MODIFY = 0x0080, + GMEM_DISCARDABLE = 0x0100, + GMEM_NOT_BANKED = 0x1000, + GMEM_SHARE = 0x2000, + GMEM_DDESHARE = 0x2000, + GMEM_NOTIFY = 0x4000, + GMEM_LOWER = GMEM_NOT_BANKED, + GMEM_VALID_FLAGS = 0x7F72, + GMEM_INVALID_HANDLE = 0x8000, + GHND = (GMEM_MOVEABLE | GMEM_ZEROINIT), + GPTR = (GMEM_FIXED | GMEM_ZEROINIT) + } + + internal enum ROP2DrawMode : int { + R2_BLACK = 1, + R2_NOTMERGEPEN = 2, + R2_MASKNOTPEN = 3, + R2_NOTCOPYPEN = 4, + R2_MASKPENNOT = 5, + R2_NOT = 6, + R2_XORPEN = 7, + R2_NOTMASKPEN = 8, + R2_MASKPEN = 9, + R2_NOTXORPEN = 10, + R2_NOP = 11, + R2_MERGENOTPEN = 12, + R2_COPYPEN = 13, + R2_MERGEPENNOT = 14, + R2_MERGEPEN = 15, + R2_WHITE = 16, + R2_LAST = 16 + } + + internal enum PenStyle : int { + PS_SOLID = 0, + PS_DASH = 1, + PS_DOT = 2, + PS_DASHDOT = 3, + PS_DASHDOTDOT = 4, + PS_NULL = 5, + PS_INSIDEFRAME = 6, + PS_USERSTYLE = 7, + PS_ALTERNATE = 8 + } + + internal enum PatBltRop : int { + PATCOPY = 0xf00021, + PATINVERT = 0x5a0049, + DSTINVERT = 0x550009, + BLACKNESS = 0x000042, + WHITENESS = 0xff0062, + } + + internal enum StockObject : int { + WHITE_BRUSH = 0, + LTGRAY_BRUSH = 1, + GRAY_BRUSH = 2, + DKGRAY_BRUSH = 3, + BLACK_BRUSH = 4, + NULL_BRUSH = 5, + HOLLOW_BRUSH = NULL_BRUSH, + WHITE_PEN = 6, + BLACK_PEN = 7, + NULL_PEN = 8, + OEM_FIXED_FONT = 10, + ANSI_FIXED_FONT = 11, + ANSI_VAR_FONT = 12, + SYSTEM_FONT = 13, + DEVICE_DEFAULT_FONT = 14, + DEFAULT_PALETTE = 15, + SYSTEM_FIXED_FONT = 16 + } + + internal enum HatchStyle : int { + HS_HORIZONTAL = 0, + HS_VERTICAL = 1, + HS_FDIAGONAL = 2, + HS_BDIAGONAL = 3, + HS_CROSS = 4, + HS_DIAGCROSS = 5 + } + + [Flags] + internal enum SndFlags : int { + SND_SYNC = 0x0000, + SND_ASYNC = 0x0001, + SND_NODEFAULT = 0x0002, + SND_MEMORY = 0x0004, + SND_LOOP = 0x0008, + SND_NOSTOP = 0x0010, + SND_NOWAIT = 0x00002000, + SND_ALIAS = 0x00010000, + SND_ALIAS_ID = 0x00110000, + SND_FILENAME = 0x00020000, + SND_RESOURCE = 0x00040004, + SND_PURGE = 0x0040, + SND_APPLICATION = 0x0080, + } + + [Flags] + internal enum LayeredWindowAttributes : int { + LWA_COLORKEY = 0x1, + LWA_ALPHA = 0x2, + } + + public enum ACLineStatus : byte { + Offline = 0, + Online = 1, + Unknown = 255 + } + + public enum BatteryFlag : byte { + High = 1, + Low = 2, + Critical = 4, + Charging = 8, + NoSystemBattery = 128, + Unknown = 255 + } + + [StructLayout (LayoutKind.Sequential)] + public class SYSTEMPOWERSTATUS { + public ACLineStatus _ACLineStatus; + public BatteryFlag _BatteryFlag; + public Byte _BatteryLifePercent; + public Byte _Reserved1; + public Int32 _BatteryLifeTime; + public Int32 _BatteryFullLifeTime; + } + #endregion + + #region Constructor & Destructor + private XplatUIWin32() { + // Handle singleton stuff first + ref_count=0; + + mouse_state = MouseButtons.None; + mouse_position = Point.Empty; + + grab_confined = false; + grab_area = Rectangle.Empty; + + message_queue = new Queue(); + + themes_enabled = false; + + wnd_proc = new WndProc(InternalWndProc); + + FosterParentLast = IntPtr.Zero; + + scroll_height = Win32GetSystemMetrics(SystemMetrics.SM_CYHSCROLL); + scroll_width = Win32GetSystemMetrics(SystemMetrics.SM_CXVSCROLL); + + timer_list = new Hashtable (); + registered_classes = new Hashtable (); + } + #endregion // Constructor & Destructor + + #region Private Support Methods + + private IntPtr GetFosterParent() + { + if (!IsWindow(FosterParentLast)) + { + FosterParentLast=Win32CreateWindow(WindowExStyles.WS_EX_TOOLWINDOW, "static", "Foster Parent Window", WindowStyles.WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + + if (FosterParentLast==IntPtr.Zero) { + Win32MessageBox(IntPtr.Zero, "Could not create foster window, win32 error " + Win32GetLastError().ToString(), "Oops", 0); + } + } + return FosterParentLast; + } + + private string RegisterWindowClass (int classStyle) + { + string class_name; + + lock (registered_classes) { + class_name = (string)registered_classes[classStyle]; + + if (class_name != null) + return class_name; + + class_name = string.Format ("ShiftUI.Form.Thread={0}.GUID={1}", System.Threading.Thread.GetDomainID ().ToString (), Guid.NewGuid().ToString()); + + WNDCLASS wndClass; + + wndClass.style = classStyle; + wndClass.lpfnWndProc = wnd_proc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 0; + wndClass.hbrBackground = (IntPtr)(GetSysColorIndex.COLOR_WINDOW + 1); + wndClass.hCursor = Win32LoadCursor (IntPtr.Zero, LoadCursorType.IDC_ARROW); + wndClass.hIcon = IntPtr.Zero; + wndClass.hInstance = IntPtr.Zero; + wndClass.lpszClassName = class_name; + wndClass.lpszMenuName = ""; + + bool result = Win32RegisterClass (ref wndClass); + + if (result == false) + Win32MessageBox (IntPtr.Zero, "Could not register the window class, win32 error " + Win32GetLastError ().ToString (), "Oops", 0); + + registered_classes[classStyle] = class_name; + } + + return class_name; + } + + private static bool RetrieveMessage(ref MSG msg) { + MSG message; + + if (message_queue.Count == 0) { + return false; + } + + message = (MSG)message_queue.Dequeue(); + msg = message; + + return true; + } + + private static bool StoreMessage(ref MSG msg) { + MSG message = new MSG(); + + message = msg; + message_queue.Enqueue(message); + + return true; + } + + internal static String AnsiToString(IntPtr ansi_data) { + return (string)Marshal.PtrToStringAnsi(ansi_data); + } + + internal static String UnicodeToString(IntPtr unicode_data) { + return (string)Marshal.PtrToStringUni(unicode_data); + } + + internal static Image DIBtoImage(IntPtr dib_data) { + BITMAPINFOHEADER bmi; + int ncolors; + int imagesize; + //int palettesize; + Bitmap bmp; + BitmapData bits; + ColorPalette pal; + int[] palette; + byte[] imagebits; + int bytesPerLine; + + bmi = (BITMAPINFOHEADER)Marshal.PtrToStructure(dib_data, typeof(BITMAPINFOHEADER)); + + ncolors = (int)bmi.biClrUsed; + if (ncolors == 0) { + if (bmi.biBitCount < 24) { + ncolors = (int)(1 << bmi.biBitCount); + } + } + //palettesize = ncolors * 4; + + imagesize = (int)bmi.biSizeImage; + if (imagesize == 0) { + imagesize = (int)(((((bmi.biWidth * bmi.biBitCount) + 31) & ~31) >> 3) * bmi.biHeight); + } + + switch(bmi.biBitCount) { + case 1: { // Monochrome + bmp = new Bitmap(bmi.biWidth, bmi.biHeight, PixelFormat.Format1bppIndexed); + palette = new int[2]; + break; + } + + case 4: { // 4bpp + bmp = new Bitmap(bmi.biWidth, bmi.biHeight, PixelFormat.Format4bppIndexed); + palette = new int[16]; + break; + } + + case 8: { // 8bpp + bmp = new Bitmap(bmi.biWidth, bmi.biHeight, PixelFormat.Format8bppIndexed); + palette = new int[256]; + break; + } + + case 24: + case 32: { // 32bpp + bmp = new Bitmap(bmi.biWidth, bmi.biHeight, PixelFormat.Format32bppArgb); + palette = new int[0]; + break; + } + + default: { + throw new Exception("Unexpected number of bits:" + bmi.biBitCount.ToString()); + } + } + + if (bmi.biBitCount < 24) { + pal = bmp.Palette; // Managed palette + Marshal.Copy((IntPtr)((int)dib_data + Marshal.SizeOf(typeof(BITMAPINFOHEADER))), palette, 0, palette.Length); + + for (int i = 0; i < ncolors; i++) { + pal.Entries[i] = Color.FromArgb(palette[i] | unchecked((int)0xff000000)); + } + bmp.Palette = pal; + } + + bytesPerLine = (int)((((bmi.biWidth * bmi.biBitCount) + 31) & ~31) >> 3); + bits = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat); + + imagebits = new byte[bytesPerLine]; + + for (int y = 0; y < bmi.biHeight; y++) { + // Copy from source to managed + Marshal.Copy((IntPtr)((int)dib_data + Marshal.SizeOf(typeof(BITMAPINFOHEADER)) + palette.Length * 4 + bytesPerLine * y), imagebits, 0, bytesPerLine); + + // Copy from managed to dest + Marshal.Copy(imagebits, 0, (IntPtr)((int)bits.Scan0 + bits.Stride * (bmi.biHeight - 1 - y)), imagebits.Length); + } + + bmp.UnlockBits(bits); + + return bmp; + } + + internal static byte[] ImageToDIB(Image image) { + MemoryStream ms; + byte[] buffer; + byte[] retbuf; + + ms = new MemoryStream(); + image.Save(ms, ImageFormat.Bmp); + buffer = ms.GetBuffer(); + + // Filter out the file header + retbuf = new byte[buffer.Length]; + Array.Copy(buffer, 14, retbuf, 0, buffer.Length - 14); + return retbuf; + } + + internal static IntPtr DupGlobalMem(IntPtr mem) { + IntPtr dup; + IntPtr dup_ptr; + IntPtr mem_ptr; + uint len; + + len = Win32GlobalSize(mem); + mem_ptr = Win32GlobalLock(mem); + + dup = Win32GlobalAlloc(GAllocFlags.GMEM_MOVEABLE, (int)len); + dup_ptr = Win32GlobalLock(dup); + + Win32CopyMemory(dup_ptr, mem_ptr, (int)len); + + Win32GlobalUnlock(mem); + Win32GlobalUnlock(dup); + + return dup; + } + + private int GetSystemParametersInfoInt (SPIAction spi) + { + int value = 0; + + Win32SystemParametersInfo (spi, 0, ref value, 0); + + return value; + } + + private bool GetSystemParametersInfoBool (SPIAction spi) + { + bool value = false; + + Win32SystemParametersInfo (spi, 0, ref value, 0); + + return value; + } + #endregion // Private Support Methods + + #region Static Properties + internal override int ActiveWindowTrackingDelay { + get { return GetSystemParametersInfoInt (SPIAction.SPI_GETACTIVEWNDTRKTIMEOUT); } + } + + internal override int CaretWidth { + get { + // Supported on 2k, XP, 2k3 + + if (Environment.OSVersion.Version.Major < 5) + throw new NotSupportedException (); + + return GetSystemParametersInfoInt (SPIAction.SPI_GETCARETWIDTH); + } + } + + internal override int FontSmoothingContrast { + get { + // Supported on XP, 2k3 + + if (Environment.OSVersion.Version.Major < 5 || (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 0)) + throw new NotSupportedException (); + + return GetSystemParametersInfoInt (SPIAction.SPI_GETFONTSMOOTHINGCONTRAST); + } + } + + internal override int FontSmoothingType { + get { + // Supported on XP, 2k3 + + if (Environment.OSVersion.Version.Major < 5 || (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 0)) + throw new NotSupportedException (); + + return GetSystemParametersInfoInt (SPIAction.SPI_GETFONTSMOOTHINGTYPE); + } + } + + internal override int HorizontalResizeBorderThickness { + get { return Win32GetSystemMetrics (SystemMetrics.SM_CXSIZEFRAME); } + } + + internal override bool IsActiveWindowTrackingEnabled { + get { return GetSystemParametersInfoBool (SPIAction.SPI_GETACTIVEWINDOWTRACKING); } + } + + internal override bool IsComboBoxAnimationEnabled { + get { return GetSystemParametersInfoBool (SPIAction.SPI_GETCOMBOBOXANIMATION); } + } + + internal override bool IsDropShadowEnabled { + get { + // Supported on XP, 2k3 + + if (Environment.OSVersion.Version.Major < 5 || (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 0)) + throw new NotSupportedException (); + + return GetSystemParametersInfoBool (SPIAction.SPI_GETDROPSHADOW); + } + } + + internal override bool IsFontSmoothingEnabled { + get { return GetSystemParametersInfoBool (SPIAction.SPI_GETFONTSMOOTHING); } + } + + internal override bool IsHotTrackingEnabled { + get { return GetSystemParametersInfoBool (SPIAction.SPI_GETHOTTRACKING); } + } + + internal override bool IsIconTitleWrappingEnabled { + get { return GetSystemParametersInfoBool (SPIAction.SPI_GETICONTITLEWRAP); } + } + + internal override bool IsKeyboardPreferred { + get { return GetSystemParametersInfoBool (SPIAction.SPI_GETKEYBOARDPREF); } + } + + internal override bool IsListBoxSmoothScrollingEnabled { + get { return GetSystemParametersInfoBool (SPIAction.SPI_GETLISTBOXSMOOTHSCROLLING); } + } + + internal override bool IsMenuAnimationEnabled { + get { return GetSystemParametersInfoBool (SPIAction.SPI_GETMENUANIMATION); } + } + + internal override bool IsMenuFadeEnabled { + get { return GetSystemParametersInfoBool (SPIAction.SPI_GETMENUFADE); } + } + + internal override bool IsMinimizeRestoreAnimationEnabled { + get { + ANIMATIONINFO ai = new ANIMATIONINFO (); + ai.cbSize = (uint)Marshal.SizeOf (ai); + + Win32SystemParametersInfo (SPIAction.SPI_GETANIMATION, 0, ref ai, 0); + return ai.iMinAnimate == 0 ? false : true; + } + } + + internal override bool IsSelectionFadeEnabled { + get { return GetSystemParametersInfoBool (SPIAction.SPI_GETSELECTIONFADE); } + } + + internal override bool IsSnapToDefaultEnabled { + get { return GetSystemParametersInfoBool (SPIAction.SPI_GETSNAPTODEFBUTTON); } + } + + internal override bool IsTitleBarGradientEnabled { + get { return GetSystemParametersInfoBool (SPIAction.SPI_GETGRADIENTCAPTIONS); } + } + + internal override bool IsToolTipAnimationEnabled { + get { return GetSystemParametersInfoBool (SPIAction.SPI_GETTOOLTIPANIMATION); } + } + + internal override Size MenuBarButtonSize { + get { + return new Size (Win32GetSystemMetrics (SystemMetrics.SM_CXMENUSIZE), + Win32GetSystemMetrics (SystemMetrics.SM_CYMENUSIZE)); + } + } + + public override Size MenuButtonSize { + get { + return new Size ( + Win32GetSystemMetrics (SystemMetrics.SM_CXMENUSIZE), + Win32GetSystemMetrics (SystemMetrics.SM_CYMENUSIZE)); + } + } + + internal override int MenuShowDelay { + get { return GetSystemParametersInfoInt (SPIAction.SPI_GETMENUSHOWDELAY); } + } + + internal override int MouseSpeed { + get { return GetSystemParametersInfoInt (SPIAction.SPI_GETMOUSESPEED); } + } + + internal override LeftRightAlignment PopupMenuAlignment { + get { return GetSystemParametersInfoBool (SPIAction.SPI_GETMENUDROPALIGNMENT) == true ? LeftRightAlignment.Left : LeftRightAlignment.Right; } + } + + internal override PowerStatus PowerStatus { + get { + SYSTEMPOWERSTATUS p = new SYSTEMPOWERSTATUS (); + + Win32GetSystemPowerStatus (p); + + PowerStatus ps = new PowerStatus ((BatteryChargeStatus)p._BatteryFlag, p._BatteryFullLifeTime, (float)p._BatteryLifePercent / 255f, p._BatteryLifeTime, (PowerLineStatus)p._ACLineStatus); + + return ps; + } + } + + internal override int SizingBorderWidth { + get { return Win32GetSystemMetrics (SystemMetrics.SM_CXSIZEFRAME); } + } + + internal override Size SmallCaptionButtonSize { + get { + return new Size (Win32GetSystemMetrics (SystemMetrics.SM_CXSMSIZE), + Win32GetSystemMetrics (SystemMetrics.SM_CYSMSIZE)); + } + } + + internal override bool UIEffectsEnabled { + get { return GetSystemParametersInfoBool (SPIAction.SPI_GETUIEFFECTS); } + } + + internal override int VerticalResizeBorderThickness { + get { return Win32GetSystemMetrics (SystemMetrics.SM_CYSIZEFRAME); } + } + + internal override void RaiseIdle (EventArgs e) + { + if (Idle != null) + Idle (this, e); + } + + internal override Keys ModifierKeys { + get { + short state; + Keys key_state; + + key_state = Keys.None; + + state = Win32GetKeyState(VirtualKeys.VK_SHIFT); + if ((state & 0x8000) != 0) { + key_state |= Keys.Shift; + } + state = Win32GetKeyState(VirtualKeys.VK_CONTROL); + if ((state & 0x8000) != 0) { + key_state |= Keys.Widget; + } + + state = Win32GetKeyState(VirtualKeys.VK_MENU); + if ((state & 0x8000) != 0) { + key_state |= Keys.Alt; + } + + return key_state; + } + } + + internal override MouseButtons MouseButtons { + get { + return mouse_state; + } + } + + internal override Point MousePosition { + get { + return mouse_position; + } + } + + internal override Size MouseHoverSize { + get { + int width = 4; + int height = 4; + + Win32SystemParametersInfo(SPIAction.SPI_GETMOUSEHOVERWIDTH, 0, ref width, 0); + Win32SystemParametersInfo(SPIAction.SPI_GETMOUSEHOVERWIDTH, 0, ref height, 0); + return new Size(width, height); + } + } + + internal override int MouseHoverTime { + get { + int time = 500; + + Win32SystemParametersInfo(SPIAction.SPI_GETMOUSEHOVERTIME, 0, ref time, 0); + return time; + } + } + + internal override int MouseWheelScrollDelta { + get { + int delta = 120; + Win32SystemParametersInfo(SPIAction.SPI_GETWHEELSCROLLLINES, 0, ref delta, 0); + return delta; + } + } + + internal override int HorizontalScrollBarHeight { + get { + return scroll_height; + } + } + + internal override bool UserClipWontExposeParent { + get { + return false; + } + } + + + internal override int VerticalScrollBarWidth { + get { + return scroll_width; + } + } + + internal override int MenuHeight { + get { + return Win32GetSystemMetrics(SystemMetrics.SM_CYMENU); + } + } + + internal override Size Border3DSize { + get { + return new Size (Win32GetSystemMetrics (SystemMetrics.SM_CXEDGE), + Win32GetSystemMetrics (SystemMetrics.SM_CYEDGE)); + } + } + + internal override Size BorderSize { + get { + return new Size (Win32GetSystemMetrics (SystemMetrics.SM_CXBORDER), + Win32GetSystemMetrics (SystemMetrics.SM_CYBORDER)); + } + } + + internal override bool DropTarget { + get { + return false; + } + + set { + if (value) { + //throw new NotImplementedException("Need to figure out D'n'D for Win32"); + } + } + } + + internal override Size CaptionButtonSize { + get { + return new Size (Win32GetSystemMetrics (SystemMetrics.SM_CXSIZE), + Win32GetSystemMetrics (SystemMetrics.SM_CYSIZE)); + } + } + + internal override int CaptionHeight { + get { + return Win32GetSystemMetrics(SystemMetrics.SM_CYCAPTION); + } + } + + internal override Size CursorSize { + get { + return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR), Win32GetSystemMetrics(SystemMetrics.SM_CYCURSOR)); + } + } + + internal override bool DragFullWindows { + get { + int full = 0; + Win32SystemParametersInfo (SPIAction.SPI_GETDRAGFULLWINDOWS, 0, ref full, 0); + return (full != 0); + } + } + + internal override Size DragSize { + get { + return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXDRAG), Win32GetSystemMetrics(SystemMetrics.SM_CYDRAG)); + } + } + + internal override Size DoubleClickSize { + get { + return new Size (Win32GetSystemMetrics (SystemMetrics.SM_CXDOUBLECLK), + Win32GetSystemMetrics (SystemMetrics.SM_CYDOUBLECLK)); + } + } + + internal override int DoubleClickTime { + get { + return Win32GetDoubleClickTime (); + } + } + + internal override Size FixedFrameBorderSize { + get { + return new Size (Win32GetSystemMetrics (SystemMetrics.SM_CXFIXEDFRAME), + Win32GetSystemMetrics (SystemMetrics.SM_CYFIXEDFRAME)); + } + } + + internal override Size FrameBorderSize { + get { + return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXFRAME), Win32GetSystemMetrics(SystemMetrics.SM_CYFRAME)); + } + } + + internal override Size IconSize { + get { + return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXICON), Win32GetSystemMetrics(SystemMetrics.SM_CYICON)); + } + } + + internal override Size MaxWindowTrackSize { + get { + return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXMAXTRACK), Win32GetSystemMetrics(SystemMetrics.SM_CYMAXTRACK)); + } + } + + internal override bool MenuAccessKeysUnderlined { + get { + int underlined = 0; + Win32SystemParametersInfo (SPIAction.SPI_GETKEYBOARDCUES, 0, ref underlined, 0); + return (underlined != 0); + } + } + + internal override Size MinimizedWindowSize { + get { + return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXMINIMIZED), Win32GetSystemMetrics(SystemMetrics.SM_CYMINIMIZED)); + } + } + + internal override Size MinimizedWindowSpacingSize { + get { + return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXMINSPACING), Win32GetSystemMetrics(SystemMetrics.SM_CYMINSPACING)); + } + } + + internal override Size MinimumWindowSize { + get { + return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXMIN), Win32GetSystemMetrics(SystemMetrics.SM_CYMIN)); + } + } + + internal override Size MinWindowTrackSize { + get { + return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXMINTRACK), Win32GetSystemMetrics(SystemMetrics.SM_CYMINTRACK)); + } + } + + internal override Size SmallIconSize { + get { + return new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXSMICON), Win32GetSystemMetrics(SystemMetrics.SM_CYSMICON)); + } + } + + internal override int MouseButtonCount { + get { + return Win32GetSystemMetrics(SystemMetrics.SM_CMOUSEBUTTONS); + } + } + + internal override bool MouseButtonsSwapped { + get { + return Win32GetSystemMetrics(SystemMetrics.SM_SWAPBUTTON) != 0; + } + } + + internal override bool MouseWheelPresent { + get { + return Win32GetSystemMetrics(SystemMetrics.SM_MOUSEWHEELPRESENT) != 0; + } + } + + internal override Rectangle VirtualScreen { + get { + return new Rectangle( Win32GetSystemMetrics(SystemMetrics.SM_XVIRTUALSCREEN), Win32GetSystemMetrics(SystemMetrics.SM_YVIRTUALSCREEN), + Win32GetSystemMetrics(SystemMetrics.SM_CXVIRTUALSCREEN), Win32GetSystemMetrics(SystemMetrics.SM_CYVIRTUALSCREEN)); + } + } + + internal override Rectangle WorkingArea { + get { + RECT rect; + + rect = new RECT(); + Win32SystemParametersInfo(SPIAction.SPI_GETWORKAREA, 0, ref rect, 0); + return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); + //return new Rectangle(0, 0, Win32GetSystemMetrics(SystemMetrics.SM.SM_CXSCREEN), Win32GetSystemMetrics(SystemMetrics.SM_CYSCREEN)); + } + } + + [MonoTODO] + internal override Screen[] AllScreens { + get { + // To support multiples, we need to use GetMonitorInfo API on Win32 + return null; + } + } + + internal override bool ThemesEnabled { + get { + return XplatUIWin32.themes_enabled; + } + } + + internal override bool RequiresPositiveClientAreaSize { + get { + return false; + } + } + + public override int ToolWindowCaptionHeight { + get { + return Win32GetSystemMetrics (SystemMetrics.SM_CYSMCAPTION); + } + } + + public override Size ToolWindowCaptionButtonSize { + get { + return new Size ( + Win32GetSystemMetrics (SystemMetrics.SM_CXSMSIZE), + Win32GetSystemMetrics (SystemMetrics.SM_CYSMSIZE)); + } + } + #endregion // Static Properties + + #region Singleton Specific Code + public static XplatUIWin32 GetInstance() { + if (instance==null) { + instance=new XplatUIWin32(); + } + ref_count++; + return instance; + } + + public int Reference { + get { + return ref_count; + } + } + #endregion + + #region Public Static Methods + internal override IntPtr InitializeDriver() { + return IntPtr.Zero; + } + + internal override void ShutdownDriver(IntPtr token) { + Console.WriteLine("XplatUIWin32 ShutdownDriver called"); + } + + + internal void Version() { + Console.WriteLine("Xplat version $revision: $"); + } + + string GetSoundAlias (AlertType alert) + { + switch (alert) { + case AlertType.Error: + return "SystemHand"; + case AlertType.Question: + return "SystemQuestion"; + case AlertType.Warning: + return "SystemExclamation"; + case AlertType.Information: + return "SystemAsterisk"; + default: + return "SystemDefault"; + } + } + + internal override void AudibleAlert(AlertType alert) { + Win32PlaySound(GetSoundAlias (alert), IntPtr.Zero, SndFlags.SND_ALIAS_ID | SndFlags.SND_ASYNC | SndFlags.SND_NOSTOP | SndFlags.SND_NOWAIT); + } + + internal override void BeginMoveResize (IntPtr handle) { + } + + internal override void GetDisplaySize(out Size size) { + RECT rect; + + Win32GetWindowRect(Win32GetDesktopWindow(), out rect); + + size = new Size(rect.right - rect.left, rect.bottom - rect.top); + } + + internal override void EnableThemes() { + themes_enabled=true; + } + + internal override IntPtr CreateWindow(CreateParams cp) { + IntPtr WindowHandle; + IntPtr ParentHandle; + Hwnd hwnd; + + hwnd = new Hwnd(); + + ParentHandle=cp.Parent; + + if ((ParentHandle==IntPtr.Zero) && (cp.Style & (int)(WindowStyles.WS_CHILD))!=0) { + // We need to use our foster parent window until this poor child gets it's parent assigned + ParentHandle = GetFosterParent(); + } + + if ( ((cp.Style & (int)(WindowStyles.WS_CHILD | WindowStyles.WS_POPUP))==0) && ((cp.ExStyle & (int)WindowExStyles.WS_EX_APPWINDOW) == 0)) { + // If we want to be hidden from the taskbar we need to be 'owned' by + // something not on the taskbar. FosterParent is just that + ParentHandle = GetFosterParent(); + } + + Point location; + if (cp.HasWindowManager) { + location = Hwnd.GetNextStackedFormLocation (cp, Hwnd.ObjectFromHandle (cp.Parent)); + } else { + location = new Point (cp.X, cp.Y); + } + + string class_name = RegisterWindowClass (cp.ClassStyle); + HwndCreating = hwnd; + + // We cannot actually send the WS_EX_MDICHILD flag to Windows because we + // are faking MDI, not uses Windows' version. + if ((cp.WindowExStyle & WindowExStyles.WS_EX_MDICHILD) == WindowExStyles.WS_EX_MDICHILD) + cp.WindowExStyle ^= WindowExStyles.WS_EX_MDICHILD; + + WindowHandle = Win32CreateWindow (cp.WindowExStyle, class_name, cp.Caption, cp.WindowStyle, location.X, location.Y, cp.Width, cp.Height, ParentHandle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + + HwndCreating = null; + + if (WindowHandle==IntPtr.Zero) { + int error = Marshal.GetLastWin32Error (); + + Win32MessageBox(IntPtr.Zero, "Error : " + error.ToString(), "Failed to create window, class '"+cp.ClassName+"'", 0); + } + + hwnd.ClientWindow = WindowHandle; + hwnd.Mapped = true; + Win32SetWindowLong(WindowHandle, WindowLong.GWL_USERDATA, (uint)ThemeEngine.Current.DefaultControlBackColor.ToArgb()); + + return WindowHandle; + } + + internal override IntPtr CreateWindow(IntPtr Parent, int X, int Y, int Width, int Height) { + CreateParams create_params = new CreateParams(); + + create_params.Caption = ""; + create_params.X = X; + create_params.Y = Y; + create_params.Width = Width; + create_params.Height = Height; + + create_params.ClassName=XplatUI.GetDefaultClassName (GetType ()); + create_params.ClassStyle = 0; + create_params.ExStyle=0; + create_params.Parent=IntPtr.Zero; + create_params.Param=0; + + return CreateWindow(create_params); + } + + internal override void DestroyWindow(IntPtr handle) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + Win32DestroyWindow(handle); + hwnd.Dispose(); + return; + } + + internal override void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max) { + // We do nothing, Form has to handle WM_GETMINMAXINFO + } + + + internal override FormWindowState GetWindowState(IntPtr handle) { + uint style; + + style = Win32GetWindowLong(handle, WindowLong.GWL_STYLE); + if ((style & (uint)WindowStyles.WS_MAXIMIZE) != 0) { + return FormWindowState.Maximized; + } else if ((style & (uint)WindowStyles.WS_MINIMIZE) != 0) { + return FormWindowState.Minimized; + } + return FormWindowState.Normal; + } + + internal override void SetWindowState(IntPtr hwnd, FormWindowState state) { + switch(state) { + case FormWindowState.Normal: { + Win32ShowWindow(hwnd, WindowPlacementFlags.SW_RESTORE); + return; + } + + case FormWindowState.Minimized: { + Win32ShowWindow(hwnd, WindowPlacementFlags.SW_MINIMIZE); + return; + } + + case FormWindowState.Maximized: { + Win32ShowWindow(hwnd, WindowPlacementFlags.SW_MAXIMIZE); + return; + } + } + } + + internal override void SetWindowStyle(IntPtr handle, CreateParams cp) { + + Win32SetWindowLong(handle, WindowLong.GWL_STYLE, (uint)cp.Style); + Win32SetWindowLong(handle, WindowLong.GWL_EXSTYLE, (uint)cp.ExStyle); + + // From MSDN: + // Certain window data is cached, so changes you make using SetWindowLong + // will not take effect until you call the SetWindowPos function. Specifically, + // if you change any of the frame styles, you must call SetWindowPos with + // the SWP_FRAMECHANGED flag for the cache to be updated properly. + if (cp.control is Form) + XplatUI.RequestNCRecalc (handle); + } + + internal override double GetWindowTransparency(IntPtr handle) + { + LayeredWindowAttributes lwa; + COLORREF clrRef; + byte alpha; + + if (0 == Win32GetLayeredWindowAttributes (handle, out clrRef, out alpha, out lwa)) + return 1.0; + + return ((double)alpha) / 255.0; + } + + internal override void SetWindowTransparency(IntPtr handle, double transparency, Color key) { + LayeredWindowAttributes lwa = LayeredWindowAttributes.LWA_ALPHA; + byte opacity = (byte)(transparency*255); + COLORREF clrRef = new COLORREF(); + if (key != Color.Empty) { + clrRef.R = key.R; + clrRef.G = key.G; + clrRef.B = key.B; + lwa = (LayeredWindowAttributes)( (int)lwa | (int)LayeredWindowAttributes.LWA_COLORKEY ); + } + RECT rc; + rc.right = 1000; + rc.bottom = 1000; + Win32SetLayeredWindowAttributes(handle, clrRef, opacity, lwa); + } + + TransparencySupport support; + bool queried_transparency_support; + internal override TransparencySupport SupportsTransparency() { + if (queried_transparency_support) + return support; + + bool flag; + support = TransparencySupport.None; + + flag = true; + try { + Win32SetLayeredWindowAttributes (IntPtr.Zero, new COLORREF (), 255, LayeredWindowAttributes.LWA_ALPHA); + } + catch (EntryPointNotFoundException) { flag = false; } + catch { /* swallow everything else */ } + + if (flag) support |= TransparencySupport.Set; + + flag = true; + try { + LayeredWindowAttributes lwa; + COLORREF clrRef; + byte alpha; + + Win32GetLayeredWindowAttributes (IntPtr.Zero, out clrRef, out alpha, out lwa); + } + catch (EntryPointNotFoundException) { flag = false; } + catch { /* swallow everything else */ } + + if (flag) support |= TransparencySupport.Get; + + queried_transparency_support = true; + return support; + } + + internal override void UpdateWindow(IntPtr handle) { + Win32UpdateWindow(handle); + } + + internal override PaintEventArgs PaintEventStart(ref Message msg, IntPtr handle, bool client) { + IntPtr hdc; + PAINTSTRUCT ps; + PaintEventArgs paint_event; + RECT rect; + Rectangle clip_rect; + Hwnd hwnd; + + clip_rect = new Rectangle(); + rect = new RECT(); + ps = new PAINTSTRUCT(); + + hwnd = Hwnd.ObjectFromHandle(msg.HWnd); + + if (client) { + if (Win32GetUpdateRect(msg.HWnd, ref rect, false)) { + if (handle != msg.HWnd) { + // We need to validate the window where the paint message + // was generated, otherwise we'll never stop getting paint + // messages. + Win32GetClientRect (msg.HWnd, out rect); + Win32ValidateRect (msg.HWnd, ref rect); + hdc = Win32GetDC (handle); + } else { + hdc = Win32BeginPaint (handle, ref ps); + rect = ps.rcPaint; + } + } else { + hdc = Win32GetDC(handle); + } + clip_rect = rect.ToRectangle (); + } else { + hdc = Win32GetWindowDC (handle); + + // HACK this in for now + Win32GetWindowRect (handle, out rect); + clip_rect = new Rectangle (0, 0, rect.Width, rect.Height); + } + + // If we called BeginPaint, store the PAINTSTRUCT, + // otherwise store hdc, so that PaintEventEnd can know + // whether to call EndPaint or ReleaseDC. + if (ps.hdc != IntPtr.Zero) { + hwnd.drawing_stack.Push (ps); + } else { + hwnd.drawing_stack.Push (hdc); + } + + Graphics dc = Graphics.FromHdc(hdc); + hwnd.drawing_stack.Push (dc); + + paint_event = new PaintEventArgs(dc, clip_rect); + + return paint_event; + } + + internal override void PaintEventEnd(ref Message m, IntPtr handle, bool client) { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(m.HWnd); + + Graphics dc = (Graphics)hwnd.drawing_stack.Pop(); + dc.Dispose (); + + object o = hwnd.drawing_stack.Pop(); + if (o is IntPtr) { + IntPtr hdc = (IntPtr) o; + Win32ReleaseDC (handle, hdc); + } else if (o is PAINTSTRUCT) { + PAINTSTRUCT ps = (PAINTSTRUCT) o; + Win32EndPaint (handle, ref ps); + } + } + + + internal override void SetWindowPos(IntPtr handle, int x, int y, int width, int height) { + Win32MoveWindow(handle, x, y, width, height, true); + return; + } + + internal override void GetWindowPos(IntPtr handle, bool is_toplevel, out int x, out int y, out int width, out int height, out int client_width, out int client_height) { + IntPtr parent; + RECT rect; + POINT pt; + + Win32GetWindowRect(handle, out rect); + width = rect.right - rect.left; + height = rect.bottom - rect.top; + + pt.x=rect.left; + pt.y=rect.top; + + parent = Win32GetAncestor (handle, AncestorType.GA_PARENT); + if (parent != IntPtr.Zero && parent != Win32GetDesktopWindow ()) + Win32ScreenToClient(parent, ref pt); + + x = pt.x; + y = pt.y; + + Win32GetClientRect(handle, out rect); + client_width = rect.right - rect.left; + client_height = rect.bottom - rect.top; + return; + } + + internal override void Activate(IntPtr handle) { + Win32SetActiveWindow(handle); + // delayed timer enabled + lock (timer_list) { + foreach (Timer t in timer_list.Values) { + if (t.Enabled && t.window == IntPtr.Zero) { + t.window = handle; + int id = t.GetHashCode (); + Win32SetTimer(handle, id, (uint)t.Interval, IntPtr.Zero); + } + } + } + } + + internal override void Invalidate(IntPtr handle, Rectangle rc, bool clear) { + RECT rect; + + rect.left=rc.Left; + rect.top=rc.Top; + rect.right=rc.Right; + rect.bottom=rc.Bottom; + Win32InvalidateRect(handle, ref rect, clear); + } + + + internal override void InvalidateNC (IntPtr handle) + { + // found this gem at + // http://www.dotnet247.com/247reference/msgs/58/292037.aspx + Win32SetWindowPos(handle, IntPtr.Zero, + 0, 0, 0, 0, + SetWindowPosFlags.SWP_NOMOVE | + SetWindowPosFlags.SWP_NOSIZE | + SetWindowPosFlags.SWP_NOZORDER | + SetWindowPosFlags.SWP_NOACTIVATE | + SetWindowPosFlags.SWP_DRAWFRAME); + } + + private IntPtr InternalWndProc (IntPtr hWnd, Msg msg, IntPtr wParam, IntPtr lParam) + { + if (HwndCreating != null && HwndCreating.ClientWindow == IntPtr.Zero) + HwndCreating.ClientWindow = hWnd; + return NativeWindow.WndProc (hWnd, msg, wParam, lParam); + } + + internal override IntPtr DefWndProc(ref Message msg) { + msg.Result=Win32DefWindowProc(msg.HWnd, (Msg)msg.Msg, msg.WParam, msg.LParam); + return msg.Result; + } + + internal override void HandleException(Exception e) { + StackTrace st = new StackTrace(e); + Win32MessageBox(IntPtr.Zero, e.Message+st.ToString(), "Exception", 0); + Console.WriteLine("{0}{1}", e.Message, st.ToString()); + } + + internal override void DoEvents() { + MSG msg = new MSG(); + + while (GetMessage(ref msg, IntPtr.Zero, 0, 0, false)) { + Message m = Message.Create (msg.hwnd, (int)msg.message, msg.wParam, msg.lParam); + + if (Application.FilterMessage (ref m)) + continue; + + XplatUI.TranslateMessage(ref msg); + XplatUI.DispatchMessage(ref msg); + } + } + + internal override bool PeekMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) { + return Win32PeekMessage(ref msg, hWnd, wFilterMin, wFilterMax, flags); + } + + internal override void PostQuitMessage(int exitCode) { + Win32PostQuitMessage(exitCode); + } + + internal override void RequestAdditionalWM_NCMessages(IntPtr hwnd, bool hover, bool leave) + { + if (wm_nc_registered == null) + wm_nc_registered = new Hashtable (); + + TMEFlags flags = TMEFlags.TME_NONCLIENT; + if (hover) + flags |= TMEFlags.TME_HOVER; + if (leave) + flags |= TMEFlags.TME_LEAVE; + + if (flags == TMEFlags.TME_NONCLIENT) { + if (wm_nc_registered.Contains (hwnd)) { + wm_nc_registered.Remove (hwnd); + } + } else { + if (!wm_nc_registered.Contains (hwnd)) { + wm_nc_registered.Add (hwnd, flags); + } else { + wm_nc_registered [hwnd] = flags; + } + } + } + + internal override void RequestNCRecalc(IntPtr handle) { + Win32SetWindowPos(handle, IntPtr.Zero, 0, 0, 0, 0, SetWindowPosFlags.SWP_FRAMECHANGED | SetWindowPosFlags.SWP_NOOWNERZORDER | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE); + } + + internal override void ResetMouseHover(IntPtr handle) { + TRACKMOUSEEVENT tme; + + tme = new TRACKMOUSEEVENT(); + tme.size = Marshal.SizeOf(tme); + tme.hWnd = handle; + tme.dwFlags = TMEFlags.TME_LEAVE | TMEFlags.TME_HOVER; + Win32TrackMouseEvent(ref tme); + } + + + internal override bool GetMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax) { + return GetMessage(ref msg, hWnd, wFilterMin, wFilterMax, true); + } + + private bool GetMessage(ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, bool blocking) { + bool result; + + msg.refobject = 0; + if (RetrieveMessage(ref msg)) { + return true; + } + + if (blocking) { + result = Win32GetMessage(ref msg, hWnd, wFilterMin, wFilterMax); + } else { + result = Win32PeekMessage(ref msg, hWnd, wFilterMin, wFilterMax, (uint)PeekMessageFlags.PM_REMOVE); + if (!result) { + return false; + } + } + + // We need to fake WM_MOUSE_ENTER + switch (msg.message) { + case Msg.WM_LBUTTONDOWN: { + mouse_state |= MouseButtons.Left; + break; + } + + case Msg.WM_MBUTTONDOWN: { + mouse_state |= MouseButtons.Middle; + break; + } + + case Msg.WM_RBUTTONDOWN: { + mouse_state |= MouseButtons.Right; + break; + } + + case Msg.WM_LBUTTONUP: { + mouse_state &= ~MouseButtons.Left; + break; + } + + case Msg.WM_MBUTTONUP: { + mouse_state &= ~MouseButtons.Middle; + break; + } + + case Msg.WM_RBUTTONUP: { + mouse_state &= ~MouseButtons.Right; + break; + } + + case Msg.WM_ASYNC_MESSAGE: { + XplatUIDriverSupport.ExecuteClientMessage((GCHandle)msg.lParam); + break; + } + + case Msg.WM_MOUSEMOVE: { + if (msg.hwnd != prev_mouse_hwnd) { + TRACKMOUSEEVENT tme; + + mouse_state = Widget.FromParamToMouseButtons ((int)msg.lParam.ToInt32()); + + // The current message will be sent out next time around + StoreMessage(ref msg); + + // This is the message we want to send at this point + msg.message = Msg.WM_MOUSE_ENTER; + + prev_mouse_hwnd = msg.hwnd; + + tme = new TRACKMOUSEEVENT(); + tme.size = Marshal.SizeOf(tme); + tme.hWnd = msg.hwnd; + tme.dwFlags = TMEFlags.TME_LEAVE | TMEFlags.TME_HOVER; + Win32TrackMouseEvent(ref tme); + return result; + } + break; + } + + case Msg.WM_NCMOUSEMOVE: { + if (wm_nc_registered == null || !wm_nc_registered.Contains (msg.hwnd)) + break; + + mouse_state = Widget.FromParamToMouseButtons ((int)msg.lParam.ToInt32 ()); + + TRACKMOUSEEVENT tme; + + tme = new TRACKMOUSEEVENT (); + tme.size = Marshal.SizeOf(tme); + tme.hWnd = msg.hwnd; + tme.dwFlags = (TMEFlags)wm_nc_registered[msg.hwnd]; + Win32TrackMouseEvent (ref tme); + return result; + } + + case Msg.WM_DROPFILES: { + return Win32DnD.HandleWMDropFiles(ref msg); + } + + case Msg.WM_MOUSELEAVE: { + prev_mouse_hwnd = IntPtr.Zero; + break; + } + + case Msg.WM_TIMER: { + Timer timer=(Timer)timer_list[(int)msg.wParam]; + + if (timer != null) { + timer.FireTick(); + } + break; + } + } + + return result; + } + + internal override bool TranslateMessage(ref MSG msg) { + return Win32TranslateMessage(ref msg); + } + + internal override IntPtr DispatchMessage(ref MSG msg) { + return Win32DispatchMessage(ref msg); + } + + internal override bool SetZOrder(IntPtr hWnd, IntPtr AfterhWnd, bool Top, bool Bottom) { + if (Top) { + Win32SetWindowPos(hWnd, SetWindowPosZOrder.HWND_TOP, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE); + return true; + } else if (!Bottom) { + Win32SetWindowPos(hWnd, AfterhWnd, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE); + } else { + Win32SetWindowPos(hWnd, (IntPtr)SetWindowPosZOrder.HWND_BOTTOM, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE); + return true; + } + return false; + } + + internal override bool SetTopmost(IntPtr hWnd, bool Enabled) { + if (Enabled) { + Win32SetWindowPos(hWnd, SetWindowPosZOrder.HWND_TOPMOST, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE); + return true; + } else { + Win32SetWindowPos(hWnd, SetWindowPosZOrder.HWND_NOTOPMOST, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE); + return true; + } + } + + internal override bool SetOwner(IntPtr hWnd, IntPtr hWndOwner) { + Win32SetWindowLong(hWnd, WindowLong.GWL_HWNDPARENT, (uint) hWndOwner); + return true; + } + + internal override bool Text(IntPtr handle, string text) { + Win32SetWindowText(handle, text); + return true; + } + + internal override bool GetText(IntPtr handle, out string text) { + StringBuilder sb; + + sb = new StringBuilder(256); + Win32GetWindowText(handle, sb, sb.Capacity); + text = sb.ToString(); + return true; + } + + internal override bool SetVisible (IntPtr handle, bool visible, bool activate) + { + if (visible) { + Widget c = Widget.FromHandle (handle); + if (c is Form) { + Form f; + + f = (Form)Widget.FromHandle (handle); + WindowPlacementFlags flags = WindowPlacementFlags.SW_SHOWNORMAL; + switch (f.WindowState) { + case FormWindowState.Normal: flags = WindowPlacementFlags.SW_SHOWNORMAL; break; + case FormWindowState.Minimized: flags = WindowPlacementFlags.SW_MINIMIZE; break; + case FormWindowState.Maximized: flags = WindowPlacementFlags.SW_MAXIMIZE; break; + } + + if (!f.ActivateOnShow) + flags = WindowPlacementFlags.SW_SHOWNOACTIVATE; + + Win32ShowWindow (handle, flags); + } + else { + if (c.ActivateOnShow) + Win32ShowWindow (handle, WindowPlacementFlags.SW_SHOWNORMAL); + else + Win32ShowWindow (handle, WindowPlacementFlags.SW_SHOWNOACTIVATE); + } + } + else { + Win32ShowWindow (handle, WindowPlacementFlags.SW_HIDE); + } + return true; + } + + internal override bool IsEnabled(IntPtr handle) { + return IsWindowEnabled (handle); + } + + internal override bool IsKeyLocked (VirtualKeys key) + { + return (Win32GetKeyState (key) & 1) == 1; + } + + internal override bool IsVisible(IntPtr handle) { + return IsWindowVisible (handle); + } + + internal override IntPtr SetParent(IntPtr handle, IntPtr parent) { + Widget c = Widget.FromHandle (handle); + if (parent == IntPtr.Zero) { + if (!(c is Form)) { + Win32ShowWindow(handle, WindowPlacementFlags.SW_HIDE); + } + } else { + if (!(c is Form)) { + SetVisible (handle, c.is_visible, true); + } + } + // The Win32SetParent is lame, it can very well move the window + // ref: http://groups.google.com/group/microsoft.public.vb.winapi/browse_thread/thread/1b82ccc54231ecee/afa82835bfc0422a%23afa82835bfc0422a + // Here we save the position before changing the parent, and if it has changed afterwards restore it. + // Another possibility would be to intercept WM_WINDOWPOSCHANGING and restore the coords there, but this would require plumbing in weird places + // (either inside Widget or add handling to InternalWndProc) + // We also need to remove WS_CHILD if making the window parent-less, and add it if we're parenting it. + RECT rect, rect2; + IntPtr result; + WindowStyles style, new_style; + + Win32GetWindowRect (handle, out rect); + style = (WindowStyles) Win32GetWindowLong (handle, WindowLong.GWL_STYLE); + + if (parent == IntPtr.Zero) { + new_style = style & ~WindowStyles.WS_CHILD; + result = Win32SetParent (handle, GetFosterParent()); + } else { + new_style = style | WindowStyles.WS_CHILD; + result = Win32SetParent (handle, parent); + } + if (style != new_style && c is Form) { + Win32SetWindowLong (handle, WindowLong.GWL_STYLE, (uint) new_style); + } + Win32GetWindowRect (handle, out rect2); + if (rect.top != rect2.top && rect.left != rect2.left && c is Form) { + Win32SetWindowPos (handle, IntPtr.Zero, rect.top, rect.left, rect.Width, rect.Height, SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOREDRAW | SetWindowPosFlags.SWP_NOOWNERZORDER | SetWindowPosFlags.SWP_NOENDSCHANGING | SetWindowPosFlags.SWP_NOACTIVATE); + } + return result; + } + + // If we ever start using this, we should probably replace FosterParent with IntPtr.Zero + internal override IntPtr GetParent(IntPtr handle) { + return Win32GetParent(handle); + } + + // This is a nop on win32 and x11 + internal override IntPtr GetPreviousWindow(IntPtr handle) { + return handle; + } + + internal override void GrabWindow(IntPtr hWnd, IntPtr ConfineToHwnd) { + grab_hwnd = hWnd; + Win32SetCapture(hWnd); + + if (ConfineToHwnd != IntPtr.Zero) { + RECT window_rect; + Win32GetWindowRect (ConfineToHwnd, out window_rect); + Win32GetClipCursor (out clipped_cursor_rect); + Win32ClipCursor (ref window_rect); + } + } + + internal override void GrabInfo(out IntPtr hWnd, out bool GrabConfined, out Rectangle GrabArea) { + hWnd = grab_hwnd; + GrabConfined = grab_confined; + GrabArea = grab_area; + } + + internal override void UngrabWindow(IntPtr hWnd) { + if (!(clipped_cursor_rect.top == 0 && clipped_cursor_rect.bottom == 0 && clipped_cursor_rect.left == 0 && clipped_cursor_rect.right == 0)) { + Win32ClipCursor (ref clipped_cursor_rect); + clipped_cursor_rect = new RECT (); + } + + Win32ReleaseCapture(); + grab_hwnd = IntPtr.Zero; + } + + internal override bool CalculateWindowRect(ref Rectangle ClientRect, CreateParams cp, Menu menu, out Rectangle WindowRect) { + RECT rect; + + rect.left=ClientRect.Left; + rect.top=ClientRect.Top; + rect.right=ClientRect.Right; + rect.bottom=ClientRect.Bottom; + + if (!Win32AdjustWindowRectEx(ref rect, cp.Style, menu != null, cp.ExStyle)) { + WindowRect = new Rectangle(ClientRect.Left, ClientRect.Top, ClientRect.Width, ClientRect.Height); + return false; + } + + WindowRect = new Rectangle(rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top); + return true; + } + + internal override void SetCursor(IntPtr window, IntPtr cursor) { + Win32SetCursor(cursor); + return; + } + + internal override void ShowCursor(bool show) { + Win32ShowCursor(show); + } + + internal override void OverrideCursor(IntPtr cursor) { + Win32SetCursor(cursor); + } + + internal override IntPtr DefineCursor(Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) { + IntPtr cursor; + Bitmap cursor_bitmap; + Bitmap cursor_mask; + Byte[] cursor_bits; + Byte[] mask_bits; + Color pixel; + int width; + int height; + + // Win32 only allows creation cursors of a certain size + if ((bitmap.Width != Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR)) || (bitmap.Width != Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR))) { + cursor_bitmap = new Bitmap(bitmap, new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR), Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR))); + cursor_mask = new Bitmap(mask, new Size(Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR), Win32GetSystemMetrics(SystemMetrics.SM_CXCURSOR))); + } else { + cursor_bitmap = bitmap; + cursor_mask = mask; + } + + width = cursor_bitmap.Width; + height = cursor_bitmap.Height; + + cursor_bits = new Byte[(width / 8) * height]; + mask_bits = new Byte[(width / 8) * height]; + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + pixel = cursor_bitmap.GetPixel(x, y); + + if (pixel == cursor_pixel) { + cursor_bits[y * width / 8 + x / 8] |= (byte)(0x80 >> (x % 8)); + } + + pixel = cursor_mask.GetPixel(x, y); + + if (pixel == mask_pixel) { + mask_bits[y * width / 8 + x / 8] |= (byte)(0x80 >> (x % 8)); + } + } + } + + cursor = Win32CreateCursor(IntPtr.Zero, xHotSpot, yHotSpot, width, height, mask_bits, cursor_bits); + + return cursor; + } + + internal override Bitmap DefineStdCursorBitmap (StdCursor id) + { + // We load the cursor, create a bitmap, draw the cursor onto the bitmap and return the bitmap. + IntPtr cursor = DefineStdCursor (id); + // Windows only have one possible cursor size! + int width = Win32GetSystemMetrics (SystemMetrics.SM_CXCURSOR); + int height = Win32GetSystemMetrics (SystemMetrics.SM_CYCURSOR); + Bitmap bmp = new Bitmap (width, height); + Graphics gc = Graphics.FromImage (bmp); + IntPtr hdc = gc.GetHdc (); + Win32DrawIcon (hdc, 0, 0, cursor); + gc.ReleaseHdc (hdc); + gc.Dispose (); + return bmp; + } + + [MonoTODO("Define the missing cursors")] + internal override IntPtr DefineStdCursor(StdCursor id) { + switch(id) { + case StdCursor.AppStarting: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_APPSTARTING); + case StdCursor.Arrow: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); + case StdCursor.Cross: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_CROSS); + case StdCursor.Default: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); + case StdCursor.Hand: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_HAND); + case StdCursor.Help: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_HELP); + case StdCursor.HSplit: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.IBeam: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_IBEAM); + case StdCursor.No: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_NO); + case StdCursor.NoMove2D: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.NoMoveHoriz: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.NoMoveVert: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.PanEast: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.PanNE: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.PanNorth: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.PanNW: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.PanSE: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.PanSouth: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.PanSW: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.PanWest: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.SizeAll: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZEALL); + case StdCursor.SizeNESW: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZENESW); + case StdCursor.SizeNS: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZENS); + case StdCursor.SizeNWSE: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZENWSE); + case StdCursor.SizeWE: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_SIZEWE); + case StdCursor.UpArrow: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_UPARROW); + case StdCursor.VSplit: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_ARROW); // FIXME + case StdCursor.WaitCursor: return Win32LoadCursor(IntPtr.Zero, LoadCursorType.IDC_WAIT); + } + throw new NotImplementedException (); + } + + internal override void DestroyCursor(IntPtr cursor) { + if ((cursor.ToInt32() < (int)LoadCursorType.First) || (cursor.ToInt32() > (int)LoadCursorType.Last)) { + Win32DestroyCursor(cursor); + } + } + + [MonoTODO] + internal override void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y) { + ICONINFO ii = new ICONINFO (); + + if (!Win32GetIconInfo (cursor, out ii)) + throw new Win32Exception (); + + width = 20; + height = 20; + hotspot_x = ii.xHotspot; + hotspot_y = ii.yHotspot; + } + + internal override void SetCursorPos(IntPtr handle, int x, int y) { + Win32SetCursorPos(x, y); + } + + internal override Region GetClipRegion(IntPtr hwnd) { + Region region; + + region = new Region(); + + Win32GetWindowRgn(hwnd, region.GetHrgn(Graphics.FromHwnd(hwnd))); + + return region; + } + + internal override void SetClipRegion(IntPtr hwnd, Region region) { + if (region == null) + Win32SetWindowRgn (hwnd, IntPtr.Zero, true); + else + Win32SetWindowRgn(hwnd, region.GetHrgn(Graphics.FromHwnd(hwnd)), true); + } + + internal override void EnableWindow(IntPtr handle, bool Enable) { + Win32EnableWindow(handle, Enable); + } + + internal override void EndLoop(System.Threading.Thread thread) { + // Nothing to do + } + + internal override object StartLoop(System.Threading.Thread thread) { + return null; + } + + internal override void SetModal(IntPtr handle, bool Modal) { + // we do nothing on Win32 + } + + internal override void GetCursorPos(IntPtr handle, out int x, out int y) { + POINT pt; + + Win32GetCursorPos(out pt); + + if (handle!=IntPtr.Zero) { + Win32ScreenToClient(handle, ref pt); + } + + x=pt.x; + y=pt.y; + } + + internal override void ScreenToClient(IntPtr handle, ref int x, ref int y) + { + POINT pnt = new POINT(); + + pnt.x = x; + pnt.y = y; + Win32ScreenToClient (handle, ref pnt); + + x = pnt.x; + y = pnt.y; + } + + internal override void ClientToScreen(IntPtr handle, ref int x, ref int y) { + POINT pnt = new POINT(); + + pnt.x = x; + pnt.y = y; + + Win32ClientToScreen(handle, ref pnt); + + x = pnt.x; + y = pnt.y; + } + + internal override void ScreenToMenu(IntPtr handle, ref int x, ref int y) { + RECT rect; + + Win32GetWindowRect(handle, out rect); + x -= rect.left + SystemInformation.FrameBorderSize.Width; + y -= rect.top + SystemInformation.FrameBorderSize.Height; + + WindowStyles style = (WindowStyles) Win32GetWindowLong (handle, WindowLong.GWL_STYLE); + if (CreateParams.IsSet (style, WindowStyles.WS_CAPTION)) { + y -= ThemeEngine.Current.CaptionHeight; + } + } + + internal override void MenuToScreen(IntPtr handle, ref int x, ref int y) { + RECT rect; + + Win32GetWindowRect(handle, out rect); + x += rect.left + SystemInformation.FrameBorderSize.Width; + y += rect.top + SystemInformation.FrameBorderSize.Height + ThemeEngine.Current.CaptionHeight; + return; + } + + internal override void SendAsyncMethod (AsyncMethodData method) + { + Win32PostMessage(GetFosterParent(), Msg.WM_ASYNC_MESSAGE, IntPtr.Zero, (IntPtr)GCHandle.Alloc (method)); + } + + internal override void SetTimer (Timer timer) + { + IntPtr FosterParent=GetFosterParent(); + int index; + + index = timer.GetHashCode(); + + lock (timer_list) { + timer_list[index]=timer; + } + + if (Win32SetTimer(FosterParent, index, (uint)timer.Interval, IntPtr.Zero) != IntPtr.Zero) + timer.window = FosterParent; + else + timer.window = IntPtr.Zero; + } + + internal override void KillTimer (Timer timer) + { + int index; + + index = timer.GetHashCode(); + + Win32KillTimer(timer.window, index); + + lock (timer_list) { + timer_list.Remove(index); + } + } + + internal override void CreateCaret(IntPtr hwnd, int width, int height) { + Win32CreateCaret(hwnd, IntPtr.Zero, width, height); + caret_visible = false; + } + + internal override void DestroyCaret(IntPtr hwnd) { + Win32DestroyCaret(); + } + + internal override void SetCaretPos(IntPtr hwnd, int x, int y) { + Win32SetCaretPos(x, y); + } + + internal override void CaretVisible(IntPtr hwnd, bool visible) { + if (visible) { + if (!caret_visible) { + Win32ShowCaret(hwnd); + caret_visible = true; + } + } else { + if (caret_visible) { + Win32HideCaret(hwnd); + caret_visible = false; + } + } + } + + internal override IntPtr GetFocus() { + return Win32GetFocus(); + } + + internal override void SetFocus(IntPtr hwnd) { + Win32SetFocus(hwnd); + } + + internal override IntPtr GetActive() { + return Win32GetActiveWindow(); + } + + internal override bool GetFontMetrics(Graphics g, Font font, out int ascent, out int descent) { + IntPtr dc; + IntPtr prevobj; + TEXTMETRIC tm; + + tm = new TEXTMETRIC(); + + dc = Win32GetDC (IntPtr.Zero); + prevobj = Win32SelectObject (dc, font.ToHfont ()); + + if (Win32GetTextMetrics (dc, ref tm) == false) { + prevobj = Win32SelectObject (dc, prevobj); + Win32DeleteObject (prevobj); + Win32ReleaseDC (IntPtr.Zero, dc); + ascent = 0; + descent = 0; + return false; + } + prevobj = Win32SelectObject (dc, prevobj); + Win32DeleteObject (prevobj); + Win32ReleaseDC (IntPtr.Zero, dc); + + ascent = tm.tmAscent; + descent = tm.tmDescent; + + return true; + } + + internal override void ScrollWindow(IntPtr hwnd, Rectangle rectangle, int XAmount, int YAmount, bool with_children) { + RECT rect; + + rect = new RECT(); + rect.left = rectangle.X; + rect.top = rectangle.Y; + rect.right = rectangle.Right; + rect.bottom = rectangle.Bottom; + + Win32ScrollWindowEx(hwnd, XAmount, YAmount, IntPtr.Zero, ref rect, IntPtr.Zero, IntPtr.Zero, ScrollWindowExFlags.SW_INVALIDATE | ScrollWindowExFlags.SW_ERASE | (with_children ? ScrollWindowExFlags.SW_SCROLLCHILDREN : ScrollWindowExFlags.SW_NONE)); + Win32UpdateWindow(hwnd); + } + + internal override void ScrollWindow(IntPtr hwnd, int XAmount, int YAmount, bool with_children) { + Win32ScrollWindowEx(hwnd, XAmount, YAmount, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ScrollWindowExFlags.SW_INVALIDATE | ScrollWindowExFlags.SW_ERASE | (with_children ? ScrollWindowExFlags.SW_SCROLLCHILDREN : ScrollWindowExFlags.SW_NONE)); + } + + internal override bool SystrayAdd(IntPtr hwnd, string tip, Icon icon, out ToolTip tt) { + NOTIFYICONDATA nid; + + nid = new NOTIFYICONDATA(); + + nid.cbSize = (uint)Marshal.SizeOf(nid); + nid.hWnd = hwnd; + nid.uID = 1; + nid.uCallbackMessage = (uint)Msg.WM_USER; + nid.uFlags = NotifyIconFlags.NIF_MESSAGE; + + if (tip != null) { + nid.szTip = tip; + nid.uFlags |= NotifyIconFlags.NIF_TIP; + } + + if (icon != null) { + nid.hIcon = icon.Handle; + nid.uFlags |= NotifyIconFlags.NIF_ICON; + } + + tt = null; + + return Win32Shell_NotifyIcon(NotifyIconMessage.NIM_ADD, ref nid); + } + + internal override bool SystrayChange(IntPtr hwnd, string tip, Icon icon, ref ToolTip tt) { + NOTIFYICONDATA nid; + + nid = new NOTIFYICONDATA(); + + nid.cbSize = (uint)Marshal.SizeOf(nid); + nid.hIcon = icon.Handle; + nid.hWnd = hwnd; + nid.uID = 1; + nid.uCallbackMessage = (uint)Msg.WM_USER; + nid.uFlags = NotifyIconFlags.NIF_MESSAGE; + + if (tip != null) { + nid.szTip = tip; + nid.uFlags |= NotifyIconFlags.NIF_TIP; + } + + if (icon != null) { + nid.hIcon = icon.Handle; + nid.uFlags |= NotifyIconFlags.NIF_ICON; + } + + return Win32Shell_NotifyIcon(NotifyIconMessage.NIM_MODIFY, ref nid); + } + + internal override void SystrayRemove(IntPtr hwnd, ref ToolTip tt) { + NOTIFYICONDATA nid; + + nid = new NOTIFYICONDATA(); + + nid.cbSize = (uint)Marshal.SizeOf(nid); + nid.hWnd = hwnd; + nid.uID = 1; + nid.uFlags = 0; + + Win32Shell_NotifyIcon(NotifyIconMessage.NIM_DELETE, ref nid); + } + + internal override void SystrayBalloon(IntPtr hwnd, int timeout, string title, string text, ToolTipIcon icon) + { + NOTIFYICONDATA nid; + + nid = new NOTIFYICONDATA(); + + nid.cbSize = (uint)Marshal.SizeOf(nid); + nid.hWnd = hwnd; + nid.uID = 1; + nid.uFlags = NotifyIconFlags.NIF_INFO; + nid.uTimeoutOrVersion = timeout; + nid.szInfoTitle = title; + nid.szInfo = text; + nid.dwInfoFlags = icon; + + Win32Shell_NotifyIcon(NotifyIconMessage.NIM_MODIFY, ref nid); + } + + internal override void SetBorderStyle(IntPtr handle, FormBorderStyle border_style) { + // Nothing to do on Win32 + } + + internal override void SetMenu(IntPtr handle, Menu menu) { + // Trigger WM_NCCALC + Win32SetWindowPos(handle, IntPtr.Zero, 0, 0, 0, 0, SetWindowPosFlags.SWP_FRAMECHANGED | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE); + } + + internal override Point GetMenuOrigin(IntPtr handle) { + Form form = Widget.FromHandle (handle) as Form; + + if (form != null) { + if (form.FormBorderStyle == FormBorderStyle.None) + return Point.Empty; + + int bordersize = (form.Width - form.ClientSize.Width) / 2; + + if (form.FormBorderStyle == FormBorderStyle.FixedToolWindow || form.FormBorderStyle == FormBorderStyle.SizableToolWindow) + return new Point (bordersize, bordersize + SystemInformation.ToolWindowCaptionHeight); + else + return new Point (bordersize, bordersize + SystemInformation.CaptionHeight); + } + + return new Point(SystemInformation.FrameBorderSize.Width, SystemInformation.FrameBorderSize.Height + ThemeEngine.Current.CaptionHeight); + } + + internal override void SetIcon(IntPtr hwnd, Icon icon) { + Win32SendMessage(hwnd, Msg.WM_SETICON, (IntPtr)1, icon == null ? IntPtr.Zero : icon.Handle); // 1 = large icon (0 would be small) + } + + internal override void ClipboardClose(IntPtr handle) { + if (handle != clip_magic) { + throw new ArgumentException("handle is not a valid clipboard handle"); + } + Win32CloseClipboard(); + } + + internal override int ClipboardGetID(IntPtr handle, string format) { + if (handle != clip_magic) { + throw new ArgumentException("handle is not a valid clipboard handle"); + } + if (format == "Text" ) return 1; + else if (format == "Bitmap" ) return 2; + else if (format == "MetaFilePict" ) return 3; + else if (format == "SymbolicLink" ) return 4; + else if (format == "DataInterchangeFormat" ) return 5; + else if (format == "Tiff" ) return 6; + else if (format == "OEMText" ) return 7; + else if (format == "DeviceIndependentBitmap" ) return 8; + else if (format == "Palette" ) return 9; + else if (format == "PenData" ) return 10; + else if (format == "RiffAudio" ) return 11; + else if (format == "WaveAudio" ) return 12; + else if (format == "UnicodeText" ) return 13; + else if (format == "EnhancedMetafile" ) return 14; + else if (format == "FileDrop" ) return 15; + else if (format == "Locale" ) return 16; + + return (int)Win32RegisterClipboardFormat(format); + } + + internal override IntPtr ClipboardOpen(bool primary_selection) { + // Win32 does not have primary selection + Win32OpenClipboard(GetFosterParent()); + return clip_magic; + } + + internal override int[] ClipboardAvailableFormats(IntPtr handle) { + uint format; + int[] result; + int count; + + if (handle != clip_magic) { + return null; + } + + // Count first + count = 0; + format = 0; + do { + format = Win32EnumClipboardFormats(format); + if (format != 0) { + count++; + } + } while (format != 0); + + // Now assign + result = new int[count]; + count = 0; + format = 0; + do { + format = Win32EnumClipboardFormats(format); + if (format != 0) { + result[count++] = (int)format; + } + } while (format != 0); + + return result; + } + + + internal override object ClipboardRetrieve(IntPtr handle, int type, XplatUI.ClipboardToObject converter) { + IntPtr hmem; + IntPtr data; + object obj; + + if (handle != clip_magic) { + throw new ArgumentException("handle is not a valid clipboard handle"); + } + + hmem = Win32GetClipboardData((uint)type); + if (hmem == IntPtr.Zero) { + return null; + } + + data = Win32GlobalLock(hmem); + if (data == IntPtr.Zero) { + uint error = Win32GetLastError(); + Console.WriteLine("Error: {0}", error); + return null; + } + + obj = null; + + if (type == DataFormats.GetFormat(DataFormats.Rtf).Id) { + obj = AnsiToString(data); + } else switch ((ClipboardFormats)type) { + case ClipboardFormats.CF_TEXT: { + obj = AnsiToString(data); + break; + } + + case ClipboardFormats.CF_DIB: { + obj = DIBtoImage(data); + break; + } + + case ClipboardFormats.CF_UNICODETEXT: { + obj = UnicodeToString(data); + break; + } + + default: { + if (converter != null && !converter(type, data, out obj)) { + obj = null; + } + break; + } + } + Win32GlobalUnlock(hmem); + + return obj; + + } + + internal override void ClipboardStore(IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter, bool copy) + { + byte[] data = null; + + if (handle != clip_magic) { + throw new ArgumentException("handle is not a valid clipboard handle"); + } + + if (obj == null) { + // Just clear it + if (!Win32EmptyClipboard()) + throw new ExternalException("Win32EmptyClipboard"); + return; + } + + if (type == -1) { + if (obj is string) { + type = (int)ClipboardFormats.CF_UNICODETEXT; + } else if (obj is Image) { + type = (int)ClipboardFormats.CF_DIB; + } + } + + if (type == DataFormats.GetFormat(DataFormats.Rtf).Id) { + data = StringToAnsi ((string)obj); + } else switch((ClipboardFormats)type) { + case ClipboardFormats.CF_UNICODETEXT: { + data = StringToUnicode ((string)obj); + break; + } + + case ClipboardFormats.CF_TEXT: { + data = StringToAnsi ((string)obj); + break; + } + + case ClipboardFormats.CF_BITMAP: + case ClipboardFormats.CF_DIB: { + data = ImageToDIB ((Image)obj); + type = (int)ClipboardFormats.CF_DIB; + break; + } + + default: { + if (converter != null && !converter(ref type, obj, out data)) { + data = null; // ensure that a failed conversion leaves null. + } + break; + } + } + if (data != null) { + SetClipboardData ((uint)type, data); + } + } + + internal static byte[] StringToUnicode (string text) + { + return Encoding.Unicode.GetBytes (text + "\0"); + } + + internal static byte[] StringToAnsi (string text) + { + // FIXME, follow the behaviour of the previous code using UTF-8, + // but this should be 'ANSI' on Windows, i.e. the current code page. + // Does Encoding.Default work on Windows? + return Encoding.UTF8.GetBytes (text + "\0"); + } + + private void SetClipboardData (uint type, byte[] data) + { + if (data.Length == 0) + // Shouldn't call Win32SetClipboard with NULL, as, from MSDN: + // "This parameter can be NULL, indicating that the window provides data + // in the specified clipboard format (renders the format) upon request." + // and I don't think we support that... + // Note this is unrelated to the fact that passing a null obj to + // ClipboardStore is actually a request to empty the clipboard! + return; + IntPtr hmem = CopyToMoveableMemory (data); + if (hmem == IntPtr.Zero) + // As above, should not call with null. + // (Not that CopyToMoveableMemory should ever return null!) + throw new ExternalException ("CopyToMoveableMemory failed."); + if (Win32SetClipboardData (type, hmem) == IntPtr.Zero) + throw new ExternalException ("Win32SetClipboardData"); + } + + /// + /// Creates a memory block with GlobalAlloc(GMEM_MOVEABLE), copies the data + /// into it, and returns the handle to the memory. + /// + /// - + /// The data. Must not be null or zero-length — + /// see the exception notes. + /// - + /// The *handle* to the allocated GMEM_MOVEABLE block. + /// - + /// The data was null or zero + /// length. This is disallowed since a zero length allocation can't be made + /// + /// The allocation, + /// or locking (handle->pointer) failed. + /// Either out of memory or the handle table is full (256 max currently). + /// Note Win32Exception is a subclass of ExternalException so this is OK in + /// the documented Clipboard interface. + /// + internal static IntPtr CopyToMoveableMemory (byte[] data) + { + if (data == null || data.Length == 0) + // detect this before GlobalAlloc does. + throw new ArgumentException ("Can't create a zero length memory block."); + + IntPtr hmem = Win32GlobalAlloc (GAllocFlags.GMEM_MOVEABLE | GAllocFlags.GMEM_DDESHARE, data.Length); + if (hmem == IntPtr.Zero) + throw new Win32Exception (); + IntPtr hmem_ptr = Win32GlobalLock (hmem); + if (hmem_ptr == IntPtr.Zero) // If the allocation was valid this shouldn't occur. + throw new Win32Exception (); + Marshal.Copy (data, 0, hmem_ptr, data.Length); + Win32GlobalUnlock (hmem); + return hmem; + } + + + internal override void SetAllowDrop(IntPtr hwnd, bool allowed) { + if (allowed) { + Win32DnD.RegisterDropTarget(hwnd); + } else { + Win32DnD.UnregisterDropTarget(hwnd); + } + } + + internal override DragDropEffects StartDrag(IntPtr hwnd, object data, DragDropEffects allowedEffects) { + return Win32DnD.StartDrag(hwnd, data, allowedEffects); + } + + // XXX this doesn't work at all for FrameStyle.Dashed - it draws like Thick, and in the Thick case + // the corners are drawn incorrectly. + internal override void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style) { + IntPtr hdc; + IntPtr pen; + IntPtr oldpen; + COLORREF clrRef = new COLORREF(); + + // If we want the standard hatch pattern we would + // need to create a brush + + clrRef.R = backColor.R; + clrRef.G = backColor.G; + clrRef.B = backColor.B; + + // Grab a pen + pen = Win32CreatePen (style == FrameStyle.Thick ? PenStyle.PS_SOLID : PenStyle.PS_DASH, + style == FrameStyle.Thick ? 4 : 2, ref clrRef); + + hdc = Win32GetDC(IntPtr.Zero); + Win32SetROP2(hdc, ROP2DrawMode.R2_NOT); + oldpen = Win32SelectObject(hdc, pen); + + Win32MoveToEx(hdc, rectangle.Left, rectangle.Top, IntPtr.Zero); + if ((rectangle.Width > 0) && (rectangle.Height > 0)) { + Win32LineTo(hdc, rectangle.Right, rectangle.Top); + Win32LineTo(hdc, rectangle.Right, rectangle.Bottom); + Win32LineTo(hdc, rectangle.Left, rectangle.Bottom); + Win32LineTo(hdc, rectangle.Left, rectangle.Top); + } else { + if (rectangle.Width > 0) { + Win32LineTo(hdc, rectangle.Right, rectangle.Top); + } else { + Win32LineTo(hdc, rectangle.Left, rectangle.Bottom); + } + } + + Win32SelectObject(hdc, oldpen); + Win32DeleteObject(pen); + + Win32ReleaseDC(IntPtr.Zero, hdc); + } + + internal override void DrawReversibleLine(Point start, Point end, Color backColor) { + IntPtr hdc; + IntPtr pen; + IntPtr oldpen; + POINT pt; + COLORREF clrRef = new COLORREF(); + + pt = new POINT(); + pt.x = 0; + pt.y = 0; + Win32ClientToScreen(IntPtr.Zero, ref pt); + + // If we want the standard hatch pattern we would + // need to create a brush + + clrRef.R = backColor.R; + clrRef.G = backColor.G; + clrRef.B = backColor.B; + + // Grab a pen + pen = Win32CreatePen(PenStyle.PS_SOLID, 1, ref clrRef); + + hdc = Win32GetDC(IntPtr.Zero); + Win32SetROP2(hdc, ROP2DrawMode.R2_NOT); + oldpen = Win32SelectObject(hdc, pen); + + Win32MoveToEx(hdc, pt.x + start.X, pt.y + start.Y, IntPtr.Zero); + Win32LineTo(hdc, pt.x + end.X, pt.y + end.Y); + + Win32SelectObject(hdc, oldpen); + Win32DeleteObject(pen); + + Win32ReleaseDC(IntPtr.Zero, hdc); + } + + internal override void FillReversibleRectangle (Rectangle rectangle, Color backColor) + { + RECT rect; + + rect = new RECT(); + rect.left = rectangle.Left; + rect.top = rectangle.Top; + rect.right = rectangle.Right; + rect.bottom = rectangle.Bottom; + + IntPtr hdc; + IntPtr brush; + IntPtr oldbrush; + COLORREF clrRef = new COLORREF(); + + clrRef.R = backColor.R; + clrRef.G = backColor.G; + clrRef.B = backColor.B; + + // Grab a brush + brush = Win32CreateSolidBrush (clrRef); + + hdc = Win32GetDC(IntPtr.Zero); + oldbrush = Win32SelectObject(hdc, brush); + + Win32PatBlt (hdc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height, PatBltRop.DSTINVERT); + + Win32SelectObject(hdc, oldbrush); + Win32DeleteObject(brush); + + Win32ReleaseDC(IntPtr.Zero, hdc); + } + + internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width) { + IntPtr hdc; + IntPtr pen; + IntPtr oldpen; + POINT pt; + + pt = new POINT(); + pt.x = 0; + pt.y = 0; + Win32ClientToScreen(handle, ref pt); + + // If we want the standard hatch pattern we would + // need to create a brush + + // Grab a pen + pen = Win32CreatePen(PenStyle.PS_SOLID, line_width, IntPtr.Zero); + + hdc = Win32GetDC(IntPtr.Zero); + Win32SetROP2(hdc, ROP2DrawMode.R2_NOT); + oldpen = Win32SelectObject(hdc, pen); + + Widget c = Widget.FromHandle (handle); + if (c != null) { + RECT window_rect; + Win32GetWindowRect (c.Handle, out window_rect); + Region r = new Region (new Rectangle(window_rect.left, window_rect.top, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top)); + Win32ExtSelectClipRgn(hdc, r.GetHrgn (Graphics.FromHdc (hdc)), (int) ClipCombineMode.RGN_AND); + } + + Win32MoveToEx(hdc, pt.x + rect.Left, pt.y + rect.Top, IntPtr.Zero); + if ((rect.Width > 0) && (rect.Height > 0)) { + Win32LineTo(hdc, pt.x + rect.Right, pt.y + rect.Top); + Win32LineTo(hdc, pt.x + rect.Right, pt.y + rect.Bottom); + Win32LineTo(hdc, pt.x + rect.Left, pt.y + rect.Bottom); + Win32LineTo(hdc, pt.x + rect.Left, pt.y + rect.Top); + } else { + if (rect.Width > 0) { + Win32LineTo(hdc, pt.x + rect.Right, pt.y + rect.Top); + } else { + Win32LineTo(hdc, pt.x + rect.Left, pt.y + rect.Bottom); + } + } + + Win32SelectObject(hdc, oldpen); + Win32DeleteObject(pen); + if (c != null) + Win32ExtSelectClipRgn(hdc, IntPtr.Zero, (int) ClipCombineMode.RGN_COPY); + + Win32ReleaseDC(IntPtr.Zero, hdc); + } + + internal override SizeF GetAutoScaleSize(Font font) { + Graphics g; + float width; + string magic_string = "The quick brown fox jumped over the lazy dog."; + double magic_number = 44.549996948242189; + + g = Graphics.FromHwnd(GetFosterParent()); + + width = (float) (g.MeasureString (magic_string, font).Width / magic_number); + return new SizeF(width, font.Height); + } + + internal override IntPtr SendMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam) { + return Win32SendMessage(hwnd, message, wParam, lParam); + } + + internal override bool PostMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam) { + return Win32PostMessage(hwnd, message, wParam, lParam); + } + + internal override int SendInput (IntPtr hwnd, Queue keys) { + INPUT[] inputs = new INPUT[keys.Count]; + const Int32 INPUT_KEYBOARD = 1; + uint returns = 0; + int i = 0; + while (keys.Count > 0) { + MSG msg = (MSG)keys.Dequeue(); + + + inputs[i].ki.wScan = 0; + inputs[i].ki.time = 0; + inputs[i].ki.dwFlags = (Int32)(msg.message == Msg.WM_KEYUP ? InputFlags.KEYEVENTF_KEYUP : 0); + inputs[i].ki.wVk = (short)msg.wParam.ToInt32(); + inputs[i].type = INPUT_KEYBOARD; + i++; + } + returns = Win32SendInput((UInt32)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT))); + + return (int) returns; + } + + internal override int KeyboardSpeed { + get { + int speed = 0; + Win32SystemParametersInfo(SPIAction.SPI_GETKEYBOARDSPEED, 0, ref speed, 0); + // + // Return values range from 0 to 31 which map to 2.5 to 30 repetitions per second. + // + return speed; + } + } + + internal override int KeyboardDelay { + get { + int delay = 1; + Win32SystemParametersInfo(SPIAction.SPI_GETKEYBOARDDELAY, 0, ref delay, 0); + // + // Return values must range from 0 to 4, 0 meaning 250ms, + // and 4 meaning 1000 ms. + // + return delay; + } + } + + private class WinBuffer + { + public IntPtr hdc; + public IntPtr bitmap; + + public WinBuffer (IntPtr hdc, IntPtr bitmap) + { + this.hdc = hdc; + this.bitmap = bitmap; + } + } + + internal override void CreateOffscreenDrawable (IntPtr handle, int width, int height, out object offscreen_drawable) + { + Graphics destG = Graphics.FromHwnd (handle); + IntPtr destHdc = destG.GetHdc (); + + IntPtr srcHdc = Win32CreateCompatibleDC (destHdc); + IntPtr srcBmp = Win32CreateCompatibleBitmap (destHdc, width, height); + Win32SelectObject (srcHdc, srcBmp); + + offscreen_drawable = new WinBuffer (srcHdc, srcBmp); + + destG.ReleaseHdc (destHdc); + } + + internal override Graphics GetOffscreenGraphics (object offscreen_drawable) + { + return Graphics.FromHdc (((WinBuffer)offscreen_drawable).hdc); + } + + internal override void BlitFromOffscreen (IntPtr dest_handle, Graphics dest_dc, object offscreen_drawable, Graphics offscreen_dc, Rectangle r) + { + WinBuffer wb = (WinBuffer)offscreen_drawable; + + IntPtr destHdc = dest_dc.GetHdc (); + Win32BitBlt (destHdc, r.Left, r.Top, r.Width, r.Height, wb.hdc, r.Left, r.Top, TernaryRasterOperations.SRCCOPY); + dest_dc.ReleaseHdc (destHdc); + } + + internal override void DestroyOffscreenDrawable (object offscreen_drawable) + { + WinBuffer wb = (WinBuffer)offscreen_drawable; + + Win32DeleteObject (wb.bitmap); + Win32DeleteDC (wb.hdc); + } + + internal override void SetForegroundWindow (IntPtr handle) + { + Win32SetForegroundWindow(handle); + } + + internal override event EventHandler Idle; + #endregion // Public Static Methods + + #region Win32 Imports + [DllImport ("kernel32.dll", EntryPoint="GetLastError", CallingConvention=CallingConvention.StdCall)] + private extern static uint Win32GetLastError(); + + [DllImport ("user32.dll", EntryPoint="CreateWindowExW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + internal extern static IntPtr Win32CreateWindow(WindowExStyles dwExStyle, string lpClassName, string lpWindowName, WindowStyles dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lParam); + + [DllImport ("user32.dll", EntryPoint="DestroyWindow", CallingConvention=CallingConvention.StdCall)] + internal extern static bool Win32DestroyWindow(IntPtr hWnd); + + [DllImport ("user32.dll", EntryPoint="PeekMessageW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + internal extern static bool Win32PeekMessage(ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags); + + [DllImport ("user32.dll", EntryPoint="GetMessageW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + internal extern static bool Win32GetMessage(ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax); + + [DllImport ("user32.dll", EntryPoint="TranslateMessage", CallingConvention=CallingConvention.StdCall)] + internal extern static bool Win32TranslateMessage(ref MSG msg); + + [DllImport ("user32.dll", EntryPoint="DispatchMessageW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + internal extern static IntPtr Win32DispatchMessage(ref MSG msg); + + [DllImport ("user32.dll", EntryPoint="MoveWindow", CallingConvention=CallingConvention.StdCall)] + internal extern static bool Win32MoveWindow(IntPtr hWnd, int x, int y, int width, int height, bool repaint); + + [DllImport ("user32.dll", EntryPoint="SetWindowPos", CallingConvention=CallingConvention.StdCall)] + internal extern static bool Win32SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SetWindowPosFlags Flags); + + [DllImport ("user32.dll", EntryPoint="SetWindowPos", CallingConvention=CallingConvention.StdCall)] + internal extern static bool Win32SetWindowPos(IntPtr hWnd, SetWindowPosZOrder pos, int x, int y, int cx, int cy, SetWindowPosFlags Flags); + + [DllImport ("user32.dll", EntryPoint="SetWindowTextW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + internal extern static bool Win32SetWindowText(IntPtr hWnd, string lpString); + + [DllImport ("user32.dll", EntryPoint="GetWindowTextW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + internal extern static bool Win32GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); + + [DllImport ("user32.dll", EntryPoint="SetParent", CallingConvention=CallingConvention.StdCall)] + internal extern static IntPtr Win32SetParent(IntPtr hWnd, IntPtr hParent); + + [DllImport ("user32.dll", EntryPoint="RegisterClassW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32RegisterClass(ref WNDCLASS wndClass); + + [DllImport ("user32.dll", EntryPoint="LoadCursorW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32LoadCursor(IntPtr hInstance, LoadCursorType type); + + [DllImport ("user32.dll", EntryPoint="ShowCursor", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32ShowCursor(bool bShow); + + [DllImport ("user32.dll", EntryPoint="SetCursor", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32SetCursor(IntPtr hCursor); + + [DllImport ("user32.dll", EntryPoint="CreateCursor", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32CreateCursor(IntPtr hInstance, int xHotSpot, int yHotSpot, int nWidth, int nHeight, Byte[] pvANDPlane, Byte[] pvORPlane); + + [DllImport ("user32.dll", EntryPoint="DestroyCursor", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32DestroyCursor(IntPtr hCursor); + + [DllImport ("user32.dll", EntryPoint = "DrawIcon", CallingConvention = CallingConvention.StdCall)] + private extern static bool Win32DrawIcon (IntPtr hDC, int X, int Y, IntPtr hIcon); + + [DllImport ("user32.dll", EntryPoint="DefWindowProcW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32DefWindowProc(IntPtr hWnd, Msg Msg, IntPtr wParam, IntPtr lParam); + + //[DllImport ("user32.dll", EntryPoint="DefDlgProcW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + //private extern static IntPtr Win32DefDlgProc(IntPtr hWnd, Msg Msg, IntPtr wParam, IntPtr lParam); + + [DllImport ("user32.dll", EntryPoint="PostQuitMessage", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32PostQuitMessage(int nExitCode); + + [DllImport ("user32.dll", EntryPoint="UpdateWindow", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32UpdateWindow(IntPtr hWnd); + + [DllImport ("user32.dll", EntryPoint="GetUpdateRect", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32GetUpdateRect(IntPtr hWnd, ref RECT rect, bool erase); + + [DllImport ("user32.dll", EntryPoint="BeginPaint", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32BeginPaint(IntPtr hWnd, ref PAINTSTRUCT ps); + + [DllImport ("user32.dll", EntryPoint = "ValidateRect", CallingConvention = CallingConvention.StdCall)] + private extern static IntPtr Win32ValidateRect (IntPtr hWnd, ref RECT rect); + + [DllImport ("user32.dll", EntryPoint="EndPaint", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32EndPaint(IntPtr hWnd, ref PAINTSTRUCT ps); + + [DllImport ("user32.dll", EntryPoint="GetDC", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32GetDC(IntPtr hWnd); + + [DllImport ("user32.dll", EntryPoint="GetWindowDC", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32GetWindowDC(IntPtr hWnd); + + //[DllImport ("user32.dll", EntryPoint="GetDCEx", CallingConvention=CallingConvention.StdCall)] + //private extern static IntPtr Win32GetDCEx(IntPtr hWnd, IntPtr hRgn, DCExFlags flags); + + [DllImport ("user32.dll", EntryPoint="ReleaseDC", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32ReleaseDC(IntPtr hWnd, IntPtr hDC); + + [DllImport ("user32.dll", EntryPoint="MessageBoxW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32MessageBox(IntPtr hParent, string pText, string pCaption, uint uType); + + [DllImport ("user32.dll", EntryPoint="InvalidateRect", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32InvalidateRect(IntPtr hWnd, ref RECT lpRect, bool bErase); + + //[DllImport ("user32.dll", EntryPoint="InvalidateRect", CallingConvention=CallingConvention.StdCall)] + //private extern static IntPtr Win32InvalidateRect(IntPtr hWnd, IntPtr lpRect, bool bErase); + + [DllImport ("user32.dll", EntryPoint="SetCapture", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32SetCapture(IntPtr hWnd); + + [DllImport ("user32.dll", EntryPoint="ReleaseCapture", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32ReleaseCapture(); + + [DllImport ("user32.dll", EntryPoint="GetWindowRect", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32GetWindowRect(IntPtr hWnd, out RECT rect); + + [DllImport ("user32.dll", EntryPoint="GetClientRect", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32GetClientRect(IntPtr hWnd, out RECT rect); + + [DllImport ("user32.dll", EntryPoint="ScreenToClient", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32ScreenToClient(IntPtr hWnd, ref POINT pt); + + [DllImport ("user32.dll", EntryPoint="ClientToScreen", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32ClientToScreen(IntPtr hWnd, ref POINT pt); + + // This function returns the parent OR THE OWNER! + // Use GetAncestor to only get the parent. + [DllImport ("user32.dll", EntryPoint="GetParent", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32GetParent(IntPtr hWnd); + + [DllImport ("user32.dll", EntryPoint = "GetAncestor", CallingConvention = CallingConvention.StdCall)] + private extern static IntPtr Win32GetAncestor (IntPtr hWnd, AncestorType flags); + + [DllImport ("user32.dll", EntryPoint="SetActiveWindow", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32SetActiveWindow(IntPtr hWnd); + + [DllImport ("user32.dll", EntryPoint="AdjustWindowRectEx", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32AdjustWindowRectEx(ref RECT lpRect, int dwStyle, bool bMenu, int dwExStyle); + + [DllImport ("user32.dll", EntryPoint="GetCursorPos", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32GetCursorPos(out POINT lpPoint); + + [DllImport ("user32.dll", EntryPoint="SetCursorPos", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32SetCursorPos(int x, int y); + + //[DllImport ("user32.dll", EntryPoint="GetWindowPlacement", CallingConvention=CallingConvention.StdCall)] + //private extern static bool Win32GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl); + + [DllImport ("user32.dll", EntryPoint="TrackMouseEvent", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32TrackMouseEvent(ref TRACKMOUSEEVENT tme); + + //[DllImport ("gdi32.dll", EntryPoint="CreateBrushIndirect", CallingConvention=CallingConvention.StdCall)] + //private extern static IntPtr Win32CreateBrushIndirect(ref LOGBRUSH lb); + + [DllImport ("gdi32.dll", EntryPoint="CreateSolidBrush", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32CreateSolidBrush(COLORREF clrRef); + + [DllImport ("gdi32.dll", EntryPoint="PatBlt", CallingConvention=CallingConvention.StdCall)] + private extern static int Win32PatBlt(IntPtr hdc, int nXLeft, int nYLeft, int nWidth, int nHeight, PatBltRop dwRop); + + [DllImport ("user32.dll", EntryPoint="SetWindowLong", CallingConvention=CallingConvention.StdCall)] + private extern static uint Win32SetWindowLong(IntPtr hwnd, WindowLong index, uint value); + + [DllImport ("user32.dll", EntryPoint="GetWindowLong", CallingConvention=CallingConvention.StdCall)] + private extern static uint Win32GetWindowLong(IntPtr hwnd, WindowLong index); + + [DllImport ("user32.dll", EntryPoint="SetLayeredWindowAttributes", CallingConvention=CallingConvention.StdCall)] + private extern static uint Win32SetLayeredWindowAttributes (IntPtr hwnd, COLORREF crKey, byte bAlpha, LayeredWindowAttributes dwFlags); + + [DllImport ("user32.dll", EntryPoint="GetLayeredWindowAttributes", CallingConvention=CallingConvention.StdCall)] + private extern static uint Win32GetLayeredWindowAttributes (IntPtr hwnd, out COLORREF pcrKey, out byte pbAlpha, out LayeredWindowAttributes pwdFlags); + + [DllImport ("gdi32.dll", EntryPoint="DeleteObject", CallingConvention=CallingConvention.StdCall)] + public extern static bool Win32DeleteObject(IntPtr o); + + [DllImport ("user32.dll", EntryPoint="GetKeyState", CallingConvention=CallingConvention.StdCall)] + private extern static short Win32GetKeyState(VirtualKeys nVirtKey); + + [DllImport ("user32.dll", EntryPoint="GetDesktopWindow", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32GetDesktopWindow(); + + [DllImport ("user32.dll", EntryPoint="SetTimer", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32SetTimer(IntPtr hwnd, int nIDEvent, uint uElapse, IntPtr timerProc); + + [DllImport ("user32.dll", EntryPoint="KillTimer", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32KillTimer(IntPtr hwnd, int nIDEvent); + + [DllImport ("user32.dll", EntryPoint="ShowWindow", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32ShowWindow(IntPtr hwnd, WindowPlacementFlags nCmdShow); + + [DllImport ("user32.dll", EntryPoint="EnableWindow", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32EnableWindow(IntPtr hwnd, bool Enabled); + + [DllImport ("user32.dll", EntryPoint="SetFocus", CallingConvention=CallingConvention.StdCall)] + internal extern static IntPtr Win32SetFocus(IntPtr hwnd); + + [DllImport ("user32.dll", EntryPoint="GetFocus", CallingConvention=CallingConvention.StdCall)] + internal extern static IntPtr Win32GetFocus(); + + [DllImport ("user32.dll", EntryPoint="CreateCaret", CallingConvention=CallingConvention.StdCall)] + internal extern static bool Win32CreateCaret(IntPtr hwnd, IntPtr hBitmap, int nWidth, int nHeight); + + [DllImport ("user32.dll", EntryPoint="DestroyCaret", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32DestroyCaret(); + + [DllImport ("user32.dll", EntryPoint="ShowCaret", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32ShowCaret(IntPtr hwnd); + + [DllImport ("user32.dll", EntryPoint="HideCaret", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32HideCaret(IntPtr hwnd); + + [DllImport ("user32.dll", EntryPoint="SetCaretPos", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32SetCaretPos(int X, int Y); + + //[DllImport ("user32.dll", EntryPoint="GetCaretBlinkTime", CallingConvention=CallingConvention.StdCall)] + //private extern static uint Win32GetCaretBlinkTime(); + + [DllImport ("gdi32.dll", EntryPoint="GetTextMetricsW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + internal extern static bool Win32GetTextMetrics(IntPtr hdc, ref TEXTMETRIC tm); + + [DllImport ("gdi32.dll", EntryPoint="SelectObject", CallingConvention=CallingConvention.StdCall)] + internal extern static IntPtr Win32SelectObject(IntPtr hdc, IntPtr hgdiobject); + + //[DllImport ("user32.dll", EntryPoint="ScrollWindowEx", CallingConvention=CallingConvention.StdCall)] + //private extern static bool Win32ScrollWindowEx(IntPtr hwnd, int dx, int dy, ref RECT prcScroll, ref RECT prcClip, IntPtr hrgnUpdate, out RECT prcUpdate, ScrollWindowExFlags flags); + + //[DllImport ("user32.dll", EntryPoint="ScrollWindowEx", CallingConvention=CallingConvention.StdCall)] + //private extern static bool Win32ScrollWindowEx(IntPtr hwnd, int dx, int dy, IntPtr prcScroll, ref RECT prcClip, IntPtr hrgnUpdate, out RECT prcUpdate, ScrollWindowExFlags flags); + + //[DllImport ("user32.dll", EntryPoint="ScrollWindowEx", CallingConvention=CallingConvention.StdCall)] + //private extern static bool Win32ScrollWindowEx(IntPtr hwnd, int dx, int dy, ref RECT prcScroll, IntPtr prcClip, IntPtr hrgnUpdate, out RECT prcUpdate, ScrollWindowExFlags flags); + + [DllImport ("user32.dll", EntryPoint="ScrollWindowEx", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32ScrollWindowEx(IntPtr hwnd, int dx, int dy, IntPtr prcScroll, ref RECT prcClip, IntPtr hrgnUpdate, IntPtr prcUpdate, ScrollWindowExFlags flags); + + //[DllImport ("user32.dll", EntryPoint="ScrollWindowEx", CallingConvention=CallingConvention.StdCall)] + //private extern static bool Win32ScrollWindowEx(IntPtr hwnd, int dx, int dy, ref RECT prcScroll, IntPtr prcClip, IntPtr hrgnUpdate, IntPtr prcUpdate, ScrollWindowExFlags flags); + + //[DllImport ("user32.dll", EntryPoint="ScrollWindowEx", CallingConvention=CallingConvention.StdCall)] + //private extern static bool Win32ScrollWindowEx(IntPtr hwnd, int dx, int dy, ref RECT prcScroll, ref RECT prcClip, IntPtr hrgnUpdate, IntPtr prcUpdate, ScrollWindowExFlags flags); + + [DllImport ("user32.dll", EntryPoint="ScrollWindowEx", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32ScrollWindowEx(IntPtr hwnd, int dx, int dy, IntPtr prcScroll, IntPtr prcClip, IntPtr hrgnUpdate, IntPtr prcUpdate, ScrollWindowExFlags flags); + + [DllImport ("user32.dll", EntryPoint="GetActiveWindow", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32GetActiveWindow(); + + [DllImport ("user32.dll", EntryPoint="GetSystemMetrics", CallingConvention=CallingConvention.StdCall)] + private extern static int Win32GetSystemMetrics(SystemMetrics nIndex); + + [DllImport ("shell32.dll", EntryPoint="Shell_NotifyIconW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32Shell_NotifyIcon(NotifyIconMessage dwMessage, ref NOTIFYICONDATA lpData); + + [DllImport ("gdi32.dll", EntryPoint="CreateRectRgn", CallingConvention=CallingConvention.StdCall)] + internal extern static IntPtr Win32CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); + + [DllImport ("user32.dll", EntryPoint="IsWindowEnabled", CallingConvention=CallingConvention.StdCall)] + private extern static bool IsWindowEnabled(IntPtr hwnd); + + [DllImport ("user32.dll", EntryPoint="IsWindowVisible", CallingConvention=CallingConvention.StdCall)] + private extern static bool IsWindowVisible(IntPtr hwnd); + + [DllImport ("user32.dll", EntryPoint="IsWindow", CallingConvention=CallingConvention.StdCall)] + private extern static bool IsWindow(IntPtr hwnd); + + //[DllImport ("user32.dll", EntryPoint="SetClassLong", CallingConvention=CallingConvention.StdCall)] + //private extern static bool Win32SetClassLong(IntPtr hwnd, ClassLong nIndex, IntPtr dwNewLong); + + [DllImport ("user32.dll", EntryPoint="SendMessageW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32SendMessage(IntPtr hwnd, Msg msg, IntPtr wParam, IntPtr lParam); + + [DllImport ("user32.dll", EntryPoint="PostMessageW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32PostMessage(IntPtr hwnd, Msg msg, IntPtr wParam, IntPtr lParam); + + [DllImport ("user32.dll", EntryPoint="SendInput", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + private extern static UInt32 Win32SendInput(UInt32 nInputs, [MarshalAs(UnmanagedType.LPArray)] INPUT[] inputs, Int32 cbSize); + + [DllImport ("user32.dll", EntryPoint="SystemParametersInfoW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32SystemParametersInfo(SPIAction uiAction, uint uiParam, ref RECT rect, uint fWinIni); + + //[DllImport ("user32.dll", EntryPoint="SystemParametersInfoW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + //private extern static bool Win32SystemParametersInfo(SPIAction uiAction, uint uiParam, ref uint value, uint fWinIni); + + [DllImport ("user32.dll", EntryPoint = "SystemParametersInfoW", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] + private extern static bool Win32SystemParametersInfo (SPIAction uiAction, uint uiParam, ref int value, uint fWinIni); + + [DllImport ("user32.dll", EntryPoint = "SystemParametersInfoW", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] + private extern static bool Win32SystemParametersInfo (SPIAction uiAction, uint uiParam, ref bool value, uint fWinIni); + + [DllImport ("user32.dll", EntryPoint = "SystemParametersInfoW", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] + private extern static bool Win32SystemParametersInfo (SPIAction uiAction, uint uiParam, ref ANIMATIONINFO value, uint fWinIni); + + [DllImport ("user32.dll", EntryPoint="OpenClipboard", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32OpenClipboard(IntPtr hwnd); + + [DllImport ("user32.dll", EntryPoint="EmptyClipboard", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32EmptyClipboard(); + + [DllImport ("user32.dll", EntryPoint="RegisterClipboardFormatW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] + private extern static uint Win32RegisterClipboardFormat(string format); + + [DllImport ("user32.dll", EntryPoint="CloseClipboard", CallingConvention=CallingConvention.StdCall)] + private extern static bool Win32CloseClipboard(); + + [DllImport ("user32.dll", EntryPoint="EnumClipboardFormats", CallingConvention=CallingConvention.StdCall)] + private extern static uint Win32EnumClipboardFormats(uint format); + + [DllImport ("user32.dll", EntryPoint="GetClipboardData", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32GetClipboardData(uint format); + + [DllImport ("user32.dll", EntryPoint="SetClipboardData", CallingConvention=CallingConvention.StdCall)] + private extern static IntPtr Win32SetClipboardData(uint format, IntPtr handle); + + [DllImport ("kernel32.dll", EntryPoint="GlobalAlloc", CallingConvention=CallingConvention.StdCall)] + internal extern static IntPtr Win32GlobalAlloc(GAllocFlags Flags, int dwBytes); + + [DllImport ("kernel32.dll", EntryPoint="CopyMemory", CallingConvention=CallingConvention.StdCall)] + internal extern static void Win32CopyMemory(IntPtr Destination, IntPtr Source, int length); + + [DllImport ("kernel32.dll", EntryPoint="GlobalFree", CallingConvention=CallingConvention.StdCall)] + internal extern static IntPtr Win32GlobalFree(IntPtr hMem); + + [DllImport ("kernel32.dll", EntryPoint="GlobalSize", CallingConvention=CallingConvention.StdCall)] + internal extern static uint Win32GlobalSize(IntPtr hMem); + + [DllImport ("kernel32.dll", EntryPoint="GlobalLock", CallingConvention=CallingConvention.StdCall)] + internal extern static IntPtr Win32GlobalLock(IntPtr hMem); + + [DllImport ("kernel32.dll", EntryPoint="GlobalUnlock", CallingConvention=CallingConvention.StdCall)] + internal extern static IntPtr Win32GlobalUnlock(IntPtr hMem); + + [DllImport ("gdi32.dll", EntryPoint="SetROP2", CallingConvention=CallingConvention.StdCall)] + internal extern static int Win32SetROP2(IntPtr hdc, ROP2DrawMode fnDrawMode); + + [DllImport ("gdi32.dll", EntryPoint="MoveToEx", CallingConvention=CallingConvention.StdCall)] + internal extern static bool Win32MoveToEx(IntPtr hdc, int x, int y, ref POINT lpPoint); + + [DllImport ("gdi32.dll", EntryPoint="MoveToEx", CallingConvention=CallingConvention.StdCall)] + internal extern static bool Win32MoveToEx(IntPtr hdc, int x, int y, IntPtr lpPoint); + + [DllImport ("gdi32.dll", EntryPoint="LineTo", CallingConvention=CallingConvention.StdCall)] + internal extern static bool Win32LineTo(IntPtr hdc, int x, int y); + + [DllImport ("gdi32.dll", EntryPoint="CreatePen", CallingConvention=CallingConvention.StdCall)] + internal extern static IntPtr Win32CreatePen(PenStyle fnPenStyle, int nWidth, ref COLORREF color); + + [DllImport ("gdi32.dll", EntryPoint="CreatePen", CallingConvention=CallingConvention.StdCall)] + internal extern static IntPtr Win32CreatePen(PenStyle fnPenStyle, int nWidth, IntPtr color); + + [DllImport ("gdi32.dll", EntryPoint="GetStockObject", CallingConvention=CallingConvention.StdCall)] + internal extern static IntPtr Win32GetStockObject(StockObject fnObject); + + [DllImport ("gdi32.dll", EntryPoint="CreateHatchBrush", CallingConvention=CallingConvention.StdCall)] + internal extern static IntPtr Win32CreateHatchBrush(HatchStyle fnStyle, IntPtr color); + + [DllImport ("gdi32.dll", EntryPoint="CreateHatchBrush", CallingConvention=CallingConvention.StdCall)] + internal extern static IntPtr Win32CreateHatchBrush(HatchStyle fnStyle, ref COLORREF color); + + [DllImport("gdi32.dll", EntryPoint = "ExcludeClipRect", CallingConvention = CallingConvention.StdCall)] + internal extern static int Win32ExcludeClipRect (IntPtr hdc, int left, int top, int right, int bottom); + + [DllImport ("gdi32.dll", EntryPoint="ExtSelectClipRgn", CallingConvention=CallingConvention.StdCall)] + internal extern static int Win32ExtSelectClipRgn(IntPtr hdc, IntPtr hrgn, int mode); + + [DllImport ("winmm.dll", EntryPoint="PlaySoundW", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode)] + internal extern static IntPtr Win32PlaySound(string pszSound, IntPtr hmod, SndFlags fdwSound); + + [DllImport ("user32.dll", EntryPoint="GetDoubleClickTime", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode)] + private extern static int Win32GetDoubleClickTime (); + + [DllImport ("user32.dll", EntryPoint="SetWindowRgn", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode)] + internal extern static int Win32SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool redraw); + + [DllImport ("user32.dll", EntryPoint="GetWindowRgn", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode)] + internal extern static IntPtr Win32GetWindowRgn(IntPtr hWnd, IntPtr hRgn); + + [DllImport ("user32.dll", EntryPoint="ClipCursor", CallingConvention=CallingConvention.StdCall)] + internal extern static bool Win32ClipCursor (ref RECT lpRect); + + [DllImport ("user32.dll", EntryPoint="GetClipCursor", CallingConvention=CallingConvention.StdCall)] + internal extern static bool Win32GetClipCursor (out RECT lpRect); + + [DllImport ("gdi32.dll", EntryPoint="BitBlt", CallingConvention=CallingConvention.StdCall)] + internal static extern bool Win32BitBlt (IntPtr hObject, int nXDest, int nYDest, int nWidth, + int nHeight, IntPtr hObjSource, int nXSrc, int nYSrc, TernaryRasterOperations dwRop); + + [DllImport ("gdi32.dll", EntryPoint="CreateCompatibleDC", CallingConvention=CallingConvention.StdCall, ExactSpelling = true, SetLastError = true)] + internal static extern IntPtr Win32CreateCompatibleDC (IntPtr hdc); + + [DllImport ("gdi32.dll", EntryPoint="DeleteDC", CallingConvention=CallingConvention.StdCall, ExactSpelling = true, SetLastError = true)] + internal static extern bool Win32DeleteDC (IntPtr hdc); + + [DllImport ("gdi32.dll", EntryPoint="CreateCompatibleBitmap", CallingConvention=CallingConvention.StdCall)] + internal static extern IntPtr Win32CreateCompatibleBitmap (IntPtr hdc, int nWidth, int nHeight); + + [DllImport ("kernel32.dll", EntryPoint = "GetSystemPowerStatus", CallingConvention = CallingConvention.StdCall)] + internal static extern Boolean Win32GetSystemPowerStatus (SYSTEMPOWERSTATUS sps); + + [DllImport ("user32.dll", EntryPoint = "GetIconInfo", CallingConvention = CallingConvention.StdCall)] + internal static extern bool Win32GetIconInfo (IntPtr hIcon, out ICONINFO piconinfo); + + [DllImport ("user32.dll", EntryPoint="SetForegroundWindow", CallingConvention=CallingConvention.StdCall)] + extern static bool Win32SetForegroundWindow(IntPtr hWnd); + #endregion + } +} diff --git a/source/ShiftUI/Internal/XplatUIX11-new.cs b/source/ShiftUI/Internal/XplatUIX11-new.cs new file mode 100644 index 0000000..3795406 --- /dev/null +++ b/source/ShiftUI/Internal/XplatUIX11-new.cs @@ -0,0 +1,1079 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// Chris Toshok toshok@ximian.com +// +// + +// NOTE: +// This driver understands the following environment variables: (Set the var to enable feature) +// +// MONO_XEXCEPTIONS = throw an exception when a X11 error is encountered; +// by default a message is displayed but execution continues +// +// MONO_XSYNC = perform all X11 commands synchronous; this is slower but +// helps in debugging errors +// + +// NOT COMPLETE + +// define to log Window handles and relationships to stdout +#undef DriverDebug + +// Extra detailed debug +#undef DriverDebugExtra +#undef DriverDebugParent +#undef DriverDebugCreate +#undef DriverDebugDestroy +#undef DriverDebugThreads +#undef DriverDebugXEmbed + +using System; +using System.ComponentModel; +using System.Collections; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using ShiftUI; + +/// X11 Version +namespace ShiftUI.X11Internal { + internal class XplatUIX11_new : XplatUIX11 { + + + #region Local Variables + // General + static volatile XplatUIX11_new Instance; + static readonly object lockobj = new object (); + static int RefCount; + static bool themes_enabled; + + static Hashtable MessageQueues; // Holds our thread-specific X11ThreadQueues + + X11Display display; + + #endregion // Local Variables + #region Constructors + private XplatUIX11_new() { + // Handle singleton stuff first + RefCount = 0; + + // Now regular initialization + MessageQueues = Hashtable.Synchronized (new Hashtable(7)); + if (Xlib.XInitThreads() == 0) { + Console.WriteLine ("Failed XInitThreads. The X11 event loop will not function properly"); + } + } + + private void InitializeDisplay () + { + display = new X11Display (Xlib.XOpenDisplay(IntPtr.Zero)); + + Graphics.FromHdcInternal (display.Handle); + } + + ~XplatUIX11_new() { + // Remove our display handle from S.D + Graphics.FromHdcInternal (IntPtr.Zero); + } + + #endregion // Constructors + + #region Singleton Specific Code + public static XplatUIX11_new GetInstance() { + lock (lockobj) { + if (Instance == null) { + Instance = new XplatUIX11_new (); + + Instance.InitializeDisplay (); + } + RefCount++; + } + return Instance; + } + + public int Reference { + get { + return RefCount; + } + } + #endregion + + #region Internal Methods + internal static void Where() { + Console.WriteLine("Here: {0}\n", GetInstance().display.WhereString()); + } + + #endregion // Internal Methods + + #region Private Methods + + internal X11ThreadQueue ThreadQueue (Thread thread) + { + X11ThreadQueue queue; + + queue = (X11ThreadQueue)MessageQueues[thread]; + if (queue == null) { + queue = new X11ThreadQueue(thread); + MessageQueues[thread] = queue; + } + + return queue; + } + #endregion // Private Methods + + + #region Public Properties + internal override int CaptionHeight { + get { return 19; } + } + + internal override Size CursorSize { + get { return display.CursorSize; } + } + + internal override bool DragFullWindows { + get { return true; } + } + + internal override Size DragSize { + get { return new Size(4, 4); } + } + + internal override Size FrameBorderSize { + get { return new Size (4, 4); } + } + + internal override Size IconSize { + get { return display.IconSize; } + } + + internal override int KeyboardSpeed { + get { return display.KeyboardSpeed; } + } + + internal override int KeyboardDelay { + get { return display.KeyboardSpeed; } + } + + internal override Size MaxWindowTrackSize { + get { return new Size (WorkingArea.Width, WorkingArea.Height); } + } + + internal override bool MenuAccessKeysUnderlined { + get { + return false; + } + } + + internal override Size MinimizedWindowSpacingSize { + get { return new Size(1, 1); } + } + + internal override Size MinimumWindowSize { + get { return new Size(1, 1); } + } + + internal override Keys ModifierKeys { + get { return display.ModifierKeys; } + } + + internal override Size SmallIconSize { + get { return display.SmallIconSize; } + } + + internal override int MouseButtonCount { + get { return 3; /* FIXME - should detect this somehow.. */} + } + + internal override bool MouseButtonsSwapped { + get { return false; /*FIXME - how to detect? */} + } + + internal override Size MouseHoverSize { + get { return new Size (1, 1); } + } + + internal override int MouseHoverTime { + get { return display.MouseHoverTime; } + } + + internal override bool MouseWheelPresent { + get { return true; /* FIXME - how to detect? */ } + } + + internal override Rectangle VirtualScreen { + get { return display.VirtualScreen; } + } + + internal override Rectangle WorkingArea { + get { return display.WorkingArea; } + } + + internal override bool ThemesEnabled { + get { return XplatUIX11_new.themes_enabled; } + } + + + #endregion // Public properties + + #region Public Static Methods + internal override void RaiseIdle (EventArgs e) + { + X11ThreadQueue queue = ThreadQueue (Thread.CurrentThread); + queue.OnIdle (e); + } + + internal override IntPtr InitializeDriver () + { + lock (this) { + if (display == null) + display = new X11Display (Xlib.XOpenDisplay(IntPtr.Zero)); + } + return IntPtr.Zero; + } + + internal override void ShutdownDriver(IntPtr token) + { + lock (this) { + if (display != null) { + display.Close (); + display = null; + } + } + } + + internal override void EnableThemes() + { + themes_enabled = true; + } + + internal override void Activate (IntPtr handle) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + hwnd.Activate (); + } + + internal override void AudibleAlert(AlertType atype) + { + display.AudibleAlert (); + } + + + internal override void CaretVisible (IntPtr handle, bool visible) + { + display.CaretVisible (handle, visible); + } + + // XXX this implementation should probably be shared between all non-win32 backends + internal override bool CalculateWindowRect (ref Rectangle ClientRect, CreateParams cp, Menu menu, out Rectangle WindowRect) + { + WindowRect = Hwnd.GetWindowRectangle (cp, menu, ClientRect); + return true; + } + + internal override void ClientToScreen (IntPtr handle, ref int x, ref int y) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + hwnd.ClientToScreen (ref x, ref y); + } + + internal override void CreateCaret (IntPtr handle, int width, int height) + { + display.CreateCaret (handle, width, height); + } + + internal override IntPtr CreateWindow (CreateParams cp) + { + X11Hwnd hwnd = new X11Hwnd (display); + + hwnd.CreateWindow (cp); + + return hwnd.Handle; + } + + internal override IntPtr CreateWindow (IntPtr Parent, int X, int Y, int Width, int Height) + { + CreateParams create_params = new CreateParams(); + + create_params.Caption = ""; + create_params.X = X; + create_params.Y = Y; + create_params.Width = Width; + create_params.Height = Height; + + create_params.ClassName = XplatUI.DefaultClassName; + create_params.ClassStyle = 0; + create_params.ExStyle = 0; + create_params.Parent = IntPtr.Zero; + create_params.Param = 0; + + return CreateWindow (create_params); + } + + internal override IntPtr DefineCursor (Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) + { + return display.DefineCursor (bitmap, mask, cursor_pixel, mask_pixel, xHotSpot, yHotSpot); + } + internal override Bitmap DefineStdCursorBitmap (StdCursor id) + { + return display.DefineStdCursorBitmap (id); + } + internal override IntPtr DefineStdCursor (StdCursor id) + { + return display.DefineStdCursor (id); + } + + internal override IntPtr DefWndProc(ref Message msg) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow(msg.HWnd); + + if (hwnd == null) + return IntPtr.Zero; + + return hwnd.DefWndProc (ref msg); + } + + internal override void DestroyCaret (IntPtr handle) + { + display.DestroyCaret (handle); + } + + internal override void DestroyCursor(IntPtr cursor) + { + display.DestroyCursor (cursor); + } + + internal override void DestroyWindow (IntPtr handle) { + X11Hwnd hwnd; + + hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd == null) { +#if DriverDebug || DriverDebugDestroy + Console.WriteLine("window {0:X} already destroyed", handle.ToInt32()); +#endif + return; + } + +#if DriverDebug || DriverDebugDestroy + Console.WriteLine("Destroying window {0}", XplatUI.Window(hwnd.ClientWindow)); +#endif + + display.DestroyWindow (hwnd); + } + + internal override IntPtr DispatchMessage(ref MSG msg) + { + return display.DispatchMessage (ref msg); + } + + internal override void DrawReversibleLine (Point start, Point end, Color backColor) + { + display.DrawReversibleLine (start, end, backColor); + } + + internal override void FillReversibleRectangle (Rectangle rectangle, Color backColor) + { + display.FillReversibleRectangle (rectangle, backColor); + } + + internal override void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style) + { + display.DrawReversibleFrame (rectangle, backColor, style); + } + + internal override void DrawReversibleRectangle (IntPtr handle, Rectangle rect, int line_width) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + hwnd.DrawReversibleRectangle (rect, line_width); + } + + internal override void DoEvents () + { + X11ThreadQueue queue = ThreadQueue (Thread.CurrentThread); + display.DoEvents (queue); + } + + internal override void EnableWindow (IntPtr handle, bool Enable) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + if (hwnd != null) + hwnd.Enabled = Enable; + } + + internal override void EndLoop (Thread thread) + { + // This is where we one day will shut down the loop for the thread + } + + + internal override IntPtr GetActive() + { + X11Hwnd hwnd = display.GetActiveWindow (); + + return (hwnd == null) ? IntPtr.Zero : hwnd.Handle; + } + + internal override Region GetClipRegion (IntPtr handle) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + return (hwnd == null) ? null : hwnd.GetClipRegion (); + } + + internal override void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y) + { + width = 20; + height = 20; + hotspot_x = 0; + hotspot_y = 0; + } + + internal override void GetDisplaySize(out Size size) + { + display.GetDisplaySize (out size); + } + + internal override SizeF GetAutoScaleSize (Font font) + { + return display.GetAutoScaleSize (font); + } + + // XXX this should be someplace shareable by all non-win32 backends.. like in Hwnd itself. + // maybe a Hwnd.ParentHandle property + internal override IntPtr GetParent (IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + if (hwnd != null && hwnd.parent != null) { + return hwnd.parent.Handle; + } + return IntPtr.Zero; + } + + // This is a nop on win32 and x11 + internal override IntPtr GetPreviousWindow(IntPtr handle) { + return handle; + } + + internal override void GetCursorPos (IntPtr handle, out int x, out int y) + { + display.GetCursorPos ((X11Hwnd)Hwnd.ObjectFromHandle(handle), + out x, out y); + } + + internal override IntPtr GetFocus() + { + return display.GetFocus (); + } + + // XXX this should be shared amongst non-win32 backends + internal override bool GetFontMetrics (Graphics g, Font font, out int ascent, out int descent) + { + FontFamily ff = font.FontFamily; + ascent = ff.GetCellAscent (font.Style); + descent = ff.GetCellDescent (font.Style); + return true; + } + + + // XXX this should be shared amongst non-win32 backends + internal override Point GetMenuOrigin (IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + return hwnd.MenuOrigin; + + return Point.Empty; + } + + internal override bool GetMessage (object queue_id, ref MSG msg, IntPtr handle, int wFilterMin, int wFilterMax) + { + return display.GetMessage (queue_id, ref msg, handle, wFilterMin, wFilterMax); + } + + internal override bool GetText (IntPtr handle, out string text) + { + X11Hwnd hwnd = (X11Hwnd) Hwnd.ObjectFromHandle(handle); + + text = ""; + return hwnd != null && hwnd.GetText (out text); + } + + internal override void GetWindowPos (IntPtr handle, bool is_toplevel, + out int x, out int y, + out int width, out int height, + out int client_width, out int client_height) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) { + hwnd.GetPosition (is_toplevel, out x, out y, out width, out height, out client_width, out client_height); + } + else { + // Should we throw an exception or fail silently? + // throw new ArgumentException("Called with an invalid window handle", "handle"); + + x = 0; + y = 0; + width = 0; + height = 0; + client_width = 0; + client_height = 0; + } + } + + internal override FormWindowState GetWindowState (IntPtr handle) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd == null) + return FormWindowState.Normal; // XXX should we throw an exception here? probably + + return hwnd.GetWindowState (); + } + + internal override void GrabInfo (out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea) + { + display.GrabInfo (out handle, out GrabConfined, out GrabArea); + } + + internal override void GrabWindow (IntPtr handle, IntPtr confine_to_handle) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + X11Hwnd confine_to_hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(confine_to_handle); + + display.GrabWindow (hwnd, confine_to_hwnd); + } + + internal override void UngrabWindow (IntPtr handle) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + display.UngrabWindow (hwnd); + } + + internal override void HandleException(Exception e) { + StackTrace st = new StackTrace(e, true); + Console.WriteLine("Exception '{0}'", e.Message+st.ToString()); + Console.WriteLine("{0}{1}", e.Message, st.ToString()); + } + + internal override void Invalidate (IntPtr handle, Rectangle rc, bool clear) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + hwnd.Invalidate (rc, clear); + } + + internal override void InvalidateNC (IntPtr handle) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + hwnd.InvalidateNC (); + } + + internal override bool IsEnabled(IntPtr handle) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle (handle); + + return hwnd != null && hwnd.Enabled; + } + + internal override bool IsVisible(IntPtr handle) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle (handle); + + return hwnd != null && hwnd.Visible; + } + + internal override void KillTimer (Timer timer) + { + X11ThreadQueue queue = (X11ThreadQueue) MessageQueues [timer.thread]; + + if (queue == null) { + // This isn't really an error, MS doesn't start the timer if + // it has no assosciated queue + return; + } + queue.KillTimer (timer); + } + + internal override void MenuToScreen (IntPtr handle, ref int x, ref int y) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + hwnd.MenuToScreen (ref x, ref y); + } + + internal override void OverrideCursor (IntPtr cursor) + { + display.OverrideCursor = cursor; + } + + internal override PaintEventArgs PaintEventStart (ref Message m, IntPtr handle, bool client) + { + return display.PaintEventStart (ref m, handle, client); + } + + internal override void PaintEventEnd (ref Message m, IntPtr handle, bool client) + { + display.PaintEventEnd (ref m, handle, client); + } + + + internal override bool PeekMessage (object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) + { + return display.PeekMessage (queue_id, ref msg, hWnd, wFilterMin, wFilterMax, flags); + } + + internal override bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam) + { + return display.PostMessage (handle, message, wparam, lparam); + } + + internal override void PostQuitMessage(int exitCode) + { + display.PostMessage (display.FosterParent.Handle, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero); + display.Flush (); + } + + [MonoTODO] + internal override void RequestAdditionalWM_NCMessages (IntPtr handle, bool hover, bool leave) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + hwnd.RequestAdditionalWM_NCMessages (hover, leave); + } + + internal override void RequestNCRecalc (IntPtr handle) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + hwnd.RequestNCRecalc (); + } + + internal override void ResetMouseHover (IntPtr handle) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + display.ResetMouseHover (hwnd); + } + + internal override void ScreenToClient(IntPtr handle, ref int x, ref int y) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + hwnd.ScreenToClient (ref x, ref y); + } + + internal override void ScreenToMenu (IntPtr handle, ref int x, ref int y) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + hwnd.ScreenToMenu (ref x, ref y); + } + + internal override void ScrollWindow (IntPtr handle, Rectangle area, int XAmount, int YAmount, bool with_children) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + hwnd.ScrollWindow (area, XAmount, YAmount, with_children); + } + + internal override void ScrollWindow(IntPtr handle, int XAmount, int YAmount, bool with_children) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow(handle); + + if (hwnd != null) { + Rectangle rect; + + rect = hwnd.ClientRect; + rect.X = 0; + rect.Y = 0; + hwnd.ScrollWindow (rect, XAmount, YAmount, with_children); + } + } + + internal override void SendAsyncMethod (AsyncMethodData method) + { + display.SendAsyncMethod (method); + } + + // XXX this is likely shareable amongst other backends + internal override IntPtr SendMessage (IntPtr handle, Msg message, IntPtr wParam, IntPtr lParam) + { + return display.SendMessage (handle, message, wParam, lParam); + } + + internal override int SendInput(IntPtr handle, Queue keys) { + return display.SendInput(handle, keys); + } + + + internal override void SetAllowDrop (IntPtr handle, bool value) + { + // We allow drop on all windows + } + + internal override DragDropEffects StartDrag (IntPtr handle, object data, + DragDropEffects allowed_effects) + { + return display.StartDrag (handle, data, allowed_effects); + } + + internal override void SetBorderStyle (IntPtr handle, FormBorderStyle border_style) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + hwnd.SetBorderStyle (border_style); + } + + internal override void SetCaretPos (IntPtr handle, int x, int y) + { + display.SetCaretPos (handle, x, y); + } + + internal override void SetClipRegion (IntPtr handle, Region region) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + hwnd.SetClipRegion (region); + } + + internal override void SetCursor (IntPtr handle, IntPtr cursor) + { + display.SetCursor (handle, cursor); + } + + internal override void SetCursorPos (IntPtr handle, int x, int y) + { + if (handle == IntPtr.Zero) { + display.SetCursorPos (x, y); + } + else { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + hwnd.SetCursorPos (x, y); + } + } + + internal override void SetFocus (IntPtr handle) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + display.SetFocus (hwnd); + } + + internal override void SetIcon(IntPtr handle, Icon icon) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle);; + + if (hwnd != null) + hwnd.SetIcon (icon); + } + + internal override void SetMenu(IntPtr handle, Menu menu) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + hwnd.SetMenu (menu); + } + + internal override void SetModal(IntPtr handle, bool Modal) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + display.SetModal (hwnd, Modal); + } + + internal override IntPtr SetParent(IntPtr handle, IntPtr parent) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + X11Hwnd parent_hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(parent); + + if (hwnd != null) + hwnd.SetParent (parent_hwnd); + + return IntPtr.Zero; + } + + internal override void SetTimer (Timer timer) + { + X11ThreadQueue queue = (X11ThreadQueue) MessageQueues [timer.thread]; + + if (queue == null) { + // This isn't really an error, MS doesn't start the timer if + // it has no assosciated queue + return; + } + queue.SetTimer (timer); + } + + internal override bool SetTopmost(IntPtr handle, bool enabled) + { + X11Hwnd hwnd = (X11Hwnd) Hwnd.ObjectFromHandle (handle); + + if (hwnd == null) + return false; + + return hwnd.SetTopmost (enabled); + } + + internal override bool SetOwner(IntPtr handle, IntPtr handle_owner) + { + X11Hwnd hwnd; + + hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd == null) + return false; + + X11Hwnd hwnd_owner = (X11Hwnd)Hwnd.ObjectFromHandle(handle_owner); + + return hwnd.SetOwner (hwnd_owner); + } + + internal override bool SetVisible (IntPtr handle, bool visible, bool activate) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + return hwnd != null && hwnd.SetVisible (visible, activate); + } + + internal override void SetWindowMinMax (IntPtr handle, Rectangle maximized, Size min, Size max) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd == null) + return; + + hwnd.SetMinMax (maximized, min, max); + } + + internal override void SetWindowPos (IntPtr handle, int x, int y, int width, int height) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + hwnd.SetPosition (x, y, width, height); + } + + internal override void SetWindowState (IntPtr handle, FormWindowState state) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + hwnd.SetWindowState (state); + } + + internal override void SetWindowStyle (IntPtr handle, CreateParams cp) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) { + hwnd.SetHwndStyles (cp); + hwnd.SetWMStyles (cp); + } + } + + internal override double GetWindowTransparency (IntPtr handle) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + return hwnd.GetWindowTransparency (); + else + return 0.0; + } + + internal override void SetWindowTransparency (IntPtr handle, double transparency, Color key) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + hwnd.SetWindowTransparency (transparency, key); + } + + internal override bool SetZOrder (IntPtr handle, IntPtr after_handle, bool top, bool bottom) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd == null || !hwnd.mapped) + return false; + + X11Hwnd after_hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(after_handle); + + return hwnd.SetZOrder (after_hwnd, top, bottom); + } + + internal override void ShowCursor (bool show) + { + display.ShowCursor (show); + } + + internal override object StartLoop(Thread thread) + { + return (object) ThreadQueue(thread); + } + + internal override TransparencySupport SupportsTransparency() + { + return display.SupportsTransparency (); + } + + internal override bool SystrayAdd (IntPtr handle, string tip, Icon icon, out ToolTip tt) + { + return display.SystrayAdd (handle, tip, icon, out tt); + } + + internal override bool SystrayChange (IntPtr handle, string tip, Icon icon, ref ToolTip tt) + { + return display.SystrayChange (handle, tip, icon, ref tt); + } + + internal override void SystrayRemove (IntPtr handle, ref ToolTip tt) + { + display.SystrayRemove (handle, ref tt); + } + + NotifyIcon.BalloonWindow balloon_window; + + internal override void SystrayBalloon(IntPtr handle, int timeout, string title, string text, ToolTipIcon icon) + { + Widget control = Widget.FromHandle(handle); + + if (control == null) + return; + + if (balloon_window != null) { + balloon_window.Close (); + balloon_window.Dispose (); + } + + balloon_window = new NotifyIcon.BalloonWindow (handle); + balloon_window.Title = title; + balloon_window.Text = text; + balloon_window.Timeout = timeout; + balloon_window.Show (); + + SendMessage(handle, Msg.WM_USER, IntPtr.Zero, (IntPtr) Msg.NIN_BALLOONSHOW); + } + + internal override bool Text (IntPtr handle, string text) + { + X11Hwnd hwnd = (X11Hwnd) Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + hwnd.Text = text; + + return true; + } + + internal override bool TranslateMessage (ref MSG msg) + { + return display.TranslateMessage (ref msg); + } + + internal override void UpdateWindow (IntPtr handle) + { + X11Hwnd hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) + hwnd.Update (); + } + + internal override void CreateOffscreenDrawable (IntPtr handle, + int width, int height, + out object offscreen_drawable) + { + display.CreateOffscreenDrawable (handle, width, height, + out offscreen_drawable); + } + + internal override void DestroyOffscreenDrawable (object offscreen_drawable) + { + display.DestroyOffscreenDrawable (offscreen_drawable); + } + + internal override Graphics GetOffscreenGraphics (object offscreen_drawable) + { + return display.GetOffscreenGraphics (offscreen_drawable); + } + + internal override void BlitFromOffscreen (IntPtr dest_handle, + Graphics dest_dc, + object offscreen_drawable, + Graphics offscreen_dc, + Rectangle r) + { + display.BlitFromOffscreen (dest_handle, dest_dc, offscreen_drawable, offscreen_dc, r); + } + + #endregion // Public Static Methods + + #region Events + internal override event EventHandler Idle { + add { + Console.WriteLine ("adding idle handler for thread {0}", Thread.CurrentThread.GetHashCode()); + X11ThreadQueue queue = ThreadQueue(Thread.CurrentThread); + queue.Idle += value; + } + remove { + X11ThreadQueue queue = ThreadQueue(Thread.CurrentThread); + queue.Idle += value; + } + } + #endregion // Events + } +} diff --git a/source/ShiftUI/Internal/XplatUIX11.cs b/source/ShiftUI/Internal/XplatUIX11.cs new file mode 100644 index 0000000..fd68bab --- /dev/null +++ b/source/ShiftUI/Internal/XplatUIX11.cs @@ -0,0 +1,7687 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +// NOTE: +// This driver understands the following environment variables: (Set the var to enable feature) +// +// MONO_XEXCEPTIONS = throw an exception when a X11 error is encountered; +// by default a message is displayed but execution continues +// +// MONO_XSYNC = perform all X11 commands synchronous; this is slower but +// helps in debugging errors +// + +// NOT COMPLETE + +// define to log Window handles and relationships to stdout +#undef DriverDebug + +// Extra detailed debug +#undef DriverDebugExtra +#undef DriverDebugParent +#undef DriverDebugCreate +#undef DriverDebugDestroy +#undef DriverDebugThreads +#undef DriverDebugXEmbed + +//#define TRACE +//#define DEBUG + +using System; +using System.ComponentModel; +using System.Collections; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; +using System.Threading; + +// Only do the poll when building with mono for now +#if __MonoCS__ +using Mono.Unix.Native; +#endif + +/// X11 Version +namespace ShiftUI { + internal class XplatUIX11 : XplatUIDriver { + #region Local Variables + // General + static volatile XplatUIX11 Instance; + static int RefCount; + static object XlibLock; // Our locking object + static bool themes_enabled; + + // General X11 + static IntPtr DisplayHandle; // X11 handle to display + static int ScreenNo; // Screen number used + static IntPtr DefaultColormap; // Colormap for screen + static IntPtr CustomVisual; // Visual for window creation + static IntPtr CustomColormap; // Colormap for window creation + static IntPtr RootWindow; // Handle of the root window for the screen/display + static IntPtr FosterParent; // Container to hold child windows until their parent exists + static XErrorHandler ErrorHandler; // Error handler delegate + static bool ErrorExceptions; // Throw exceptions on X errors + int render_major_opcode; + int render_first_event; + int render_first_error; + + // Clipboard + static IntPtr ClipMagic; + static ClipboardData Clipboard; // Our clipboard + + // Communication + static IntPtr PostAtom; // PostMessage atom + static IntPtr AsyncAtom; // Support for async messages + + // Message Loop + static Hashtable MessageQueues; // Holds our thread-specific XEventQueues + static ArrayList unattached_timer_list; // holds timers that are enabled but not attached to a window. + #if __MonoCS__ // + static Pollfd[] pollfds; // For watching the X11 socket + static bool wake_waiting; + static object wake_waiting_lock = new object (); + #endif // + static X11Keyboard Keyboard; // + static X11Dnd Dnd; + static Socket listen; // + static Socket wake; // + static Socket wake_receive; // + static byte[] network_buffer; // + static bool detectable_key_auto_repeat; + + // Focus tracking + static IntPtr ActiveWindow; // Handle of the active window + static IntPtr FocusWindow; // Handle of the window with keyboard focus (if any) + + // Modality support + static Stack ModalWindows; // Stack of our modal windows + + // Systray + static IntPtr SystrayMgrWindow; // Handle of the Systray Manager window + + // Cursors + static IntPtr LastCursorWindow; // The last window we set the cursor on + static IntPtr LastCursorHandle; // The handle that was last set on LastCursorWindow + static IntPtr OverrideCursorHandle; // The cursor that is set to override any other cursors + + // Caret + static CaretStruct Caret; // + + // Last window containing the pointer + static IntPtr LastPointerWindow; // The last window containing the pointer + + // Our atoms + static IntPtr WM_PROTOCOLS; + static IntPtr WM_DELETE_WINDOW; + static IntPtr WM_TAKE_FOCUS; + //static IntPtr _NET_SUPPORTED; + //static IntPtr _NET_CLIENT_LIST; + //static IntPtr _NET_NUMBER_OF_DESKTOPS; + static IntPtr _NET_DESKTOP_GEOMETRY; + //static IntPtr _NET_DESKTOP_VIEWPORT; + static IntPtr _NET_CURRENT_DESKTOP; + //static IntPtr _NET_DESKTOP_NAMES; + static IntPtr _NET_ACTIVE_WINDOW; + static IntPtr _NET_WORKAREA; + //static IntPtr _NET_SUPPORTING_WM_CHECK; + //static IntPtr _NET_VIRTUAL_ROOTS; + //static IntPtr _NET_DESKTOP_LAYOUT; + //static IntPtr _NET_SHOWING_DESKTOP; + //static IntPtr _NET_CLOSE_WINDOW; + //static IntPtr _NET_MOVERESIZE_WINDOW; + static IntPtr _NET_WM_MOVERESIZE; + //static IntPtr _NET_RESTACK_WINDOW; + //static IntPtr _NET_REQUEST_FRAME_EXTENTS; + static IntPtr _NET_WM_NAME; + //static IntPtr _NET_WM_VISIBLE_NAME; + //static IntPtr _NET_WM_ICON_NAME; + //static IntPtr _NET_WM_VISIBLE_ICON_NAME; + //static IntPtr _NET_WM_DESKTOP; + static IntPtr _NET_WM_WINDOW_TYPE; + static IntPtr _NET_WM_STATE; + //static IntPtr _NET_WM_ALLOWED_ACTIONS; + //static IntPtr _NET_WM_STRUT; + //static IntPtr _NET_WM_STRUT_PARTIAL; + //static IntPtr _NET_WM_ICON_GEOMETRY; + static IntPtr _NET_WM_ICON; + //static IntPtr _NET_WM_PID; + //static IntPtr _NET_WM_HANDLED_ICONS; + static IntPtr _NET_WM_USER_TIME; + static IntPtr _NET_FRAME_EXTENTS; + //static IntPtr _NET_WM_PING; + //static IntPtr _NET_WM_SYNC_REQUEST; + static IntPtr _NET_SYSTEM_TRAY_S; + //static IntPtr _NET_SYSTEM_TRAY_ORIENTATION; + static IntPtr _NET_SYSTEM_TRAY_OPCODE; + static IntPtr _NET_WM_STATE_MAXIMIZED_HORZ; + static IntPtr _NET_WM_STATE_MAXIMIZED_VERT; + static IntPtr _XEMBED; + static IntPtr _XEMBED_INFO; + static IntPtr _MOTIF_WM_HINTS; + static IntPtr _NET_WM_STATE_SKIP_TASKBAR; + static IntPtr _NET_WM_STATE_ABOVE; + static IntPtr _NET_WM_STATE_MODAL; + static IntPtr _NET_WM_STATE_HIDDEN; + static IntPtr _NET_WM_CONTEXT_HELP; + static IntPtr _NET_WM_WINDOW_OPACITY; + //static IntPtr _NET_WM_WINDOW_TYPE_DESKTOP; + //static IntPtr _NET_WM_WINDOW_TYPE_DOCK; + //static IntPtr _NET_WM_WINDOW_TYPE_TOOLBAR; + //static IntPtr _NET_WM_WINDOW_TYPE_MENU; + static IntPtr _NET_WM_WINDOW_TYPE_UTILITY; + //static IntPtr _NET_WM_WINDOW_TYPE_SPLASH; + // static IntPtr _NET_WM_WINDOW_TYPE_DIALOG; + static IntPtr _NET_WM_WINDOW_TYPE_NORMAL; + static IntPtr CLIPBOARD; + static IntPtr PRIMARY; + //static IntPtr DIB; + static IntPtr OEMTEXT; + static IntPtr UTF8_STRING; + static IntPtr UTF16_STRING; + static IntPtr RICHTEXTFORMAT; + static IntPtr TARGETS; + + // mouse hover message generation + static HoverStruct HoverState; // + + // double click message generation + static ClickStruct ClickPending; // + + // Support for mouse grab + static GrabStruct Grab; // + + // State + Point mouse_position; // Last position of mouse, in screen coords + internal static MouseButtons MouseState; // Last state of mouse buttons + internal static bool in_doevents; + // 'Constants' + static int DoubleClickInterval; // msec; max interval between clicks to count as double click + + const EventMask SelectInputMask = (EventMask.ButtonPressMask | + EventMask.ButtonReleaseMask | + EventMask.KeyPressMask | + EventMask.KeyReleaseMask | + EventMask.EnterWindowMask | + EventMask.LeaveWindowMask | + EventMask.ExposureMask | + EventMask.FocusChangeMask | + EventMask.PointerMotionMask | + EventMask.PointerMotionHintMask | + EventMask.SubstructureNotifyMask); + + static readonly object lockobj = new object (); + + // messages WaitForHwndMwssage is waiting on + static Hashtable messageHold; + + #endregion // Local Variables + #region Constructors + public XplatUIX11() + { + // Handle singleton stuff first + RefCount = 0; + in_doevents = false; + + // Now regular initialization + XlibLock = new object (); + X11Keyboard.XlibLock = XlibLock; + MessageQueues = Hashtable.Synchronized (new Hashtable(7)); + unattached_timer_list = ArrayList.Synchronized (new ArrayList (3)); + messageHold = Hashtable.Synchronized (new Hashtable(3)); + Clipboard = new ClipboardData (); + XInitThreads(); + + ErrorExceptions = false; + + // X11 Initialization + SetDisplay(XOpenDisplay(IntPtr.Zero)); + X11DesktopColors.Initialize(); + + + // Disable keyboard autorepeat + try { + XkbSetDetectableAutoRepeat (DisplayHandle, true, IntPtr.Zero); + detectable_key_auto_repeat = true; + } catch { + Console.Error.WriteLine ("Could not disable keyboard auto repeat, will attempt to disable manually."); + detectable_key_auto_repeat = false; + } + + // Handle any upcoming errors; we re-set it here, X11DesktopColor stuff might have stolen it (gtk does) + ErrorHandler = new XErrorHandler(HandleError); + XSetErrorHandler(ErrorHandler); + } + + ~XplatUIX11() { + // Remove our display handle from S.D + Graphics.FromHdcInternal (IntPtr.Zero); + } + + #endregion // Constructors + + #region Singleton Specific Code + public static XplatUIX11 GetInstance() { + lock (lockobj) { + if (Instance == null) { + Instance=new XplatUIX11(); + } + RefCount++; + } + return Instance; + } + + public int Reference { + get { + return RefCount; + } + } + #endregion + + #region Internal Properties + internal static IntPtr Display { + get { + return DisplayHandle; + } + + set { + XplatUIX11.GetInstance().SetDisplay(value); + } + } + + internal static int Screen { + get { + return ScreenNo; + } + + set { + ScreenNo = value; + } + } + + internal static IntPtr RootWindowHandle { + get { + return RootWindow; + } + + set { + RootWindow = value; + } + } + + internal static IntPtr Visual { + get { + return CustomVisual; + } + + set { + CustomVisual = value; + } + } + + internal static IntPtr ColorMap { + get { + return CustomColormap; + } + + set { + CustomColormap = value; + } + } + +#if DEBUG_shana + internal static IntPtr DefaultColorMap { + get { + return DefaultColormap; + } + } +#endif + #endregion + + #region XExceptionClass + internal class XException : ApplicationException { + IntPtr Display; + IntPtr ResourceID; + IntPtr Serial; + XRequest RequestCode; + byte ErrorCode; + byte MinorCode; + + public XException(IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) { + this.Display = Display; + this.ResourceID = ResourceID; + this.Serial = Serial; + this.RequestCode = RequestCode; + this.ErrorCode = ErrorCode; + this.MinorCode = MinorCode; + } + + public override string Message { + get { + return GetMessage(Display, ResourceID, Serial, ErrorCode, RequestCode, MinorCode); + } + } + + public static string GetMessage(IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) { + StringBuilder sb; + string x_error_text; + string error; + string hwnd_text; + string Widget_text; + Hwnd hwnd; + Widget c; + + sb = new StringBuilder(160); + XGetErrorText(Display, ErrorCode, sb, sb.Capacity); + x_error_text = sb.ToString(); + hwnd = Hwnd.ObjectFromHandle(ResourceID); + if (hwnd != null) { + hwnd_text = hwnd.ToString(); + c = Widget.FromHandle(hwnd.Handle); + if (c != null) { + Widget_text = c.ToString(); + } else { + Widget_text = String.Format("", hwnd.Handle.ToInt32()); + } + } else { + hwnd_text = ""; + Widget_text = ""; + } + + + error = String.Format("\n Error: {0}\n Request: {1:D} ({2})\n Resource ID: 0x{3:X}\n Serial: {4}\n Hwnd: {5}\n Widget: {6}", x_error_text, RequestCode, MinorCode, ResourceID.ToInt32(), Serial, hwnd_text, Widget_text); + return error; + } + } + #endregion // XExceptionClass + + #region Internal Methods + internal void SetDisplay(IntPtr display_handle) + { + if (display_handle != IntPtr.Zero) { + Hwnd hwnd; + + if ((DisplayHandle != IntPtr.Zero) && (FosterParent != IntPtr.Zero)) { + hwnd = Hwnd.ObjectFromHandle(FosterParent); + XDestroyWindow(DisplayHandle, FosterParent); + hwnd.Dispose(); + } + + if (DisplayHandle != IntPtr.Zero) { + XCloseDisplay(DisplayHandle); + } + + DisplayHandle=display_handle; + + // We need to tell System.Drawing our DisplayHandle. FromHdcInternal has + // been hacked to do this for us. + Graphics.FromHdcInternal (DisplayHandle); + + // query for the render extension so + // we can ignore the spurious + // BadPicture errors that are + // generated by cairo/render. + XQueryExtension (DisplayHandle, "RENDER", + ref render_major_opcode, ref render_first_event, ref render_first_error); + + // Debugging support + if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) { + XSynchronize(DisplayHandle, true); + } + + if (Environment.GetEnvironmentVariable ("MONO_XEXCEPTIONS") != null) { + ErrorExceptions = true; + } + + // Generic X11 setup + ScreenNo = XDefaultScreen(DisplayHandle); + RootWindow = XRootWindow(DisplayHandle, ScreenNo); + DefaultColormap = XDefaultColormap(DisplayHandle, ScreenNo); + + // Create the foster parent + // it is important that border_width is kept in synch with the other XCreateWindow calls + FosterParent=XCreateSimpleWindow(DisplayHandle, RootWindow, 0, 0, 1, 1, 0, UIntPtr.Zero, UIntPtr.Zero); + if (FosterParent==IntPtr.Zero) { + Console.WriteLine("XplatUIX11 Constructor failed to create FosterParent"); + } + + DebugHelper.WriteLine ("FosterParent created 0x{0:x}", FosterParent.ToInt32()); + + hwnd = new Hwnd(); + hwnd.Queue = ThreadQueue(Thread.CurrentThread); + hwnd.WholeWindow = FosterParent; + hwnd.ClientWindow = FosterParent; + + // Create a HWND for RootWIndow as well, so our queue doesn't eat the events + hwnd = new Hwnd(); + hwnd.Queue = ThreadQueue(Thread.CurrentThread); + hwnd.whole_window = RootWindow; + hwnd.ClientWindow = RootWindow; + + // For sleeping on the X11 socket + listen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); + IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 0); + listen.Bind(ep); + listen.Listen(1); + + // To wake up when a timer is ready + network_buffer = new byte[10]; + + wake = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); + wake.Connect(listen.LocalEndPoint); + + // Make this non-blocking, so it doesn't + // deadlock if too many wakes are sent + // before the wake_receive end is polled + wake.Blocking = false; + + wake_receive = listen.Accept(); + + #if __MonoCS__ + pollfds = new Pollfd [2]; + pollfds [0] = new Pollfd (); + pollfds [0].fd = XConnectionNumber (DisplayHandle); + pollfds [0].events = PollEvents.POLLIN; + + pollfds [1] = new Pollfd (); + pollfds [1].fd = wake_receive.Handle.ToInt32 (); + pollfds [1].events = PollEvents.POLLIN; + #endif + + Keyboard = new X11Keyboard(DisplayHandle, FosterParent); + Dnd = new X11Dnd (DisplayHandle, Keyboard); + + DoubleClickInterval = 500; + + HoverState.Interval = 500; + HoverState.Timer = new Timer(); + HoverState.Timer.Enabled = false; + HoverState.Timer.Interval = HoverState.Interval; + HoverState.Timer.Tick += new EventHandler(MouseHover); + HoverState.Size = new Size(4, 4); + HoverState.X = -1; + HoverState.Y = -1; + + ActiveWindow = IntPtr.Zero; + FocusWindow = IntPtr.Zero; + ModalWindows = new Stack(3); + + MouseState = MouseButtons.None; + mouse_position = new Point(0, 0); + + Caret.Timer = new Timer(); + Caret.Timer.Interval = 500; // FIXME - where should this number come from? + Caret.Timer.Tick += new EventHandler(CaretCallback); + + SetupAtoms(); + + // Grab atom changes off the root window to catch certain WM events + XSelectInput(DisplayHandle, RootWindow, new IntPtr ((int) (EventMask.PropertyChangeMask | Keyboard.KeyEventMask))); + + // Handle any upcoming errors + ErrorHandler = new XErrorHandler(HandleError); + XSetErrorHandler(ErrorHandler); + } else { + throw new ArgumentNullException("Display", "Could not open display (X-Server required. Check your DISPLAY environment variable)"); + } + } + #endregion // Internal Methods + + #region Methods + [Conditional ("DriverDebug")] + static void DriverDebug (string format, params object [] args) + { + Console.WriteLine (String.Format (format, args)); + } + + int unixtime() { + TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1)); + + return (int) t.TotalSeconds; + } + + static void SetupAtoms() { + // make sure this array stays in sync with the statements below + string [] atom_names = new string[] { + "WM_PROTOCOLS", + "WM_DELETE_WINDOW", + "WM_TAKE_FOCUS", + //"_NET_SUPPORTED", + //"_NET_CLIENT_LIST", + //"_NET_NUMBER_OF_DESKTOPS", + "_NET_DESKTOP_GEOMETRY", + //"_NET_DESKTOP_VIEWPORT", + "_NET_CURRENT_DESKTOP", + //"_NET_DESKTOP_NAMES", + "_NET_ACTIVE_WINDOW", + "_NET_WORKAREA", + //"_NET_SUPPORTING_WM_CHECK", + //"_NET_VIRTUAL_ROOTS", + //"_NET_DESKTOP_LAYOUT", + //"_NET_SHOWING_DESKTOP", + //"_NET_CLOSE_WINDOW", + //"_NET_MOVERESIZE_WINDOW", + "_NET_WM_MOVERESIZE", + //"_NET_RESTACK_WINDOW", + //"_NET_REQUEST_FRAME_EXTENTS", + "_NET_WM_NAME", + //"_NET_WM_VISIBLE_NAME", + //"_NET_WM_ICON_NAME", + //"_NET_WM_VISIBLE_ICON_NAME", + //"_NET_WM_DESKTOP", + "_NET_WM_WINDOW_TYPE", + "_NET_WM_STATE", + //"_NET_WM_ALLOWED_ACTIONS", + //"_NET_WM_STRUT", + //"_NET_WM_STRUT_PARTIAL", + //"_NET_WM_ICON_GEOMETRY", + "_NET_WM_ICON", + //"_NET_WM_PID", + //"_NET_WM_HANDLED_ICONS", + "_NET_WM_USER_TIME", + "_NET_FRAME_EXTENTS", + //"_NET_WM_PING", + //"_NET_WM_SYNC_REQUEST", + "_NET_SYSTEM_TRAY_OPCODE", + //"_NET_SYSTEM_TRAY_ORIENTATION", + "_NET_WM_STATE_MAXIMIZED_HORZ", + "_NET_WM_STATE_MAXIMIZED_VERT", + "_NET_WM_STATE_HIDDEN", + "_XEMBED", + "_XEMBED_INFO", + "_MOTIF_WM_HINTS", + "_NET_WM_STATE_SKIP_TASKBAR", + "_NET_WM_STATE_ABOVE", + "_NET_WM_STATE_MODAL", + "_NET_WM_CONTEXT_HELP", + "_NET_WM_WINDOW_OPACITY", + //"_NET_WM_WINDOW_TYPE_DESKTOP", + //"_NET_WM_WINDOW_TYPE_DOCK", + //"_NET_WM_WINDOW_TYPE_TOOLBAR", + //"_NET_WM_WINDOW_TYPE_MENU", + "_NET_WM_WINDOW_TYPE_UTILITY", + // "_NET_WM_WINDOW_TYPE_DIALOG", + //"_NET_WM_WINDOW_TYPE_SPLASH", + "_NET_WM_WINDOW_TYPE_NORMAL", + "CLIPBOARD", + "PRIMARY", + "COMPOUND_TEXT", + "UTF8_STRING", + "UTF16_STRING", + "RICHTEXTFORMAT", + "TARGETS", + "_SWF_AsyncAtom", + "_SWF_PostMessageAtom", + "_SWF_HoverAtom" }; + + IntPtr[] atoms = new IntPtr [atom_names.Length];; + + XInternAtoms (DisplayHandle, atom_names, atom_names.Length, false, atoms); + + int off = 0; + WM_PROTOCOLS = atoms [off++]; + WM_DELETE_WINDOW = atoms [off++]; + WM_TAKE_FOCUS = atoms [off++]; + //_NET_SUPPORTED = atoms [off++]; + //_NET_CLIENT_LIST = atoms [off++]; + //_NET_NUMBER_OF_DESKTOPS = atoms [off++]; + _NET_DESKTOP_GEOMETRY = atoms [off++]; + //_NET_DESKTOP_VIEWPORT = atoms [off++]; + _NET_CURRENT_DESKTOP = atoms [off++]; + //_NET_DESKTOP_NAMES = atoms [off++]; + _NET_ACTIVE_WINDOW = atoms [off++]; + _NET_WORKAREA = atoms [off++]; + //_NET_SUPPORTING_WM_CHECK = atoms [off++]; + //_NET_VIRTUAL_ROOTS = atoms [off++]; + //_NET_DESKTOP_LAYOUT = atoms [off++]; + //_NET_SHOWING_DESKTOP = atoms [off++]; + //_NET_CLOSE_WINDOW = atoms [off++]; + //_NET_MOVERESIZE_WINDOW = atoms [off++]; + _NET_WM_MOVERESIZE = atoms [off++]; + //_NET_RESTACK_WINDOW = atoms [off++]; + //_NET_REQUEST_FRAME_EXTENTS = atoms [off++]; + _NET_WM_NAME = atoms [off++]; + //_NET_WM_VISIBLE_NAME = atoms [off++]; + //_NET_WM_ICON_NAME = atoms [off++]; + //_NET_WM_VISIBLE_ICON_NAME = atoms [off++]; + //_NET_WM_DESKTOP = atoms [off++]; + _NET_WM_WINDOW_TYPE = atoms [off++]; + _NET_WM_STATE = atoms [off++]; + //_NET_WM_ALLOWED_ACTIONS = atoms [off++]; + //_NET_WM_STRUT = atoms [off++]; + //_NET_WM_STRUT_PARTIAL = atoms [off++]; + //_NET_WM_ICON_GEOMETRY = atoms [off++]; + _NET_WM_ICON = atoms [off++]; + //_NET_WM_PID = atoms [off++]; + //_NET_WM_HANDLED_ICONS = atoms [off++]; + _NET_WM_USER_TIME = atoms [off++]; + _NET_FRAME_EXTENTS = atoms [off++]; + //_NET_WM_PING = atoms [off++]; + //_NET_WM_SYNC_REQUEST = atoms [off++]; + _NET_SYSTEM_TRAY_OPCODE = atoms [off++]; + //_NET_SYSTEM_TRAY_ORIENTATION = atoms [off++]; + _NET_WM_STATE_MAXIMIZED_HORZ = atoms [off++]; + _NET_WM_STATE_MAXIMIZED_VERT = atoms [off++]; + _NET_WM_STATE_HIDDEN = atoms [off++]; + _XEMBED = atoms [off++]; + _XEMBED_INFO = atoms [off++]; + _MOTIF_WM_HINTS = atoms [off++]; + _NET_WM_STATE_SKIP_TASKBAR = atoms [off++]; + _NET_WM_STATE_ABOVE = atoms [off++]; + _NET_WM_STATE_MODAL = atoms [off++]; + _NET_WM_CONTEXT_HELP = atoms [off++]; + _NET_WM_WINDOW_OPACITY = atoms [off++]; + //_NET_WM_WINDOW_TYPE_DESKTOP = atoms [off++]; + //_NET_WM_WINDOW_TYPE_DOCK = atoms [off++]; + //_NET_WM_WINDOW_TYPE_TOOLBAR = atoms [off++]; + //_NET_WM_WINDOW_TYPE_MENU = atoms [off++]; + _NET_WM_WINDOW_TYPE_UTILITY = atoms [off++]; + // _NET_WM_WINDOW_TYPE_DIALOG = atoms [off++]; + //_NET_WM_WINDOW_TYPE_SPLASH = atoms [off++]; + _NET_WM_WINDOW_TYPE_NORMAL = atoms [off++]; + CLIPBOARD = atoms [off++]; + PRIMARY = atoms [off++]; + OEMTEXT = atoms [off++]; + UTF8_STRING = atoms [off++]; + UTF16_STRING = atoms [off++]; + RICHTEXTFORMAT = atoms [off++]; + TARGETS = atoms [off++]; + AsyncAtom = atoms [off++]; + PostAtom = atoms [off++]; + HoverState.Atom = atoms [off++]; + + //DIB = (IntPtr)Atom.XA_PIXMAP; + _NET_SYSTEM_TRAY_S = XInternAtom (DisplayHandle, "_NET_SYSTEM_TRAY_S" + ScreenNo.ToString(), false); + } + + void GetSystrayManagerWindow() { + XGrabServer(DisplayHandle); + SystrayMgrWindow = XGetSelectionOwner(DisplayHandle, _NET_SYSTEM_TRAY_S); + XUngrabServer(DisplayHandle); + XFlush(DisplayHandle); + } + + void SendNetWMMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) { + SendNetWMMessage (window, message_type, l0, l1, l2, IntPtr.Zero); + } + + void SendNetWMMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2, IntPtr l3) { + XEvent xev; + + xev = new XEvent(); + xev.ClientMessageEvent.type = XEventName.ClientMessage; + xev.ClientMessageEvent.send_event = true; + xev.ClientMessageEvent.window = window; + xev.ClientMessageEvent.message_type = message_type; + xev.ClientMessageEvent.format = 32; + xev.ClientMessageEvent.ptr1 = l0; + xev.ClientMessageEvent.ptr2 = l1; + xev.ClientMessageEvent.ptr3 = l2; + xev.ClientMessageEvent.ptr4 = l3; + XSendEvent(DisplayHandle, RootWindow, false, new IntPtr ((int) (EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask)), ref xev); + } + + void SendNetClientMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) { + XEvent xev; + + xev = new XEvent(); + xev.ClientMessageEvent.type = XEventName.ClientMessage; + xev.ClientMessageEvent.send_event = true; + xev.ClientMessageEvent.window = window; + xev.ClientMessageEvent.message_type = message_type; + xev.ClientMessageEvent.format = 32; + xev.ClientMessageEvent.ptr1 = l0; + xev.ClientMessageEvent.ptr2 = l1; + xev.ClientMessageEvent.ptr3 = l2; + XSendEvent(DisplayHandle, window, false, new IntPtr ((int)EventMask.NoEventMask), ref xev); + } + + // For WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN, WM_XBUTTONDOWN + // WM_CREATE and WM_DESTROY causes + void SendParentNotify(IntPtr child, Msg cause, int x, int y) + { + Hwnd hwnd; + + if (child == IntPtr.Zero) { + return; + } + + hwnd = Hwnd.GetObjectFromWindow (child); + + if (hwnd == null) { + return; + } + + if (hwnd.Handle == IntPtr.Zero) { + return; + } + + if (ExStyleSet ((int) hwnd.initial_ex_style, WindowExStyles.WS_EX_NOPARENTNOTIFY)) { + return; + } + + if (hwnd.Parent == null) { + return; + } + + if (hwnd.Parent.Handle == IntPtr.Zero) { + return; + } + + if (cause == Msg.WM_CREATE || cause == Msg.WM_DESTROY) { + SendMessage(hwnd.Parent.Handle, Msg.WM_PARENTNOTIFY, Widget.MakeParam((int)cause, 0), child); + } else { + SendMessage(hwnd.Parent.Handle, Msg.WM_PARENTNOTIFY, Widget.MakeParam((int)cause, 0), Widget.MakeParam(x, y)); + } + + SendParentNotify (hwnd.Parent.Handle, cause, x, y); + } + + bool StyleSet (int s, WindowStyles ws) + { + return (s & (int)ws) == (int)ws; + } + + bool ExStyleSet (int ex, WindowExStyles exws) + { + return (ex & (int)exws) == (int)exws; + } + + internal static Rectangle TranslateClientRectangleToXClientRectangle (Hwnd hwnd) + { + return TranslateClientRectangleToXClientRectangle (hwnd, Widget.FromHandle (hwnd.Handle)); + } + + internal static Rectangle TranslateClientRectangleToXClientRectangle (Hwnd hwnd, Widget ctrl) + { + /* + * If this is a form with no window manager, X is handling all the border and caption painting + * so remove that from the area (since the area we set of the window here is the part of the window + * we're painting in only) + */ + Rectangle rect = hwnd.ClientRect; + Form form = ctrl as Form; + CreateParams cp = null; + + if (form != null) + cp = form.GetCreateParams (); + + if (form != null && (form.window_manager == null && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) { + Hwnd.Borders borders = Hwnd.GetBorders (cp, null); + Rectangle xrect = rect; + + xrect.Y -= borders.top; + xrect.X -= borders.left; + xrect.Width += borders.left + borders.right; + xrect.Height += borders.top + borders.bottom; + + rect = xrect; + } + + if (rect.Width < 1 || rect.Height < 1) { + rect.Width = 1; + rect.Height = 1; + rect.X = -5; + rect.Y = -5; + } + + return rect; + } + + internal static Size TranslateWindowSizeToXWindowSize (CreateParams cp) + { + return TranslateWindowSizeToXWindowSize (cp, new Size (cp.Width, cp.Height)); + } + + internal static Size TranslateWindowSizeToXWindowSize (CreateParams cp, Size size) + { + /* + * If this is a form with no window manager, X is handling all the border and caption painting + * so remove that from the area (since the area we set of the window here is the part of the window + * we're painting in only) + */ + Form form = cp.control as Form; + if (form != null && (form.window_manager == null && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) { + Hwnd.Borders borders = Hwnd.GetBorders (cp, null); + Size xrect = size; + + xrect.Width -= borders.left + borders.right; + xrect.Height -= borders.top + borders.bottom; + + size = xrect; + } + if (size.Height == 0) + size.Height = 1; + if (size.Width == 0) + size.Width = 1; + return size; + } + + internal static Size TranslateXWindowSizeToWindowSize (CreateParams cp, int xWidth, int xHeight) + { + /* + * If this is a form with no window manager, X is handling all the border and caption painting + * so remove that from the area (since the area we set of the window here is the part of the window + * we're painting in only) + */ + Size rect = new Size (xWidth, xHeight); + Form form = cp.control as Form; + if (form != null && (form.window_manager == null && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) { + Hwnd.Borders borders = Hwnd.GetBorders (cp, null); + Size xrect = rect; + + xrect.Width += borders.left + borders.right; + xrect.Height += borders.top + borders.bottom; + + rect = xrect; + } + return rect; + } + + internal static Point GetTopLevelWindowLocation (Hwnd hwnd) + { + IntPtr dummy; + int x, y; + Hwnd.Borders frame; + + XTranslateCoordinates (DisplayHandle, hwnd.whole_window, RootWindow, 0, 0, out x, out y, out dummy); + frame = FrameExtents (hwnd.whole_window); + + x -= frame.left; + y -= frame.top; + + return new Point (x, y); + } + + void DeriveStyles(int Style, int ExStyle, out FormBorderStyle border_style, out bool border_static, out TitleStyle title_style, out int caption_height, out int tool_caption_height) { + + caption_height = 0; + tool_caption_height = 19; + border_static = false; + + if (StyleSet (Style, WindowStyles.WS_CHILD)) { + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_CLIENTEDGE)) { + border_style = FormBorderStyle.Fixed3D; + } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_STATICEDGE)) { + border_style = FormBorderStyle.Fixed3D; + border_static = true; + } else if (!StyleSet (Style, WindowStyles.WS_BORDER)) { + border_style = FormBorderStyle.None; + } else { + border_style = FormBorderStyle.FixedSingle; + } + title_style = TitleStyle.None; + + if (StyleSet (Style, WindowStyles.WS_CAPTION)) { + caption_height = 19; + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + title_style = TitleStyle.Tool; + } else { + title_style = TitleStyle.Normal; + } + } + + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_MDICHILD)) { + caption_height = 19; + + if (StyleSet (Style, WindowStyles.WS_OVERLAPPEDWINDOW) || + ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + border_style = (FormBorderStyle) 0xFFFF; + } else { + border_style = FormBorderStyle.None; + } + } + + } else { + title_style = TitleStyle.None; + if (StyleSet (Style, WindowStyles.WS_CAPTION)) { + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + title_style = TitleStyle.Tool; + } else { + title_style = TitleStyle.Normal; + } + } + + border_style = FormBorderStyle.None; + + if (StyleSet (Style, WindowStyles.WS_THICKFRAME)) { + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + border_style = FormBorderStyle.SizableToolWindow; + } else { + border_style = FormBorderStyle.Sizable; + } + } else { + if (StyleSet (Style, WindowStyles.WS_CAPTION)) { + if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_CLIENTEDGE)) { + border_style = FormBorderStyle.Fixed3D; + } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_STATICEDGE)) { + border_style = FormBorderStyle.Fixed3D; + border_static = true; + } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_DLGMODALFRAME)) { + border_style = FormBorderStyle.FixedDialog; + } else if (ExStyleSet (ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + border_style = FormBorderStyle.FixedToolWindow; + } else if (StyleSet (Style, WindowStyles.WS_BORDER)) { + border_style = FormBorderStyle.FixedSingle; + } + } else { + if (StyleSet (Style, WindowStyles.WS_BORDER)) { + border_style = FormBorderStyle.FixedSingle; + } + } + } + } + } + + void SetHwndStyles(Hwnd hwnd, CreateParams cp) { + DeriveStyles(cp.Style, cp.ExStyle, out hwnd.border_style, out hwnd.border_static, out hwnd.title_style, out hwnd.caption_height, out hwnd.tool_caption_height); + } + + void SetWMStyles(Hwnd hwnd, CreateParams cp) { + MotifWmHints mwmHints; + MotifFunctions functions; + MotifDecorations decorations; + int[] atoms; + int atom_count; + Rectangle client_rect; + Form form; + IntPtr window_type; + bool hide_from_taskbar; + IntPtr transient_for_parent; + + // Windows we manage ourselves don't need WM window styles. + if (cp.HasWindowManager && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) { + return; + } + + atoms = new int[8]; + mwmHints = new MotifWmHints(); + functions = 0; + decorations = 0; + window_type = _NET_WM_WINDOW_TYPE_NORMAL; + transient_for_parent = IntPtr.Zero; + + mwmHints.flags = (IntPtr)(MotifFlags.Functions | MotifFlags.Decorations); + mwmHints.functions = (IntPtr)0; + mwmHints.decorations = (IntPtr)0; + + form = cp.control as Form; + + if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + /* tool windows get no window manager + decorations. + */ + + /* just because the window doesn't get any decorations doesn't + mean we should disable the functions. for instance, without + MotifFunctions.Maximize, changing the windowstate to Maximized + is ignored by metacity. */ + functions |= MotifFunctions.Move | MotifFunctions.Resize | MotifFunctions.Minimize | MotifFunctions.Maximize; + } else if (form != null && form.FormBorderStyle == FormBorderStyle.None) { + /* allow borderless window to be maximized */ + functions |= MotifFunctions.All | MotifFunctions.Resize; + } else { + if (StyleSet (cp.Style, WindowStyles.WS_CAPTION)) { + functions |= MotifFunctions.Move; + decorations |= MotifDecorations.Title | MotifDecorations.Menu; + } + + if (StyleSet (cp.Style, WindowStyles.WS_THICKFRAME)) { + functions |= MotifFunctions.Move | MotifFunctions.Resize; + decorations |= MotifDecorations.Border | MotifDecorations.ResizeH; + } + + if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZEBOX)) { + functions |= MotifFunctions.Minimize; + decorations |= MotifDecorations.Minimize; + } + + if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZEBOX)) { + functions |= MotifFunctions.Maximize; + decorations |= MotifDecorations.Maximize; + } + + if (StyleSet (cp.Style, WindowStyles.WS_SIZEBOX)) { + functions |= MotifFunctions.Resize; + decorations |= MotifDecorations.ResizeH; + } + + if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_DLGMODALFRAME)) { + decorations |= MotifDecorations.Border; + } + + if (StyleSet (cp.Style, WindowStyles.WS_BORDER)) { + decorations |= MotifDecorations.Border; + } + + if (StyleSet (cp.Style, WindowStyles.WS_DLGFRAME)) { + decorations |= MotifDecorations.Border; + } + + if (StyleSet (cp.Style, WindowStyles.WS_SYSMENU)) { + functions |= MotifFunctions.Close; + } + else { + functions &= ~(MotifFunctions.Maximize | MotifFunctions.Minimize | MotifFunctions.Close); + decorations &= ~(MotifDecorations.Menu | MotifDecorations.Maximize | MotifDecorations.Minimize); + if (cp.Caption == "") { + functions &= ~MotifFunctions.Move; + decorations &= ~(MotifDecorations.Title | MotifDecorations.ResizeH); + } + } + } + + if ((functions & MotifFunctions.Resize) == 0) { + hwnd.fixed_size = true; + Rectangle fixed_rectangle = new Rectangle (cp.X, cp.Y, cp.Width, cp.Height); + SetWindowMinMax(hwnd.Handle, fixed_rectangle, fixed_rectangle.Size, fixed_rectangle.Size, cp); + } else { + hwnd.fixed_size = false; + } + + mwmHints.functions = (IntPtr)functions; + mwmHints.decorations = (IntPtr)decorations; + + DriverDebug ("SetWMStyles ({0}, {1}) functions = {2}, decorations = {3}", hwnd, cp, functions, decorations); + + if (cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) { + // needed! map toolwindows to _NET_WM_WINDOW_TYPE_UTILITY to make newer metacity versions happy + // and get those windows in front of their parents + window_type = _NET_WM_WINDOW_TYPE_UTILITY; + } else { + window_type = _NET_WM_WINDOW_TYPE_NORMAL; + } + + if (!cp.IsSet (WindowExStyles.WS_EX_APPWINDOW)) { + hide_from_taskbar = true; + } else if (cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW) && form != null && form.Parent != null && !form.ShowInTaskbar) { + hide_from_taskbar = true; + } else { + hide_from_taskbar = false; + } + + if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + if (form != null && !hwnd.reparented) { + if (form.Owner != null && form.Owner.Handle != IntPtr.Zero) { + Hwnd owner_hwnd = Hwnd.ObjectFromHandle (form.Owner.Handle); + if (owner_hwnd != null) + transient_for_parent = owner_hwnd.whole_window; + } + } + } + if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && (hwnd.parent != null) && (hwnd.parent.whole_window != IntPtr.Zero)) { + transient_for_parent = hwnd.parent.whole_window; + } + + FormWindowState current_state = GetWindowState (hwnd.Handle); + if (current_state == (FormWindowState)(-1)) + current_state = FormWindowState.Normal; + + client_rect = TranslateClientRectangleToXClientRectangle (hwnd); + + lock (XlibLock) { + atom_count = 0; + + atoms [0] = window_type.ToInt32 (); + XChangeProperty (DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1); + + XChangeProperty(DisplayHandle, hwnd.whole_window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropertyMode.Replace, ref mwmHints, 5); + + if (transient_for_parent != IntPtr.Zero) { + XSetTransientForHint (DisplayHandle, hwnd.whole_window, transient_for_parent); + } + + MoveResizeWindow(DisplayHandle, hwnd.client_window, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height); + + if (hide_from_taskbar) { + /* this line keeps the window from showing up in gnome's taskbar */ + atoms[atom_count++] = _NET_WM_STATE_SKIP_TASKBAR.ToInt32(); + } + /* we need to add these atoms in the + * event we're maximized, since we're + * replacing the existing + * _NET_WM_STATE here. If we don't + * add them, future calls to + * GetWindowState will return Normal + * for a window which is maximized. */ + if (current_state == FormWindowState.Maximized) { + atoms[atom_count++] = _NET_WM_STATE_MAXIMIZED_HORZ.ToInt32(); + atoms[atom_count++] = _NET_WM_STATE_MAXIMIZED_VERT.ToInt32(); + } + + if (form != null && form.Modal) { + atoms[atom_count++] = _NET_WM_STATE_MODAL.ToInt32 (); + } + + XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, atom_count); + + atom_count = 0; + IntPtr[] atom_ptrs = new IntPtr[2]; + atom_ptrs[atom_count++] = WM_DELETE_WINDOW; + if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_CONTEXTHELP)) { + atom_ptrs[atom_count++] = _NET_WM_CONTEXT_HELP; + } + + XSetWMProtocols(DisplayHandle, hwnd.whole_window, atom_ptrs, atom_count); + } + } + + void SetIcon(Hwnd hwnd, Icon icon) + { + if (icon == null) { + // XXX + + // This really needs to do whatever it + // takes to remove the window manager + // menu, not just delete the ICON + // property. This will cause metacity + // to use the "no icon set" icon, and + // we'll still have an icon. + XDeleteProperty (DisplayHandle, hwnd.whole_window, _NET_WM_ICON); + } + else { + Bitmap bitmap; + int size; + IntPtr[] data; + int index; + + bitmap = icon.ToBitmap(); + index = 0; + size = bitmap.Width * bitmap.Height + 2; + data = new IntPtr[size]; + + data[index++] = (IntPtr)bitmap.Width; + data[index++] = (IntPtr)bitmap.Height; + + for (int y = 0; y < bitmap.Height; y++) { + for (int x = 0; x < bitmap.Width; x++) { + data[index++] = (IntPtr)bitmap.GetPixel (x, y).ToArgb (); + } + } + + XChangeProperty (DisplayHandle, hwnd.whole_window, + _NET_WM_ICON, (IntPtr)Atom.XA_CARDINAL, 32, + PropertyMode.Replace, data, size); + } + } + + void WakeupMain () { + try { + wake.Send (new byte [] { 0xFF }); + } catch (SocketException ex) { + if (ex.SocketErrorCode != SocketError.WouldBlock) { + throw; + } + } + } + + XEventQueue ThreadQueue(Thread thread) { + XEventQueue queue; + + queue = (XEventQueue)MessageQueues[thread]; + if (queue == null) { + queue = new XEventQueue(thread); + MessageQueues[thread] = queue; + } + + return queue; + } + + void TranslatePropertyToClipboard(IntPtr property) { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + + Clipboard.Item = null; + + XGetWindowProperty(DisplayHandle, FosterParent, property, IntPtr.Zero, new IntPtr (0x7fffffff), true, (IntPtr)Atom.AnyPropertyType, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + + if ((long)nitems > 0) { + if (property == (IntPtr)Atom.XA_STRING) { + // Xamarin-5116: PtrToStringAnsi expects to get UTF-8, but we might have + // Latin-1 instead, in which case it will return null. + var s = Marshal.PtrToStringAnsi (prop); + if (string.IsNullOrEmpty (s)) { + var sb = new StringBuilder (); + for (int i = 0; i < (int)nitems; i++) { + var b = Marshal.ReadByte (prop, i); + sb.Append ((char)b); + } + s = sb.ToString (); + } + // Some X managers/apps pass unicode chars as escaped strings, so + // we may need to unescape them. + Clipboard.Item = UnescapeUnicodeFromAnsi (s); + } else if (property == (IntPtr)Atom.XA_BITMAP) { + // FIXME - convert bitmap to image + } else if (property == (IntPtr)Atom.XA_PIXMAP) { + // FIXME - convert pixmap to image + } else if (property == OEMTEXT) { + Clipboard.Item = UnescapeUnicodeFromAnsi (Marshal.PtrToStringAnsi(prop)); + } else if (property == UTF8_STRING) { + byte [] buffer = new byte [(int)nitems]; + for (int i = 0; i < (int)nitems; i++) + buffer [i] = Marshal.ReadByte (prop, i); + Clipboard.Item = Encoding.UTF8.GetString (buffer); + } else if (property == UTF16_STRING) { + byte [] buffer = new byte [(int)nitems]; + for (int i = 0; i < (int)nitems; i++) + buffer [i] = Marshal.ReadByte (prop, i); + Clipboard.Item = Encoding.Unicode.GetString (buffer); + } else if (property == RICHTEXTFORMAT) + Clipboard.Item = Marshal.PtrToStringAnsi(prop); + else if (DataFormats.ContainsFormat (property.ToInt32 ())) { + if (DataFormats.GetFormat (property.ToInt32 ()).is_serializable) { + MemoryStream memory_stream = new MemoryStream ((int)nitems); + for (int i = 0; i < (int)nitems; i++) + memory_stream.WriteByte (Marshal.ReadByte (prop, i)); + + memory_stream.Position = 0; + BinaryFormatter formatter = new BinaryFormatter (); + Clipboard.Item = formatter.Deserialize (memory_stream); + memory_stream.Close (); + } + } + + XFree(prop); + } + } + + string UnescapeUnicodeFromAnsi (string value) + { + if (value == null || value.IndexOf ("\\u") == -1) + return value; + + StringBuilder sb = new StringBuilder (value.Length); + int start, pos; + + start = pos = 0; + while (start < value.Length) { + pos = value.IndexOf ("\\u", start); + if (pos == -1) + break; + + sb.Append (value, start, pos - start); + pos += 2; + start = pos; + + int length = 0; + while (pos < value.Length && length < 4) { + if (!ValidHexDigit (value [pos])) + break; + length++; + pos++; + } + + int res; + if (!Int32.TryParse (value.Substring (start, length), System.Globalization.NumberStyles.HexNumber, + null, out res)) + return value; // Error, return the unescaped original value. + + sb.Append ((char)res); + start = pos; + } + + // Append any remaining data. + if (start < value.Length) + sb.Append (value, start, value.Length - start); + + return sb.ToString (); + } + + private static bool ValidHexDigit (char e) + { + return Char.IsDigit (e) || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f'); + } + + void AddExpose (Hwnd hwnd, bool client, int x, int y, int width, int height) { + // Don't waste time + if ((hwnd == null) || (x > hwnd.Width) || (y > hwnd.Height) || ((x + width) < 0) || ((y + height) < 0)) { + return; + } + + // Keep the invalid area as small as needed + if ((x + width) > hwnd.width) { + width = hwnd.width - x; + } + + if ((y + height) > hwnd.height) { + height = hwnd.height - y; + } + + if (client) { + hwnd.AddInvalidArea(x, y, width, height); + if (!hwnd.expose_pending) { + if (!hwnd.nc_expose_pending) { + hwnd.Queue.Paint.Enqueue(hwnd); + } + hwnd.expose_pending = true; + } + } else { + hwnd.AddNcInvalidArea (x, y, width, height); + + if (!hwnd.nc_expose_pending) { + if (!hwnd.expose_pending) { + hwnd.Queue.Paint.Enqueue(hwnd); + } + hwnd.nc_expose_pending = true; + } + } + } + + static Hwnd.Borders FrameExtents (IntPtr window) + { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + Hwnd.Borders rect = new Hwnd.Borders (); + + XGetWindowProperty (DisplayHandle, window, _NET_FRAME_EXTENTS, IntPtr.Zero, new IntPtr (16), false, (IntPtr)Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + if (prop != IntPtr.Zero) { + if (nitems.ToInt32 () == 4) { + rect.left = Marshal.ReadInt32 (prop, 0); + rect.right = Marshal.ReadInt32 (prop, IntPtr.Size); + rect.top = Marshal.ReadInt32 (prop, 2 * IntPtr.Size); + rect.bottom = Marshal.ReadInt32 (prop, 3 * IntPtr.Size); + } + XFree (prop); + } + + return rect; + } + + void AddConfigureNotify (XEvent xevent) { + Hwnd hwnd; + + hwnd = Hwnd.GetObjectFromWindow(xevent.ConfigureEvent.window); + + // Don't waste time + if (hwnd == null || hwnd.zombie) { + return; + } + if ((xevent.ConfigureEvent.window == hwnd.whole_window)/* && (xevent.ConfigureEvent.window == xevent.ConfigureEvent.xevent)*/) { + if (hwnd.parent == null) { + // The location given by the event is not reliable between different wm's, + // so use an alternative way of getting it. + Point location = GetTopLevelWindowLocation (hwnd); + hwnd.x = location.X; + hwnd.y = location.Y; + } + + // XXX this sucks. this isn't thread safe + Widget ctrl = Widget.FromHandle (hwnd.Handle); + Size TranslatedSize; + if (ctrl != null) { + TranslatedSize = TranslateXWindowSizeToWindowSize (ctrl.GetCreateParams (), xevent.ConfigureEvent.width, xevent.ConfigureEvent.height); + } else { + TranslatedSize = new Size (xevent.ConfigureEvent.width, xevent.ConfigureEvent.height); + } + hwnd.width = TranslatedSize.Width; + hwnd.height = TranslatedSize.Height; + hwnd.ClientRect = Rectangle.Empty; + + DriverDebug ("AddConfigureNotify (hwnd.Handle = {1}, final hwnd.rect = {0}, reported rect={2})", + new Rectangle (hwnd.x, hwnd.y, hwnd.width, hwnd.height), hwnd.Handle, + new Rectangle (xevent.ConfigureEvent.x, xevent.ConfigureEvent.y, xevent.ConfigureEvent.width, xevent.ConfigureEvent.width)); + lock (hwnd.configure_lock) { + if (!hwnd.configure_pending) { + hwnd.Queue.EnqueueLocked (xevent); + hwnd.configure_pending = true; + } + } + } + // We drop configure events for Client windows + } + + void ShowCaret() { + if ((Caret.gc == IntPtr.Zero) || Caret.On) { + return; + } + Caret.On = true; + + lock (XlibLock) { + XDrawLine(DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height); + } + } + + void HideCaret() { + if ((Caret.gc == IntPtr.Zero) || !Caret.On) { + return; + } + Caret.On = false; + + lock (XlibLock) { + XDrawLine(DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height); + } + } + + int NextTimeout (ArrayList timers, DateTime now) { + int timeout = 0; + + foreach (Timer timer in timers) { + int next = (int) (timer.Expires - now).TotalMilliseconds; + if (next < 0) { + return 0; // Have a timer that has already expired + } + + if (next < timeout) { + timeout = next; + } + } + if (timeout < Timer.Minimum) { + timeout = Timer.Minimum; + } + + if (timeout > 1000) + timeout = 1000; + return timeout; + } + + void CheckTimers (ArrayList timers, DateTime now) { + int count; + + count = timers.Count; + + if (count == 0) + return; + + for (int i = 0; i < timers.Count; i++) { + Timer timer; + + timer = (Timer) timers [i]; + + if (timer.Enabled && timer.Expires <= now && !timer.Busy) { + // Timer ticks: + // - Before MainForm.OnLoad if DoEvents () is called. + // - After MainForm.OnLoad if not. + // + if (in_doevents || + (Application.MWFThread.Current.Context != null && + (Application.MWFThread.Current.Context.MainForm == null || + Application.MWFThread.Current.Context.MainForm.IsLoaded))) { + timer.Busy = true; + timer.Update (now); + timer.FireTick (); + timer.Busy = false; + } + } + } + } + + void WaitForHwndMessage (Hwnd hwnd, Msg message) { + WaitForHwndMessage (hwnd, message, false); + + } + + void WaitForHwndMessage (Hwnd hwnd, Msg message, bool process) { + MSG msg = new MSG (); + XEventQueue queue; + + queue = ThreadQueue(Thread.CurrentThread); + + queue.DispatchIdle = false; + + bool done = false; + string key = hwnd.Handle + ":" + message; + if (!messageHold.ContainsKey (key)) + messageHold.Add (key, 1); + else + messageHold[key] = ((int)messageHold[key]) + 1; + + + do { + + DebugHelper.WriteLine ("Waiting for message " + message + " on hwnd " + String.Format("0x{0:x}", hwnd.Handle.ToInt32 ())); + DebugHelper.Indent (); + + if (PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) { + if ((Msg)msg.message == Msg.WM_QUIT) { + PostQuitMessage (0); + done = true; + } + else { + + DebugHelper.WriteLine ("PeekMessage got " + msg); + + if (msg.hwnd == hwnd.Handle) { + if ((Msg)msg.message == message) { + if (process) { + TranslateMessage (ref msg); + DispatchMessage (ref msg); + } + break; + } + else if ((Msg)msg.message == Msg.WM_DESTROY) + done = true; + } + + TranslateMessage (ref msg); + DispatchMessage (ref msg); + } + } + + done = !messageHold.ContainsKey (key) || ((int)messageHold[key] < 1) || done; + } while (!done); + + messageHold.Remove (key); + + DebugHelper.Unindent (); + DebugHelper.WriteLine ("Finished waiting for " + key); + + queue.DispatchIdle = true; + + } + + void MapWindow(Hwnd hwnd, WindowType windows) { + if (!hwnd.mapped) { + Form f = Widget.FromHandle(hwnd.Handle) as Form; + if (f != null) { + if (f.WindowState == FormWindowState.Normal) { + f.waiting_showwindow = true; + SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero); + } + } + + // it's possible that our Hwnd is no + // longer valid after making that + // SendMessage call, so check here. + if (hwnd.zombie) + return; + + if (hwnd.topmost) { + // Most window managers will respect the _NET_WM_STATE property. + // If not, use XMapRaised to map the window at the top level as + // a last ditch effort. + if ((windows & WindowType.Whole) != 0) { + XMapRaised(DisplayHandle, hwnd.whole_window); + } + if ((windows & WindowType.Client) != 0) { + XMapRaised(DisplayHandle, hwnd.client_window); + } + } else { + if ((windows & WindowType.Whole) != 0) { + XMapWindow(DisplayHandle, hwnd.whole_window); + } + if ((windows & WindowType.Client) != 0) { + XMapWindow(DisplayHandle, hwnd.client_window); + } + } + + hwnd.mapped = true; + + if (f != null) { + if (f.waiting_showwindow) { + WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW); + CreateParams cp = f.GetCreateParams(); + if (!ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_MDICHILD) && + !StyleSet (cp.Style, WindowStyles.WS_CHILD)) { + WaitForHwndMessage (hwnd, Msg.WM_ACTIVATE, true); + } + } + } + } + } + + void UnmapWindow(Hwnd hwnd, WindowType windows) { + if (hwnd.mapped) { + Form f = null; + if (Widget.FromHandle(hwnd.Handle) is Form) { + f = Widget.FromHandle(hwnd.Handle) as Form; + if (f.WindowState == FormWindowState.Normal) { + f.waiting_showwindow = true; + SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, IntPtr.Zero, IntPtr.Zero); + } + } + + // it's possible that our Hwnd is no + // longer valid after making that + // SendMessage call, so check here. + // FIXME: it is likely wrong, as it has already sent WM_SHOWWINDOW + if (hwnd.zombie) + return; + + if ((windows & WindowType.Client) != 0) { + XUnmapWindow(DisplayHandle, hwnd.client_window); + } + if ((windows & WindowType.Whole) != 0) { + XUnmapWindow(DisplayHandle, hwnd.whole_window); + } + + hwnd.mapped = false; + + if (f != null) { + if (f.waiting_showwindow) { + WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW); + CreateParams cp = f.GetCreateParams(); + if (!ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_MDICHILD) && + !StyleSet (cp.Style, WindowStyles.WS_CHILD)) { + WaitForHwndMessage (hwnd, Msg.WM_ACTIVATE, true); + } + } + } + } + } + + void UpdateMessageQueue (XEventQueue queue) { + UpdateMessageQueue(queue, true); + } + + void UpdateMessageQueue (XEventQueue queue, bool allowIdle) { + DateTime now; + int pending; + Hwnd hwnd; + + now = DateTime.UtcNow; + + lock (XlibLock) { + pending = XPending (DisplayHandle); + } + + if (pending == 0 && allowIdle) { + if ((queue == null || queue.DispatchIdle) && Idle != null) { + Idle (this, EventArgs.Empty); + } + + lock (XlibLock) { + pending = XPending (DisplayHandle); + } + } + + if (pending == 0) { + int timeout = 0; + + if (queue != null) { + if (queue.Paint.Count > 0) + return; + + timeout = NextTimeout (queue.timer_list, now); + } + + if (timeout > 0) { + #if __MonoCS__ + int length = pollfds.Length - 1; + lock (wake_waiting_lock) { + if (wake_waiting == false) { + length ++; + wake_waiting = true; + } + } + + Syscall.poll (pollfds, (uint)length, timeout); + // Clean out buffer, so we're not busy-looping on the same data + if (length == pollfds.Length) { + if (pollfds[1].revents != 0) + wake_receive.Receive(network_buffer, 0, 1, SocketFlags.None); + lock (wake_waiting_lock) { + wake_waiting = false; + } + } + #endif + lock (XlibLock) { + pending = XPending (DisplayHandle); + } + } + } + + if (queue != null) + CheckTimers (queue.timer_list, now); + + while (true) { + XEvent xevent = new XEvent (); + + lock (XlibLock) { + if (XPending (DisplayHandle) == 0) + break; + + XNextEvent (DisplayHandle, ref xevent); + + if (xevent.AnyEvent.type == XEventName.KeyPress || + xevent.AnyEvent.type == XEventName.KeyRelease) { + // PreFilter() handles "shift key state updates. + Keyboard.PreFilter (xevent); + if (XFilterEvent (ref xevent, Keyboard.ClientWindow)) { + // probably here we could raise WM_IME_KEYDOWN and + // WM_IME_KEYUP, but I'm not sure it is worthy. + continue; + } + } + else if (XFilterEvent (ref xevent, IntPtr.Zero)) + continue; + } + + hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window); + if (hwnd == null) + continue; + + DebugHelper.WriteLine ("UpdateMessageQueue got Event: " + xevent.ToString ()); + + switch (xevent.type) { + case XEventName.Expose: + AddExpose (hwnd, xevent.ExposeEvent.window == hwnd.ClientWindow, xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height); + break; + + case XEventName.SelectionClear: { + // Should we do something? + break; + } + + case XEventName.SelectionRequest: { + if (Dnd.HandleSelectionRequestEvent (ref xevent)) + break; + XEvent sel_event; + + sel_event = new XEvent(); + sel_event.SelectionEvent.type = XEventName.SelectionNotify; + sel_event.SelectionEvent.send_event = true; + sel_event.SelectionEvent.display = DisplayHandle; + sel_event.SelectionEvent.selection = xevent.SelectionRequestEvent.selection; + sel_event.SelectionEvent.target = xevent.SelectionRequestEvent.target; + sel_event.SelectionEvent.requestor = xevent.SelectionRequestEvent.requestor; + sel_event.SelectionEvent.time = xevent.SelectionRequestEvent.time; + sel_event.SelectionEvent.property = IntPtr.Zero; + + IntPtr format_atom = xevent.SelectionRequestEvent.target; + + // Seems that some apps support asking for supported types + if (format_atom == TARGETS) { + int[] atoms; + int atom_count; + + atoms = new int[5]; + atom_count = 0; + + if (Clipboard.IsSourceText) { + atoms[atom_count++] = (int)Atom.XA_STRING; + atoms[atom_count++] = (int)OEMTEXT; + atoms[atom_count++] = (int)UTF8_STRING; + atoms[atom_count++] = (int)UTF16_STRING; + atoms[atom_count++] = (int)RICHTEXTFORMAT; + } else if (Clipboard.IsSourceImage) { + atoms[atom_count++] = (int)Atom.XA_PIXMAP; + atoms[atom_count++] = (int)Atom.XA_BITMAP; + } else { + // FIXME - handle other types + } + + XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, + (IntPtr)xevent.SelectionRequestEvent.target, 32, PropertyMode.Replace, atoms, atom_count); + sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property; + } else if (format_atom == (IntPtr)RICHTEXTFORMAT) { + string rtf_text = Clipboard.GetRtfText (); + if (rtf_text != null) { + // The RTF spec mentions that ascii is enough to contain it + Byte [] bytes = Encoding.ASCII.GetBytes (rtf_text); + int buflen = bytes.Length; + IntPtr buffer = Marshal.AllocHGlobal (buflen); + + for (int i = 0; i < buflen; i++) + Marshal.WriteByte (buffer, i, bytes[i]); + + XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, + (IntPtr)xevent.SelectionRequestEvent.target, 8, PropertyMode.Replace, buffer, buflen); + sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property; + Marshal.FreeHGlobal(buffer); + } + } else if (Clipboard.IsSourceText && + (format_atom == (IntPtr)Atom.XA_STRING + || format_atom == OEMTEXT + || format_atom == UTF16_STRING + || format_atom == UTF8_STRING)) { + IntPtr buffer = IntPtr.Zero; + int buflen; + Encoding encoding = null; + + buflen = 0; + + // Select an encoding depending on the target + IntPtr target_atom = xevent.SelectionRequestEvent.target; + if (target_atom == (IntPtr)Atom.XA_STRING || target_atom == OEMTEXT) + // FIXME - EOMTEXT should encode into ISO2022 + encoding = Encoding.ASCII; + else if (target_atom == UTF16_STRING) + encoding = Encoding.Unicode; + else if (target_atom == UTF8_STRING) + encoding = Encoding.UTF8; + + Byte [] bytes; + + bytes = encoding.GetBytes (Clipboard.GetPlainText ()); + buffer = Marshal.AllocHGlobal (bytes.Length); + buflen = bytes.Length; + + for (int i = 0; i < buflen; i++) + Marshal.WriteByte (buffer, i, bytes [i]); + + if (buffer != IntPtr.Zero) { + XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, 8, PropertyMode.Replace, buffer, buflen); + sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property; + Marshal.FreeHGlobal(buffer); + } + } else if (Clipboard.GetSource (format_atom.ToInt32 ()) != null) { // check if we have an available value of this format + if (DataFormats.GetFormat (format_atom.ToInt32 ()).is_serializable) { + object serializable = Clipboard.GetSource (format_atom.ToInt32 ()); + + BinaryFormatter formatter = new BinaryFormatter (); + MemoryStream memory_stream = new MemoryStream (); + formatter.Serialize (memory_stream, serializable); + + int buflen = (int)memory_stream.Length; + IntPtr buffer = Marshal.AllocHGlobal (buflen); + memory_stream.Position = 0; + for (int i = 0; i < buflen; i++) + Marshal.WriteByte (buffer, i, (byte)memory_stream.ReadByte ()); + memory_stream.Close (); + + XChangeProperty (DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, + 8, PropertyMode.Replace, buffer, buflen); + sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property; + Marshal.FreeHGlobal (buffer); + } + + } else if (Clipboard.IsSourceImage) { + if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) { + // FIXME - convert image and store as property + } else if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) { + // FIXME - convert image and store as property + } + } + + XSendEvent(DisplayHandle, xevent.SelectionRequestEvent.requestor, false, new IntPtr ((int)EventMask.NoEventMask), ref sel_event); + break; + } + + case XEventName.SelectionNotify: { + if (Clipboard.Enumerating) { + Clipboard.Enumerating = false; + if (xevent.SelectionEvent.property != IntPtr.Zero) { + XDeleteProperty(DisplayHandle, FosterParent, (IntPtr)xevent.SelectionEvent.property); + if (!Clipboard.Formats.Contains(xevent.SelectionEvent.property)) { + Clipboard.Formats.Add(xevent.SelectionEvent.property); + DriverDebug("Got supported clipboard atom format: {0}", xevent.SelectionEvent.property); + } + } + } else if (Clipboard.Retrieving) { + Clipboard.Retrieving = false; + if (xevent.SelectionEvent.property != IntPtr.Zero) { + TranslatePropertyToClipboard(xevent.SelectionEvent.property); + } else { + Clipboard.ClearSources (); + Clipboard.Item = null; + } + } else { + Dnd.HandleSelectionNotifyEvent (ref xevent); + } + break; + } + + case XEventName.KeyRelease: + if (!detectable_key_auto_repeat && XPending (DisplayHandle) != 0) { + XEvent nextevent = new XEvent (); + + XPeekEvent (DisplayHandle, ref nextevent); + + if (nextevent.type == XEventName.KeyPress && + nextevent.KeyEvent.keycode == xevent.KeyEvent.keycode && + nextevent.KeyEvent.time == xevent.KeyEvent.time) { + continue; + } + } + goto case XEventName.KeyPress; + + case XEventName.MotionNotify: { + XEvent peek; + + /* we can't do motion compression across threads, so just punt if we don't match up */ + if (Thread.CurrentThread == hwnd.Queue.Thread && hwnd.Queue.Count > 0) { + peek = hwnd.Queue.Peek(); + if (peek.AnyEvent.type == XEventName.MotionNotify) { + continue; + } + } + goto case XEventName.KeyPress; + } + + case XEventName.KeyPress: + hwnd.Queue.EnqueueLocked (xevent); + /* Process KeyPresses immediately. Otherwise multiple Compose messages as a result of a + * single physical keypress are not processed correctly */ + return; + case XEventName.ButtonPress: + case XEventName.ButtonRelease: + case XEventName.EnterNotify: + case XEventName.LeaveNotify: + case XEventName.CreateNotify: + case XEventName.DestroyNotify: + case XEventName.FocusIn: + case XEventName.FocusOut: + case XEventName.ClientMessage: + case XEventName.ReparentNotify: + case XEventName.MapNotify: + case XEventName.UnmapNotify: + hwnd.Queue.EnqueueLocked (xevent); + break; + + case XEventName.ConfigureNotify: + AddConfigureNotify(xevent); + break; + + case XEventName.PropertyNotify: + DriverDebug ("UpdateMessageQueue (), got Event: {0}", xevent.ToString ()); + if (xevent.PropertyEvent.atom == _NET_ACTIVE_WINDOW) { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + IntPtr prev_active; + + prev_active = ActiveWindow; + XGetWindowProperty(DisplayHandle, RootWindow, _NET_ACTIVE_WINDOW, IntPtr.Zero, new IntPtr (1), false, (IntPtr)Atom.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + if (((long)nitems > 0) && (prop != IntPtr.Zero)) { + ActiveWindow = Hwnd.GetHandleFromWindow((IntPtr)Marshal.ReadInt32(prop)); + XFree(prop); + + DebugHelper.WriteLine ("PropertyNotify: _NET_ACTIVE_WINDOW: previous = 0x{0:x}, new = 0x{1:x}", prev_active.ToInt32 (), ActiveWindow.ToInt32 ()); + + if (prev_active != ActiveWindow) { + if (prev_active != IntPtr.Zero) { + PostMessage(prev_active, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero); + } + if (ActiveWindow != IntPtr.Zero) { + PostMessage(ActiveWindow, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_ACTIVE, IntPtr.Zero); + } + } + if (ModalWindows.Count == 0) { + break; + } else { + // Modality Handling + // + // If there is a modal window on the stack and the new active + // window is MWF window, but not the modal one and not a non-modal + // child of the modal one, switch back to the modal window. + // + // To identify if a non-modal form is child of a modal form + // we match their ApplicationContexts, which will be the same. + // This is because each modal form runs the loop with a + // new ApplicationContext, which is inherited by the non-modal + // forms. + + Form activeForm = Widget.FromHandle (ActiveWindow) as Form; + if (activeForm != null) { + Form modalForm = Widget.FromHandle ((IntPtr)ModalWindows.Peek()) as Form; + if (ActiveWindow != (IntPtr)ModalWindows.Peek() && + (modalForm == null || activeForm.context == modalForm.context)) { + Activate((IntPtr)ModalWindows.Peek()); + } + } + break; + } + } + } + else if (xevent.PropertyEvent.atom == _NET_WM_STATE) { + // invalidate our cache - we'll query again the next time someone does GetWindowState. + hwnd.cached_window_state = (FormWindowState)(-1); + PostMessage (hwnd.Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + } + break; + + } + } + } + + IntPtr GetMousewParam(int Delta) { + int result = 0; + + if ((MouseState & MouseButtons.Left) != 0) { + result |= (int)MsgButtons.MK_LBUTTON; + } + + if ((MouseState & MouseButtons.Middle) != 0) { + result |= (int)MsgButtons.MK_MBUTTON; + } + + if ((MouseState & MouseButtons.Right) != 0) { + result |= (int)MsgButtons.MK_RBUTTON; + } + + Keys mods = ModifierKeys; + if ((mods & Keys.Widget) != 0) { + result |= (int)MsgButtons.MK_CONTROL; + } + + if ((mods & Keys.Shift) != 0) { + result |= (int)MsgButtons.MK_SHIFT; + } + + result |= Delta << 16; + + return (IntPtr)result; + } + IntPtr XGetParent(IntPtr handle) { + IntPtr Root; + IntPtr Parent; + IntPtr Children; + int ChildCount; + + lock (XlibLock) { + XQueryTree(DisplayHandle, handle, out Root, out Parent, out Children, out ChildCount); + } + + if (Children!=IntPtr.Zero) { + lock (XlibLock) { + XFree(Children); + } + } + return Parent; + } + + int HandleError (IntPtr display, ref XErrorEvent error_event) + { + // we need to workaround a problem with the + // ordering of destruction of Drawables and + // Pictures that exists between cairo and + // RENDER on the server. + if (error_event.request_code == (XRequest)render_major_opcode + && error_event.minor_code == 7 /* X_RenderFreePicture from render.h */ + && error_event.error_code == render_first_error + 1 /* BadPicture from render.h */) { + return 0; + } + + if (ErrorExceptions) { + XUngrabPointer (display, IntPtr.Zero); + throw new XException (error_event.display, error_event.resourceid, + error_event.serial, error_event.error_code, + error_event.request_code, error_event.minor_code); + } else { + Console.WriteLine("X11 Error encountered: {0}{1}\n", + XException.GetMessage (error_event.display, error_event.resourceid, + error_event.serial, error_event.error_code, + error_event.request_code, error_event.minor_code), + Environment.StackTrace); + } + return 0; + } + + void AccumulateDestroyedHandles (Widget c, ArrayList list) + { + DebugHelper.Enter (); + if (c != null) { + + Widget[] Widgets = c.Widgets.GetAllWidgets (); + + DebugHelper.WriteLine ("Checking Widget:0x{0:x}", c.IsHandleCreated ? c.Handle.ToInt32() : 0); + + if (c.IsHandleCreated && !c.IsDisposed) { + Hwnd hwnd = Hwnd.ObjectFromHandle(c.Handle); + + DriverDebug (" + adding {0} to the list of zombie windows", XplatUI.Window (hwnd.Handle)); + DriverDebug (" + parent X window is {0:X}", XGetParent (hwnd.whole_window).ToInt32()); + + list.Add (hwnd); + CleanupCachedWindows (hwnd); + } + + for (int i = 0; i < Widgets.Length; i ++) { + AccumulateDestroyedHandles (Widgets[i], list); + } + } + DebugHelper.Leave (); + } + + void CleanupCachedWindows (Hwnd hwnd) + { + if (ActiveWindow == hwnd.Handle) { + SendMessage(hwnd.client_window, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero); + ActiveWindow = IntPtr.Zero; + } + + if (FocusWindow == hwnd.Handle) { + SendMessage(hwnd.client_window, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero); + FocusWindow = IntPtr.Zero; + } + + if (Grab.Hwnd == hwnd.Handle) { + Grab.Hwnd = IntPtr.Zero; + Grab.Confined = false; + } + + DestroyCaret (hwnd.Handle); + } + + void PerformNCCalc(Hwnd hwnd) { + XplatUIWin32.NCCALCSIZE_PARAMS ncp; + IntPtr ptr; + Rectangle rect; + + rect = new Rectangle (0, 0, hwnd.Width, hwnd.Height); + + ncp = new XplatUIWin32.NCCALCSIZE_PARAMS(); + ptr = Marshal.AllocHGlobal(Marshal.SizeOf(ncp)); + + ncp.rgrc1.left = rect.Left; + ncp.rgrc1.top = rect.Top; + ncp.rgrc1.right = rect.Right; + ncp.rgrc1.bottom = rect.Bottom; + + Marshal.StructureToPtr(ncp, ptr, true); + NativeWindow.WndProc(hwnd.client_window, Msg.WM_NCCALCSIZE, (IntPtr)1, ptr); + ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(ptr, typeof(XplatUIWin32.NCCALCSIZE_PARAMS)); + Marshal.FreeHGlobal(ptr); + + + rect = new Rectangle(ncp.rgrc1.left, ncp.rgrc1.top, ncp.rgrc1.right - ncp.rgrc1.left, ncp.rgrc1.bottom - ncp.rgrc1.top); + hwnd.ClientRect = rect; + + rect = TranslateClientRectangleToXClientRectangle (hwnd); + + if (hwnd.visible) { + MoveResizeWindow (DisplayHandle, hwnd.client_window, rect.X, rect.Y, rect.Width, rect.Height); + } + + AddExpose (hwnd, hwnd.WholeWindow == hwnd.ClientWindow, 0, 0, hwnd.Width, hwnd.Height); + } + #endregion // Methods + + #region Callbacks + void MouseHover(object sender, EventArgs e) { + XEvent xevent; + Hwnd hwnd; + + HoverState.Timer.Enabled = false; + + if (HoverState.Window != IntPtr.Zero) { + hwnd = Hwnd.GetObjectFromWindow(HoverState.Window); + if (hwnd != null) { + xevent = new XEvent (); + + xevent.type = XEventName.ClientMessage; + xevent.ClientMessageEvent.display = DisplayHandle; + xevent.ClientMessageEvent.window = HoverState.Window; + xevent.ClientMessageEvent.message_type = HoverState.Atom; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = (IntPtr) (HoverState.Y << 16 | HoverState.X); + + hwnd.Queue.EnqueueLocked (xevent); + + WakeupMain (); + } + } + } + + void CaretCallback(object sender, EventArgs e) { + if (Caret.Paused) { + return; + } + Caret.On = !Caret.On; + + XDrawLine(DisplayHandle, Caret.Hwnd, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height); + } + #endregion // Callbacks + + #region Public Properties + + internal override int CaptionHeight { + get { + return 19; + } + } + + internal override Size CursorSize { + get { + int x; + int y; + + if (XQueryBestCursor(DisplayHandle, RootWindow, 32, 32, out x, out y) != 0) { + return new Size(x, y); + } else { + return new Size(16, 16); + } + } + } + + internal override bool DragFullWindows { + get { + return true; + } + } + + internal override Size DragSize { + get { + return new Size(4, 4); + } + } + + internal override Size FrameBorderSize { + get { + return new Size (4, 4); + } + } + + internal override Size IconSize { + get { + IntPtr list; + XIconSize size; + int count; + + if (XGetIconSizes(DisplayHandle, RootWindow, out list, out count) != 0) { + long current; + int largest; + + current = (long)list; + largest = 0; + + size = new XIconSize(); + + for (int i = 0; i < count; i++) { + size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType()); + current += Marshal.SizeOf(size); + + // Look for our preferred size + if (size.min_width == 32) { + XFree(list); + return new Size(32, 32); + } + + if (size.max_width == 32) { + XFree(list); + return new Size(32, 32); + } + + if (size.min_width < 32 && size.max_width > 32) { + int x; + + // check if we can fit one + x = size.min_width; + while (x < size.max_width) { + x += size.width_inc; + if (x == 32) { + XFree(list); + return new Size(32, 32); + } + } + } + + if (largest < size.max_width) { + largest = size.max_width; + } + } + + // We didn't find a match or we wouldn't be here + return new Size(largest, largest); + + } else { + return new Size(32, 32); + } + } + } + + internal override int KeyboardSpeed { + get{ + // + // A lot harder: need to do: + // XkbQueryExtension(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 1 + // XkbAllocKeyboard(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 0x080517a8 + // XkbGetWidgets(0x08051008, 1, 0x080517a8, 0xbfffdf54, 0xbfffdf58) = 0 + // + // And from that we can tell the repetition rate + // + // Notice, the values must map to: + // [0, 31] which maps to 2.5 to 30 repetitions per second. + // + return 0; + } + } + + internal override int KeyboardDelay { + get { + // + // Return values must range from 0 to 4, 0 meaning 250ms, + // and 4 meaning 1000 ms. + // + return 1; // ie, 500 ms + } + } + + internal override Size MaxWindowTrackSize { + get { + return new Size (WorkingArea.Width, WorkingArea.Height); + } + } + + internal override bool MenuAccessKeysUnderlined { + get { + return false; + } + } + + internal override Size MinimizedWindowSpacingSize { + get { + return new Size(1, 1); + } + } + + internal override Size MinimumWindowSize { + get { + return new Size(110, 22); + } + } + + internal override Size MinimumFixedToolWindowSize { + get { return new Size (27, 22); } + } + + internal override Size MinimumSizeableToolWindowSize { + get { return new Size (37, 22); } + } + + internal override Size MinimumNoBorderWindowSize { + get { return new Size (2, 2); } + } + + internal override Keys ModifierKeys { + get { + return Keyboard.ModifierKeys; + } + } + + internal override Size SmallIconSize { + get { + IntPtr list; + XIconSize size; + int count; + + if (XGetIconSizes(DisplayHandle, RootWindow, out list, out count) != 0) { + long current; + int smallest; + + current = (long)list; + smallest = 0; + + size = new XIconSize(); + + for (int i = 0; i < count; i++) { + size = (XIconSize)Marshal.PtrToStructure((IntPtr)current, size.GetType()); + current += Marshal.SizeOf(size); + + // Look for our preferred size + if (size.min_width == 16) { + XFree(list); + return new Size(16, 16); + } + + if (size.max_width == 16) { + XFree(list); + return new Size(16, 16); + } + + if (size.min_width < 16 && size.max_width > 16) { + int x; + + // check if we can fit one + x = size.min_width; + while (x < size.max_width) { + x += size.width_inc; + if (x == 16) { + XFree(list); + return new Size(16, 16); + } + } + } + + if (smallest == 0 || smallest > size.min_width) { + smallest = size.min_width; + } + } + + // We didn't find a match or we wouldn't be here + return new Size(smallest, smallest); + + } else { + return new Size(16, 16); + } + } + } + + internal override int MouseButtonCount { + get { + return 3; + } + } + + internal override bool MouseButtonsSwapped { + get { + return false; // FIXME - how to detect? + } + } + + internal override Point MousePosition { + get { + return mouse_position; + } + } + + internal override Size MouseHoverSize { + get { + return new Size (1, 1); + } + } + + internal override int MouseHoverTime { + get { + return HoverState.Interval; + } + } + + + + internal override bool MouseWheelPresent { + get { + return true; // FIXME - how to detect? + } + } + + internal override MouseButtons MouseButtons { + get { + return MouseState; + } + } + + internal override Rectangle VirtualScreen { + get { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + int width; + int height; + + XGetWindowProperty(DisplayHandle, RootWindow, _NET_DESKTOP_GEOMETRY, IntPtr.Zero, new IntPtr (256), false, (IntPtr)Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + if ((long)nitems < 2) + goto failsafe; + + width = Marshal.ReadIntPtr(prop, 0).ToInt32(); + height = Marshal.ReadIntPtr(prop, IntPtr.Size).ToInt32(); + + XFree(prop); + + return new Rectangle(0, 0, width, height); + + failsafe: + XWindowAttributes attributes=new XWindowAttributes(); + + lock (XlibLock) { + XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes); + } + + return new Rectangle(0, 0, attributes.width, attributes.height); + } + } + + internal override Rectangle WorkingArea { + get { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + int width; + int height; + int current_desktop; + int x; + int y; + + XGetWindowProperty(DisplayHandle, RootWindow, _NET_CURRENT_DESKTOP, IntPtr.Zero, new IntPtr(1), false, (IntPtr)Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + if ((long)nitems < 1) { + goto failsafe; + } + + current_desktop = Marshal.ReadIntPtr(prop, 0).ToInt32(); + XFree(prop); + + XGetWindowProperty(DisplayHandle, RootWindow, _NET_WORKAREA, IntPtr.Zero, new IntPtr (256), false, (IntPtr)Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + if ((long)nitems < 4 * (current_desktop + 1)) { + goto failsafe; + } + + x = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop).ToInt32(); + y = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size).ToInt32(); + width = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 2).ToInt32(); + height = Marshal.ReadIntPtr(prop, IntPtr.Size * 4 * current_desktop + IntPtr.Size * 3).ToInt32(); + XFree(prop); + + return new Rectangle(x, y, width, height); + + failsafe: + XWindowAttributes attributes=new XWindowAttributes(); + + lock (XlibLock) { + XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes); + } + + return new Rectangle(0, 0, attributes.width, attributes.height); + } + } + + internal override Screen[] AllScreens { + get { + if (!XineramaIsActive (DisplayHandle)) + return null; + int nScreens; + IntPtr xineramaScreens = XineramaQueryScreens (DisplayHandle, out nScreens); + var screens = new Screen [nScreens]; + IntPtr current = xineramaScreens; + for (int i = 0; i < nScreens; i++) { + var screen = (XineramaScreenInfo)Marshal.PtrToStructure (current, + typeof (XineramaScreenInfo)); + var screenRect = new Rectangle (screen.x_org, screen.y_org, screen.width, + screen.height); + var name = string.Format ("Display {0}", screen.screen_number); + screens [i] = new Screen (i == 0, name, screenRect, screenRect); + current = (IntPtr)( (ulong)current + (ulong)Marshal.SizeOf(typeof (XineramaScreenInfo))); + } + XFree (xineramaScreens); + return screens; + } + } + + internal override bool ThemesEnabled { + get { + return XplatUIX11.themes_enabled; + } + } + + + #endregion // Public properties + + #region Public Static Methods + internal override void RaiseIdle (EventArgs e) + { + if (Idle != null) + Idle (this, e); + } + + internal override IntPtr InitializeDriver() + { + lock (this) { + if (DisplayHandle==IntPtr.Zero) { + SetDisplay(XOpenDisplay(IntPtr.Zero)); + } + } + return IntPtr.Zero; + } + + internal override void ShutdownDriver(IntPtr token) + { + lock (this) { + if (DisplayHandle!=IntPtr.Zero) { + XCloseDisplay(DisplayHandle); + DisplayHandle=IntPtr.Zero; + } + } + } + + internal override void EnableThemes() + { + themes_enabled = true; + } + + + internal override void Activate(IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) { + lock (XlibLock) { + if (true /* the window manager supports NET_ACTIVE_WINDOW */) { + SendNetWMMessage(hwnd.whole_window, _NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero); + XEventQueue q = null; + lock (unattached_timer_list) { + foreach (Timer t in unattached_timer_list) { + if (q == null) + q= (XEventQueue) MessageQueues [Thread.CurrentThread]; + t.thread = q.Thread; + q.timer_list.Add (t); + } + unattached_timer_list.Clear (); + } + } +// else { +// XRaiseWindow(DisplayHandle, handle); +// } + } + } + } + + internal override void AudibleAlert(AlertType alert) + { + XBell(DisplayHandle, 0); + return; + } + + + internal override void CaretVisible(IntPtr handle, bool visible) + { + if (Caret.Hwnd == handle) { + if (visible) { + if (!Caret.Visible) { + Caret.Visible = true; + ShowCaret(); + Caret.Timer.Start(); + } + } else { + Caret.Visible = false; + Caret.Timer.Stop(); + HideCaret(); + } + } + } + + internal override bool CalculateWindowRect(ref Rectangle ClientRect, CreateParams cp, Menu menu, out Rectangle WindowRect) + { + WindowRect = Hwnd.GetWindowRectangle (cp, menu, ClientRect); + return true; + } + + internal override void ClientToScreen(IntPtr handle, ref int x, ref int y) + { + int dest_x_return; + int dest_y_return; + IntPtr child; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + lock (XlibLock) { + XTranslateCoordinates(handle, hwnd.client_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child); + } + + x = dest_x_return; + y = dest_y_return; + } + + internal override int[] ClipboardAvailableFormats(IntPtr handle) + { + DataFormats.Format f; + int[] result; + + f = DataFormats.Format.List; + + if (XGetSelectionOwner(DisplayHandle, CLIPBOARD) == IntPtr.Zero) { + return null; + } + + Clipboard.Formats = new ArrayList(); + + while (f != null) { + XConvertSelection(DisplayHandle, CLIPBOARD, (IntPtr)f.Id, (IntPtr)f.Id, FosterParent, IntPtr.Zero); + + var timeToWaitForSelectionFormats = TimeSpan.FromSeconds(4); + var startTime = DateTime.Now; + Clipboard.Enumerating = true; + while (Clipboard.Enumerating) { + UpdateMessageQueue(null, false); + + if (DateTime.Now - startTime > timeToWaitForSelectionFormats) + break; + } + f = f.Next; + } + + result = new int[Clipboard.Formats.Count]; + + for (int i = 0; i < Clipboard.Formats.Count; i++) { + result[i] = ((IntPtr)Clipboard.Formats[i]).ToInt32 (); + } + + Clipboard.Formats = null; + return result; + } + + internal override void ClipboardClose(IntPtr handle) + { + if (handle != ClipMagic) { + throw new ArgumentException("handle is not a valid clipboard handle"); + } + return; + } + + internal override int ClipboardGetID(IntPtr handle, string format) + { + if (handle != ClipMagic) { + throw new ArgumentException("handle is not a valid clipboard handle"); + } + + if (format == "Text" ) return (int)Atom.XA_STRING; + else if (format == "Bitmap" ) return (int)Atom.XA_BITMAP; + //else if (format == "MetaFilePict" ) return 3; + //else if (format == "SymbolicLink" ) return 4; + //else if (format == "DataInterchangeFormat" ) return 5; + //else if (format == "Tiff" ) return 6; + else if (format == "OEMText" ) return OEMTEXT.ToInt32(); + else if (format == "DeviceIndependentBitmap" ) return (int)Atom.XA_PIXMAP; + else if (format == "Palette" ) return (int)Atom.XA_COLORMAP; // Useless + //else if (format == "PenData" ) return 10; + //else if (format == "RiffAudio" ) return 11; + //else if (format == "WaveAudio" ) return 12; + else if (format == "UnicodeText" ) return UTF16_STRING.ToInt32(); + //else if (format == "EnhancedMetafile" ) return 14; + //else if (format == "FileDrop" ) return 15; + //else if (format == "Locale" ) return 16; + else if (format == "Rich Text Format") return RICHTEXTFORMAT.ToInt32 (); + + return XInternAtom(DisplayHandle, format, false).ToInt32(); + } + + internal override IntPtr ClipboardOpen(bool primary_selection) + { + if (!primary_selection) + ClipMagic = CLIPBOARD; + else + ClipMagic = PRIMARY; + return ClipMagic; + } + + internal override object ClipboardRetrieve(IntPtr handle, int type, XplatUI.ClipboardToObject converter) + { + XConvertSelection(DisplayHandle, handle, (IntPtr)type, (IntPtr)type, FosterParent, IntPtr.Zero); + + Clipboard.Retrieving = true; + while (Clipboard.Retrieving) { + UpdateMessageQueue(null, false); + } + + return Clipboard.Item; + } + + internal override void ClipboardStore (IntPtr handle, object obj, int type, XplatUI.ObjectToClipboard converter, bool copy) + { + Clipboard.Converter = converter; + + if (obj != null) { + Clipboard.AddSource (type, obj); + XSetSelectionOwner (DisplayHandle, CLIPBOARD, FosterParent, IntPtr.Zero); + + if (copy) { + try { + var clipboardAtom = gdk_atom_intern ("CLIPBOARD", true); + var clipboard = gtk_clipboard_get (clipboardAtom); + if (clipboard != null) { + // for now we only store text + var text = Clipboard.GetRtfText (); + if (string.IsNullOrEmpty (text)) + text = Clipboard.GetPlainText (); + if (!string.IsNullOrEmpty (text)) { + gtk_clipboard_set_text (clipboard, text, text.Length); + gtk_clipboard_store (clipboard); + } + } + } catch { + // ignore any errors - most likely because gtk isn't installed? + } + } + } else { + // Clearing the selection + Clipboard.ClearSources (); + XSetSelectionOwner (DisplayHandle, CLIPBOARD, IntPtr.Zero, IntPtr.Zero); + } + } + + internal override void CreateCaret (IntPtr handle, int width, int height) + { + XGCValues gc_values; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (Caret.Hwnd != IntPtr.Zero) { + DestroyCaret(Caret.Hwnd); + } + + Caret.Hwnd = handle; + Caret.Window = hwnd.client_window; + Caret.Width = width; + Caret.Height = height; + Caret.Visible = false; + Caret.On = false; + + gc_values = new XGCValues(); + gc_values.line_width = width; + + Caret.gc = XCreateGC(DisplayHandle, Caret.Window, new IntPtr ((int)GCFunction.GCLineWidth), ref gc_values); + if (Caret.gc == IntPtr.Zero) { + Caret.Hwnd = IntPtr.Zero; + return; + } + + XSetFunction(DisplayHandle, Caret.gc, GXFunction.GXinvert); + } + + internal override IntPtr CreateWindow (CreateParams cp) + { + XSetWindowAttributes Attributes; + Hwnd hwnd; + Hwnd parent_hwnd = null; + int X; + int Y; + int Width; + int Height; + IntPtr ParentHandle; + IntPtr WholeWindow; + IntPtr ClientWindow; + SetWindowValuemask ValueMask; + + hwnd = new Hwnd(); + + Attributes = new XSetWindowAttributes(); + X = cp.X; + Y = cp.Y; + Width = cp.Width; + Height = cp.Height; + + if (Width<1) Width=1; + if (Height<1) Height=1; + + if (cp.Parent != IntPtr.Zero) { + parent_hwnd = Hwnd.ObjectFromHandle(cp.Parent); + ParentHandle = parent_hwnd.client_window; + } else { + if (StyleSet (cp.Style, WindowStyles.WS_CHILD)) { + // We need to use our foster parent window until this poor child gets it's parent assigned + ParentHandle=FosterParent; + } else { + ParentHandle=RootWindow; + } + } + + // Set the default location location for forms. + Point next; + if (cp.control is Form) { + next = Hwnd.GetNextStackedFormLocation (cp, parent_hwnd); + X = next.X; + Y = next.Y; + } + ValueMask = SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity; + + Attributes.bit_gravity = Gravity.NorthWestGravity; + Attributes.win_gravity = Gravity.NorthWestGravity; + + // Save what's under the toolwindow + if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { + Attributes.save_under = true; + ValueMask |= SetWindowValuemask.SaveUnder; + } + + + // If we're a popup without caption we override the WM + if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && !StyleSet (cp.Style, WindowStyles.WS_CAPTION)) { + Attributes.override_redirect = true; + ValueMask |= SetWindowValuemask.OverrideRedirect; + } + + hwnd.x = X; + hwnd.y = Y; + hwnd.width = Width; + hwnd.height = Height; + hwnd.parent = Hwnd.ObjectFromHandle(cp.Parent); + hwnd.initial_style = cp.WindowStyle; + hwnd.initial_ex_style = cp.WindowExStyle; + + if (StyleSet (cp.Style, WindowStyles.WS_DISABLED)) { + hwnd.enabled = false; + } + + ClientWindow = IntPtr.Zero; + + Size XWindowSize = TranslateWindowSizeToXWindowSize (cp); + Rectangle XClientRect = TranslateClientRectangleToXClientRectangle (hwnd, cp.control); + + lock (XlibLock) { + WholeWindow = XCreateWindow(DisplayHandle, ParentHandle, X, Y, XWindowSize.Width, XWindowSize.Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, IntPtr.Zero, new UIntPtr ((uint)ValueMask), ref Attributes); + if (WholeWindow != IntPtr.Zero) { + ValueMask &= ~(SetWindowValuemask.OverrideRedirect | SetWindowValuemask.SaveUnder); + + if (CustomVisual != IntPtr.Zero && CustomColormap != IntPtr.Zero) { + ValueMask = SetWindowValuemask.ColorMap; + Attributes.colormap = CustomColormap; + } + ClientWindow = XCreateWindow(DisplayHandle, WholeWindow, XClientRect.X, XClientRect.Y, XClientRect.Width, XClientRect.Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, CustomVisual, new UIntPtr ((uint)ValueMask), ref Attributes); + } + } + + if ((WholeWindow == IntPtr.Zero) || (ClientWindow == IntPtr.Zero)) { + throw new Exception("Could not create X11 windows"); + } + + hwnd.Queue = ThreadQueue(Thread.CurrentThread); + hwnd.WholeWindow = WholeWindow; + hwnd.ClientWindow = ClientWindow; + + DriverDebug("Created window {0:X} / {1:X} parent {2:X}, Style {3}, ExStyle {4}", ClientWindow.ToInt32(), WholeWindow.ToInt32(), hwnd.parent != null ? hwnd.parent.Handle.ToInt32() : 0, (WindowStyles)cp.Style, (WindowExStyles)cp.ExStyle); + + if (!StyleSet (cp.Style, WindowStyles.WS_CHILD)) { + if ((X != unchecked((int)0x80000000)) && (Y != unchecked((int)0x80000000))) { + XSizeHints hints; + + hints = new XSizeHints(); + hints.x = X; + hints.y = Y; + hints.flags = (IntPtr)(XSizeHintsFlags.USPosition | XSizeHintsFlags.PPosition); + XSetWMNormalHints(DisplayHandle, WholeWindow, ref hints); + } + } + + lock (XlibLock) { + XSelectInput(DisplayHandle, hwnd.whole_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask | EventMask.PropertyChangeMask | Keyboard.KeyEventMask))); + if (hwnd.whole_window != hwnd.client_window) + XSelectInput(DisplayHandle, hwnd.client_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask | Keyboard.KeyEventMask))); + } + + if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOPMOST)) + SetTopmost(hwnd.whole_window, true); + + SetWMStyles(hwnd, cp); + + // set the group leader + XWMHints wm_hints = new XWMHints (); + + wm_hints.flags = (IntPtr)(XWMHintsFlags.InputHint | XWMHintsFlags.StateHint | XWMHintsFlags.WindowGroupHint); + wm_hints.input = !StyleSet (cp.Style, WindowStyles.WS_DISABLED); + wm_hints.initial_state = StyleSet (cp.Style, WindowStyles.WS_MINIMIZE) ? XInitialState.IconicState : XInitialState.NormalState; + + if (ParentHandle != RootWindow) { + wm_hints.window_group = hwnd.whole_window; + } else { + wm_hints.window_group = ParentHandle; + } + + lock (XlibLock) { + XSetWMHints(DisplayHandle, hwnd.whole_window, ref wm_hints ); + } + + if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZE)) { + SetWindowState(hwnd.Handle, FormWindowState.Minimized); + } else if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZE)) { + SetWindowState(hwnd.Handle, FormWindowState.Maximized); + } + + // for now make all windows dnd enabled + Dnd.SetAllowDrop (hwnd, true); + + // Set caption/window title + Text(hwnd.Handle, cp.Caption); + + SendMessage (hwnd.Handle, Msg.WM_CREATE, (IntPtr)1, IntPtr.Zero /* XXX unused */); + SendParentNotify (hwnd.Handle, Msg.WM_CREATE, int.MaxValue, int.MaxValue); + + if (StyleSet (cp.Style, WindowStyles.WS_VISIBLE)) { + hwnd.visible = true; + MapWindow(hwnd, WindowType.Both); + if (!(Widget.FromHandle(hwnd.Handle) is Form)) + SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero); + } + + return hwnd.Handle; + } + + internal override IntPtr CreateWindow(IntPtr Parent, int X, int Y, int Width, int Height) + { + CreateParams create_params = new CreateParams(); + + create_params.Caption = ""; + create_params.X = X; + create_params.Y = Y; + create_params.Width = Width; + create_params.Height = Height; + + create_params.ClassName=XplatUI.GetDefaultClassName (GetType ()); + create_params.ClassStyle = 0; + create_params.ExStyle=0; + create_params.Parent=IntPtr.Zero; + create_params.Param=0; + + return CreateWindow(create_params); + } + + internal override IntPtr DefineCursor(Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) + { + IntPtr cursor; + Bitmap cursor_bitmap; + Bitmap cursor_mask; + Byte[] cursor_bits; + Byte[] mask_bits; + Color c_pixel; + Color m_pixel; + int width; + int height; + IntPtr cursor_pixmap; + IntPtr mask_pixmap; + XColor fg; + XColor bg; + bool and; + bool xor; + + if (XQueryBestCursor(DisplayHandle, RootWindow, bitmap.Width, bitmap.Height, out width, out height) == 0) { + return IntPtr.Zero; + } + + // Win32 only allows creation cursors of a certain size + if ((bitmap.Width != width) || (bitmap.Width != height)) { + cursor_bitmap = new Bitmap(bitmap, new Size(width, height)); + cursor_mask = new Bitmap(mask, new Size(width, height)); + } else { + cursor_bitmap = bitmap; + cursor_mask = mask; + } + + width = cursor_bitmap.Width; + height = cursor_bitmap.Height; + + cursor_bits = new Byte[(width / 8) * height]; + mask_bits = new Byte[(width / 8) * height]; + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + c_pixel = cursor_bitmap.GetPixel(x, y); + m_pixel = cursor_mask.GetPixel(x, y); + + and = c_pixel == cursor_pixel; + xor = m_pixel == mask_pixel; + + if (!and && !xor) { + // Black + // cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8))); // The bit already is 0 + mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8)); + } else if (and && !xor) { + // White + cursor_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8)); + mask_bits[y * width / 8 + x / 8] |= (byte)(1 << (x % 8)); +#if notneeded + } else if (and && !xor) { + // Screen + } else if (and && xor) { + // Inverse Screen + + // X11 doesn't know the 'reverse screen' concept, so we'll treat them the same + // we want both to be 0 so nothing to be done + //cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8))); + //mask_bits[y * width / 8 + x / 8] |= (byte)(01 << (x % 8)); +#endif + } + } + } + + cursor_pixmap = XCreatePixmapFromBitmapData(DisplayHandle, RootWindow, cursor_bits, width, height, (IntPtr)1, (IntPtr)0, 1); + mask_pixmap = XCreatePixmapFromBitmapData(DisplayHandle, RootWindow, mask_bits, width, height, (IntPtr)1, (IntPtr)0, 1); + fg = new XColor(); + bg = new XColor(); + + fg.pixel = XWhitePixel(DisplayHandle, ScreenNo); + fg.red = (ushort)65535; + fg.green = (ushort)65535; + fg.blue = (ushort)65535; + + bg.pixel = XBlackPixel(DisplayHandle, ScreenNo); + + cursor = XCreatePixmapCursor(DisplayHandle, cursor_pixmap, mask_pixmap, ref fg, ref bg, xHotSpot, yHotSpot); + + XFreePixmap(DisplayHandle, cursor_pixmap); + XFreePixmap(DisplayHandle, mask_pixmap); + + return cursor; + } + + internal override Bitmap DefineStdCursorBitmap (StdCursor id) + { + CursorFontShape shape; + string name; + IntPtr theme; + int size; + Bitmap bmp = null; + + try { + shape = StdCursorToFontShape (id); + name = shape.ToString ().Replace ("XC_", string.Empty); + size = XcursorGetDefaultSize (DisplayHandle); + theme = XcursorGetTheme (DisplayHandle); + IntPtr images_ptr = XcursorLibraryLoadImages (name, theme, size); + DriverDebug ("DefineStdCursorBitmap, id={0}, #id={1}, name{2}, size={3}, theme: {4}, images_ptr={5}", id, (int) id, name, size, Marshal.PtrToStringAnsi (theme), images_ptr); + + if (images_ptr == IntPtr.Zero) { + return null; + } + + XcursorImages images = (XcursorImages) Marshal.PtrToStructure (images_ptr, typeof (XcursorImages)); + DriverDebug ("DefineStdCursorBitmap, cursor has {0} images", images.nimage); + + if (images.nimage > 0) { + // We only care about the first image. + XcursorImage image = (XcursorImage)Marshal.PtrToStructure (Marshal.ReadIntPtr (images.images), typeof (XcursorImage)); + + DriverDebug ("DefineStdCursorBitmap, loaded image > 16) == (int)Msg.WM_LBUTTONDOWN) { + AudibleAlert(AlertType.Default); + } + handle = Cursors.Default.handle; + break; + + case HitTest.HTHELP: handle = Cursors.Help.handle; break; + case HitTest.HTLEFT: handle = Cursors.SizeWE.handle; break; + case HitTest.HTRIGHT: handle = Cursors.SizeWE.handle; break; + case HitTest.HTTOP: handle = Cursors.SizeNS.handle; break; + case HitTest.HTTOPLEFT: handle = Cursors.SizeNWSE.handle; break; + case HitTest.HTTOPRIGHT: handle = Cursors.SizeNESW.handle; break; + + #if SameAsDefault + case HitTest.HTGROWBOX: + case HitTest.HTSIZE: + case HitTest.HTZOOM: + case HitTest.HTVSCROLL: + case HitTest.HTSYSMENU: + case HitTest.HTREDUCE: + case HitTest.HTNOWHERE: + case HitTest.HTMAXBUTTON: + case HitTest.HTMINBUTTON: + case HitTest.HTMENU: + case HitTest.HSCROLL: + case HitTest.HTBOTTOM: + case HitTest.HTCAPTION: + case HitTest.HTCLIENT: + case HitTest.HTCLOSE: + #endif + default: handle = Cursors.Default.handle; break; + } + SetCursor(msg.HWnd, handle); + } + return (IntPtr)1; + } + } + return IntPtr.Zero; + } + + internal override void DestroyCaret(IntPtr handle) + { + if (Caret.Hwnd == handle) { + if (Caret.Visible) { + HideCaret (); + Caret.Timer.Stop(); + } + if (Caret.gc != IntPtr.Zero) { + XFreeGC(DisplayHandle, Caret.gc); + Caret.gc = IntPtr.Zero; + } + Caret.Hwnd = IntPtr.Zero; + Caret.Visible = false; + Caret.On = false; + } + } + + internal override void DestroyCursor(IntPtr cursor) + { + lock (XlibLock) { + XFreeCursor(DisplayHandle, cursor); + } + } + + internal override void DestroyWindow(IntPtr handle) + { + Hwnd hwnd; + hwnd = Hwnd.ObjectFromHandle(handle); + + // The window should never ever be a zombie here, since we should + // wait until it's completely dead before returning from + // "destroying" calls, but just in case.... + if (hwnd == null || hwnd.zombie) { + DriverDebug ("window {0:X} already destroyed", handle.ToInt32()); + return; + } + + DriverDebug ("Destroying window {0}", XplatUI.Window(hwnd.client_window)); + + SendParentNotify (hwnd.Handle, Msg.WM_DESTROY, int.MaxValue, int.MaxValue); + + CleanupCachedWindows (hwnd); + + ArrayList windows = new ArrayList (); + + AccumulateDestroyedHandles (Widget.WidgetNativeWindow.WidgetFromHandle(hwnd.Handle), windows); + + + foreach (Hwnd h in windows) { + SendMessage (h.Handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero); + h.zombie = true; + } + + lock (XlibLock) { + if (hwnd.whole_window != IntPtr.Zero) { + DriverDebug ("XDestroyWindow (whole_window = {0:X})", hwnd.whole_window.ToInt32()); + Keyboard.DestroyICForWindow (hwnd.whole_window); + XDestroyWindow(DisplayHandle, hwnd.whole_window); + } + else if (hwnd.client_window != IntPtr.Zero) { + DriverDebug ("XDestroyWindow (client_window = {0:X})", hwnd.client_window.ToInt32()); + Keyboard.DestroyICForWindow (hwnd.client_window); + XDestroyWindow(DisplayHandle, hwnd.client_window); + } + + } + } + + internal override IntPtr DispatchMessage(ref MSG msg) + { + return NativeWindow.WndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam); + } + + IntPtr GetReversibleScreenGC (Color backColor) + { + XGCValues gc_values; + IntPtr gc; + uint pixel; + + XColor xcolor = new XColor(); + xcolor.red = (ushort)(backColor.R * 257); + xcolor.green = (ushort)(backColor.G * 257); + xcolor.blue = (ushort)(backColor.B * 257); + XAllocColor(DisplayHandle, DefaultColormap, ref xcolor); + pixel = (uint)xcolor.pixel.ToInt32(); + + + gc_values = new XGCValues(); + + gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors; + gc_values.foreground = (IntPtr)pixel; + + gc = XCreateGC(DisplayHandle, RootWindow, new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCForeground)), ref gc_values); + XSetForeground(DisplayHandle, gc, (UIntPtr)pixel); + XSetFunction(DisplayHandle, gc, GXFunction.GXxor); + + return gc; + } + + IntPtr GetReversibleWidgetGC (Widget Widget, int line_width) + { + XGCValues gc_values; + IntPtr gc; + + gc_values = new XGCValues(); + + gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors; + gc_values.line_width = line_width; + gc_values.foreground = XBlackPixel(DisplayHandle, ScreenNo); + + // This logic will give us true rubber bands: (libsx, SANE_XOR) + //mask = foreground ^ background; + //XSetForeground(DisplayHandle, gc, 0xffffffff); + //XSetBackground(DisplayHandle, gc, background); + //XSetFunction(DisplayHandle, gc, GXxor); + //XSetPlaneMask(DisplayHandle, gc, mask); + + + gc = XCreateGC(DisplayHandle, Widget.Handle, new IntPtr ((int) (GCFunction.GCSubwindowMode | GCFunction.GCLineWidth | GCFunction.GCForeground)), ref gc_values); + uint foreground; + uint background; + + XColor xcolor = new XColor(); + + xcolor.red = (ushort)(Widget.ForeColor.R * 257); + xcolor.green = (ushort)(Widget.ForeColor.G * 257); + xcolor.blue = (ushort)(Widget.ForeColor.B * 257); + XAllocColor(DisplayHandle, DefaultColormap, ref xcolor); + foreground = (uint)xcolor.pixel.ToInt32(); + + xcolor.red = (ushort)(Widget.BackColor.R * 257); + xcolor.green = (ushort)(Widget.BackColor.G * 257); + xcolor.blue = (ushort)(Widget.BackColor.B * 257); + XAllocColor(DisplayHandle, DefaultColormap, ref xcolor); + background = (uint)xcolor.pixel.ToInt32(); + + uint mask = foreground ^ background; + + XSetForeground(DisplayHandle, gc, (UIntPtr)0xffffffff); + XSetBackground(DisplayHandle, gc, (UIntPtr)background); + XSetFunction(DisplayHandle, gc, GXFunction.GXxor); + XSetPlaneMask(DisplayHandle, gc, (IntPtr)mask); + + return gc; + } + + internal override void DrawReversibleLine(Point start, Point end, Color backColor) + { + if (backColor.GetBrightness() < 0.5) + backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B); + + IntPtr gc = GetReversibleScreenGC (backColor); + + XDrawLine (DisplayHandle, RootWindow, gc, start.X, start.Y, end.X, end.Y); + + XFreeGC(DisplayHandle, gc); + } + + internal override void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style) + { + if (backColor.GetBrightness() < 0.5) + backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B); + + IntPtr gc = GetReversibleScreenGC (backColor); + + if (rectangle.Width < 0) { + rectangle.X += rectangle.Width; + rectangle.Width = -rectangle.Width; + } + if (rectangle.Height < 0) { + rectangle.Y += rectangle.Height; + rectangle.Height = -rectangle.Height; + } + + int line_width = 1; + GCLineStyle line_style = GCLineStyle.LineSolid; + GCCapStyle cap_style = GCCapStyle.CapButt; + GCJoinStyle join_style = GCJoinStyle.JoinMiter; + + switch (style) { + case FrameStyle.Dashed: + line_style = GCLineStyle.LineOnOffDash; + break; + case FrameStyle.Thick: + line_width = 2; + break; + } + + XSetLineAttributes (DisplayHandle, gc, line_width, line_style, cap_style, join_style); + + XDrawRectangle(DisplayHandle, RootWindow, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height); + + XFreeGC(DisplayHandle, gc); + } + + internal override void FillReversibleRectangle (Rectangle rectangle, Color backColor) + { + if (backColor.GetBrightness() < 0.5) + backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B); + + IntPtr gc = GetReversibleScreenGC (backColor); + + if (rectangle.Width < 0) { + rectangle.X += rectangle.Width; + rectangle.Width = -rectangle.Width; + } + if (rectangle.Height < 0) { + rectangle.Y += rectangle.Height; + rectangle.Height = -rectangle.Height; + } + XFillRectangle(DisplayHandle, RootWindow, gc, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height); + + XFreeGC(DisplayHandle, gc); + } + + internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width) + { + IntPtr gc; + Widget Widget = Widget.FromHandle(handle); + + gc = GetReversibleWidgetGC (Widget, line_width); + + if ((rect.Width > 0) && (rect.Height > 0)) { + XDrawRectangle(DisplayHandle, Widget.Handle, gc, rect.Left, rect.Top, rect.Width, rect.Height); + } else { + if (rect.Width > 0) { + XDrawLine(DisplayHandle, Widget.Handle, gc, rect.X, rect.Y, rect.Right, rect.Y); + } else { + XDrawLine(DisplayHandle, Widget.Handle, gc, rect.X, rect.Y, rect.X, rect.Bottom); + } + } + XFreeGC(DisplayHandle, gc); + } + + internal override void DoEvents() + { + DebugHelper.Enter (); + + MSG msg = new MSG (); + XEventQueue queue; + + if (OverrideCursorHandle != IntPtr.Zero) { + OverrideCursorHandle = IntPtr.Zero; + } + + queue = ThreadQueue(Thread.CurrentThread); + + queue.DispatchIdle = false; + in_doevents = true; + + while (PeekMessage(queue, ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) { + Message m = Message.Create (msg.hwnd, (int)msg.message, msg.wParam, msg.lParam); + + if (Application.FilterMessage (ref m)) + continue; + + TranslateMessage (ref msg); + DispatchMessage (ref msg); + + string key = msg.hwnd + ":" + msg.message; + if (messageHold[key] != null) { + messageHold[key] = ((int)messageHold[key]) - 1; + DebugHelper.WriteLine ("Got " + msg + " for " + key); + } + } + + in_doevents = false; + queue.DispatchIdle = true; + + DebugHelper.Leave (); + } + + internal override void EnableWindow(IntPtr handle, bool Enable) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + if (hwnd != null) { + hwnd.Enabled = Enable; + } + } + + internal override void EndLoop(Thread thread) + { + // This is where we one day will shut down the loop for the thread + } + + internal override IntPtr GetActive() + { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + IntPtr active = IntPtr.Zero; + + XGetWindowProperty(DisplayHandle, RootWindow, _NET_ACTIVE_WINDOW, IntPtr.Zero, new IntPtr (1), false, (IntPtr)Atom.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + if (((long)nitems > 0) && (prop != IntPtr.Zero)) { + active = (IntPtr)Marshal.ReadInt32(prop); + XFree(prop); + } else { + // The window manager does not support _NET_ACTIVE_WINDOW. Fall back to XGetInputFocus. + IntPtr revert_to = IntPtr.Zero; + XGetInputFocus(DisplayHandle, out active, out revert_to); + } + + if (active != IntPtr.Zero) { + Hwnd hwnd; + + hwnd = Hwnd.GetObjectFromWindow(active); + if (hwnd != null) { + active = hwnd.Handle; + } else { + active = IntPtr.Zero; + } + } + return active; + } + + internal override Region GetClipRegion(IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + if (hwnd != null) { + return hwnd.UserClip; + } + + return null; + } + + internal override void GetCursorInfo(IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y) + { + width = 20; + height = 20; + hotspot_x = 0; + hotspot_y = 0; + } + + internal override void GetDisplaySize(out Size size) + { + XWindowAttributes attributes=new XWindowAttributes(); + + lock (XlibLock) { + // FIXME - use _NET_WM messages instead? + XGetWindowAttributes(DisplayHandle, XRootWindow(DisplayHandle, 0), ref attributes); + } + + size = new Size(attributes.width, attributes.height); + } + + internal override SizeF GetAutoScaleSize(Font font) + { + Graphics g; + float width; + string magic_string = "The quick brown fox jumped over the lazy dog."; + double magic_number = 44.549996948242189; + + g = Graphics.FromHwnd(FosterParent); + + width = (float) (g.MeasureString (magic_string, font).Width / magic_number); + return new SizeF(width, font.Height); + } + + internal override IntPtr GetParent(IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + if (hwnd != null && hwnd.parent != null) { + return hwnd.parent.Handle; + } + return IntPtr.Zero; + } + + // This is a nop on win32 and x11 + internal override IntPtr GetPreviousWindow(IntPtr handle) + { + return handle; + } + + internal override void GetCursorPos(IntPtr handle, out int x, out int y) + { + IntPtr use_handle; + IntPtr root; + IntPtr child; + int root_x; + int root_y; + int win_x; + int win_y; + int keys_buttons; + + if (handle != IntPtr.Zero) { + use_handle = Hwnd.ObjectFromHandle(handle).client_window; + } else { + use_handle = RootWindow; + } + + lock (XlibLock) { + QueryPointer (DisplayHandle, use_handle, out root, out child, out root_x, out root_y, out win_x, out win_y, out keys_buttons); + } + + if (handle != IntPtr.Zero) { + x = win_x; + y = win_y; + } else { + x = root_x; + y = root_y; + } + } + + internal override IntPtr GetFocus() + { + return FocusWindow; + } + + + internal override bool GetFontMetrics(Graphics g, Font font, out int ascent, out int descent) + { + FontFamily ff = font.FontFamily; + ascent = ff.GetCellAscent (font.Style); + descent = ff.GetCellDescent (font.Style); + return true; + } + + internal override Point GetMenuOrigin(IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) { + return hwnd.MenuOrigin; + } + return Point.Empty; + } + + [MonoTODO("Implement filtering")] + internal override bool GetMessage(Object queue_id, ref MSG msg, IntPtr handle, int wFilterMin, int wFilterMax) + { + XEvent xevent; + bool client; + Hwnd hwnd; + + ProcessNextMessage: + + if (((XEventQueue)queue_id).Count > 0) { + xevent = (XEvent) ((XEventQueue)queue_id).Dequeue (); + } else { + UpdateMessageQueue ((XEventQueue)queue_id); + + if (((XEventQueue)queue_id).Count > 0) { + xevent = (XEvent) ((XEventQueue)queue_id).Dequeue (); + } else if (((XEventQueue)queue_id).Paint.Count > 0) { + xevent = ((XEventQueue)queue_id).Paint.Dequeue(); + } else { + msg.hwnd= IntPtr.Zero; + msg.message = Msg.WM_ENTERIDLE; + return true; + } + } + + hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window); + +#if DriverDebugDestroy + if (hwnd != null) + if (hwnd.zombie) + Console.WriteLine ( "GetMessage zombie, got Event: " + xevent.ToString () + " for 0x{0:x}", hwnd.Handle.ToInt32()); + else + Console.WriteLine ( "GetMessage, got Event: " + xevent.ToString () + " for 0x{0:x}", hwnd.Handle.ToInt32()); +#endif + // Handle messages for windows that are already or are about to be destroyed. + + // we need a special block for this because unless we remove the hwnd from the paint + // queue it will always stay there (since we don't handle the expose), and we'll + // effectively loop infinitely trying to repaint a non-existant window. + if (hwnd != null && hwnd.zombie && xevent.type == XEventName.Expose) { + hwnd.expose_pending = hwnd.nc_expose_pending = false; + hwnd.Queue.Paint.Remove (hwnd); + goto ProcessNextMessage; + } + + // We need to make sure we only allow DestroyNotify events through for zombie + // hwnds, since much of the event handling code makes requests using the hwnd's + // client_window, and that'll result in BadWindow errors if there's some lag + // between the XDestroyWindow call and the DestroyNotify event. + if (hwnd == null || hwnd.zombie && xevent.AnyEvent.type != XEventName.ClientMessage) { + DriverDebug("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}", xevent.type, xevent.AnyEvent.window.ToInt32()); + goto ProcessNextMessage; + } + + + // If we get here, that means the window is no more but there are Client Messages + // to be processed, probably a Posted message (for instance, an WM_ACTIVATE message) + // We don't want anything else to run but the ClientMessage block, so reset all hwnd + // properties that might cause other processing to occur. + if (hwnd.zombie) { + hwnd.resizing_or_moving = false; + } + + if (hwnd.client_window == xevent.AnyEvent.window) { + client = true; + //Console.WriteLine("Client message {1}, sending to window {0:X}", msg.hwnd.ToInt32(), xevent.type); + } else { + client = false; + //Console.WriteLine("Non-Client message, sending to window {0:X}", msg.hwnd.ToInt32()); + } + + msg.hwnd = hwnd.Handle; + + // Windows sends WM_ENTERSIZEMOVE when a form resize/move operation starts and WM_EXITSIZEMOVE + // when it is done. The problem in X11 is that there is no concept of start-end of a moving/sizing. + // Configure events ("this window has resized/moved") are sent for each step of the resize. We send a + // WM_ENTERSIZEMOVE when we get the first Configure event. The problem is the WM_EXITSIZEMOVE. + // + // - There is no way for us to know which is the last Configure event. We can't traverse the events + // queue, because the next configure event might not be pending yet. + // - We can't get ButtonPress/Release events for the window decorations, because they are not part + // of the window(s) we manage. + // - We can't rely on the mouse state to change to "up" before the last Configure event. It doesn't. + // + // We are almost 100% guaranteed to get another event (e.g Expose or other), but we can't know for sure + // which, so we have here to check if the mouse buttons state is "up" and send the WM_EXITSIZEMOVE + // + if (hwnd.resizing_or_moving) { + int root_x, root_y, win_x, win_y, keys_buttons; + IntPtr root, child; + XQueryPointer (DisplayHandle, hwnd.Handle, out root, out child, out root_x, out root_y, + out win_x, out win_y, out keys_buttons); + if ((keys_buttons & (int)MouseKeyMasks.Button1Mask) == 0 && + (keys_buttons & (int)MouseKeyMasks.Button2Mask) == 0 && + (keys_buttons & (int)MouseKeyMasks.Button3Mask) == 0) { + hwnd.resizing_or_moving = false; + SendMessage (hwnd.Handle, Msg.WM_EXITSIZEMOVE, IntPtr.Zero, IntPtr.Zero); + } + } + + // + // If you add a new event to this switch make sure to add it in + // UpdateMessage also unless it is not coming through the X event system. + // + switch(xevent.type) { + case XEventName.KeyPress: { + Keyboard.KeyEvent (FocusWindow, xevent, ref msg); + + // F1 key special case - WM_HELP sending + if (msg.wParam == (IntPtr)VirtualKeys.VK_F1 || msg.wParam == (IntPtr)VirtualKeys.VK_HELP) { + // Send wM_HELP and then return it as a keypress message in + // case it needs to be preproccessed. + HELPINFO helpInfo = new HELPINFO (); + GetCursorPos (IntPtr.Zero, out helpInfo.MousePos.x, out helpInfo.MousePos.y); + IntPtr helpInfoPtr = Marshal.AllocHGlobal (Marshal.SizeOf (helpInfo)); + Marshal.StructureToPtr (helpInfo, helpInfoPtr, true); + NativeWindow.WndProc (FocusWindow, Msg.WM_HELP, IntPtr.Zero, helpInfoPtr); + Marshal.FreeHGlobal (helpInfoPtr); + } + break; + } + + case XEventName.KeyRelease: { + Keyboard.KeyEvent (FocusWindow, xevent, ref msg); + break; + } + + case XEventName.ButtonPress: { + switch(xevent.ButtonEvent.button) { + case 1: { + MouseState |= MouseButtons.Left; + if (client) { + msg.message = Msg.WM_LBUTTONDOWN; + msg.wParam = GetMousewParam (0); + } else { + msg.message = Msg.WM_NCLBUTTONDOWN; + msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y); + MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + break; + } + + case 2: { + MouseState |= MouseButtons.Middle; + if (client) { + msg.message = Msg.WM_MBUTTONDOWN; + msg.wParam = GetMousewParam (0); + } else { + msg.message = Msg.WM_NCMBUTTONDOWN; + msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y); + MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + break; + } + + case 3: { + MouseState |= MouseButtons.Right; + if (client) { + msg.message = Msg.WM_RBUTTONDOWN; + msg.wParam = GetMousewParam (0); + } else { + msg.message = Msg.WM_NCRBUTTONDOWN; + msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y); + MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + break; + } + + case 4: { + msg.hwnd = FocusWindow; + msg.message=Msg.WM_MOUSEWHEEL; + msg.wParam=GetMousewParam(120); + break; + } + + case 5: { + msg.hwnd = FocusWindow; + msg.message=Msg.WM_MOUSEWHEEL; + msg.wParam=GetMousewParam(-120); + break; + } + + } + + msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x); + mouse_position.X = xevent.ButtonEvent.x; + mouse_position.Y = xevent.ButtonEvent.y; + + if (!hwnd.Enabled) { + IntPtr dummy; + + msg.hwnd = hwnd.EnabledHwnd; + XTranslateCoordinates(DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, xevent.ButtonEvent.x, xevent.ButtonEvent.y, out xevent.ButtonEvent.x, out xevent.ButtonEvent.y, out dummy); + msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X); + } + + if (Grab.Hwnd != IntPtr.Zero) { + msg.hwnd = Grab.Hwnd; + } + + if (ClickPending.Pending && ((((long)xevent.ButtonEvent.time - ClickPending.Time) < DoubleClickInterval) && (msg.wParam == ClickPending.wParam) && (msg.lParam == ClickPending.lParam) && (msg.message == ClickPending.Message))) { + // Looks like a genuine double click, clicked twice on the same spot with the same keys + switch(xevent.ButtonEvent.button) { + case 1: { + msg.message = client ? Msg.WM_LBUTTONDBLCLK : Msg.WM_NCLBUTTONDBLCLK; + break; + } + + case 2: { + msg.message = client ? Msg.WM_MBUTTONDBLCLK : Msg.WM_NCMBUTTONDBLCLK; + break; + } + + case 3: { + msg.message = client ? Msg.WM_RBUTTONDBLCLK : Msg.WM_NCRBUTTONDBLCLK; + break; + } + } + ClickPending.Pending = false; + } else { + ClickPending.Pending = true; + ClickPending.Hwnd = msg.hwnd; + ClickPending.Message = msg.message; + ClickPending.wParam = msg.wParam; + ClickPending.lParam = msg.lParam; + ClickPending.Time = (long)xevent.ButtonEvent.time; + } + + if (msg.message == Msg.WM_LBUTTONDOWN || msg.message == Msg.WM_MBUTTONDOWN || msg.message == Msg.WM_RBUTTONDOWN) { + SendParentNotify(msg.hwnd, msg.message, mouse_position.X, mouse_position.Y); + } + + break; + } + + case XEventName.ButtonRelease: { + switch(xevent.ButtonEvent.button) { + case 1: { + if (client) { + msg.message = Msg.WM_LBUTTONUP; + } else { + msg.message = Msg.WM_NCLBUTTONUP; + msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y); + MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + MouseState &= ~MouseButtons.Left; + msg.wParam = GetMousewParam (0); + break; + } + + case 2: { + if (client) { + msg.message = Msg.WM_MBUTTONUP; + } else { + msg.message = Msg.WM_NCMBUTTONUP; + msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y); + MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + MouseState &= ~MouseButtons.Middle; + msg.wParam = GetMousewParam (0); + break; + } + + case 3: { + if (client) { + msg.message = Msg.WM_RBUTTONUP; + } else { + msg.message = Msg.WM_NCRBUTTONUP; + msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y); + MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + MouseState &= ~MouseButtons.Right; + msg.wParam = GetMousewParam (0); + break; + } + + case 4: { + goto ProcessNextMessage; + } + + case 5: { + goto ProcessNextMessage; + } + } + + if (!hwnd.Enabled) { + IntPtr dummy; + + msg.hwnd = hwnd.EnabledHwnd; + XTranslateCoordinates(DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, xevent.ButtonEvent.x, xevent.ButtonEvent.y, out xevent.ButtonEvent.x, out xevent.ButtonEvent.y, out dummy); + msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X); + } + + if (Grab.Hwnd != IntPtr.Zero) { + msg.hwnd = Grab.Hwnd; + } + + msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x); + mouse_position.X = xevent.ButtonEvent.x; + mouse_position.Y = xevent.ButtonEvent.y; + + // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or + // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after + // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh* + if (msg.message == Msg.WM_LBUTTONUP || msg.message == Msg.WM_MBUTTONUP || msg.message == Msg.WM_RBUTTONUP) { + XEvent motionEvent = new XEvent (); + motionEvent.type = XEventName.MotionNotify; + motionEvent.MotionEvent.display = DisplayHandle; + motionEvent.MotionEvent.window = xevent.ButtonEvent.window; + motionEvent.MotionEvent.x = xevent.ButtonEvent.x; + motionEvent.MotionEvent.y = xevent.ButtonEvent.y; + hwnd.Queue.EnqueueLocked (motionEvent); + } + break; + } + + case XEventName.MotionNotify: { + if (client) { + DriverDebug("GetMessage(): Window {0:X} MotionNotify x={1} y={2}", + client ? hwnd.client_window.ToInt32() : hwnd.whole_window.ToInt32(), + xevent.MotionEvent.x, xevent.MotionEvent.y); + + if (Grab.Hwnd != IntPtr.Zero) { + msg.hwnd = Grab.Hwnd; + } else { + if (hwnd.Enabled) { + NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT); + } + } + + if (xevent.MotionEvent.is_hint != 0) + { + IntPtr root, child; + int mask; + XQueryPointer (DisplayHandle, xevent.AnyEvent.window, + out root, out child, + out xevent.MotionEvent.x_root, + out xevent.MotionEvent.y_root, + out xevent.MotionEvent.x, + out xevent.MotionEvent.y, out mask); + } + + msg.message = Msg.WM_MOUSEMOVE; + msg.wParam = GetMousewParam(0); + msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF); + + if (!hwnd.Enabled) { + IntPtr dummy; + + msg.hwnd = hwnd.EnabledHwnd; + XTranslateCoordinates(DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, xevent.MotionEvent.x, xevent.MotionEvent.y, out xevent.MotionEvent.x, out xevent.MotionEvent.y, out dummy); + msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X); + } + + mouse_position.X = xevent.MotionEvent.x; + mouse_position.Y = xevent.MotionEvent.y; + + if ((HoverState.Timer.Enabled) && + (((mouse_position.X + HoverState.Size.Width) < HoverState.X) || + ((mouse_position.X - HoverState.Size.Width) > HoverState.X) || + ((mouse_position.Y + HoverState.Size.Height) < HoverState.Y) || + ((mouse_position.Y - HoverState.Size.Height) > HoverState.Y))) { + HoverState.Timer.Stop(); + HoverState.Timer.Start(); + HoverState.X = mouse_position.X; + HoverState.Y = mouse_position.Y; + } + + break; + } else { + HitTest ht; + IntPtr dummy; + + DriverDebug("GetMessage(): non-client area {0:X} MotionNotify x={1} y={2}", + client ? hwnd.client_window.ToInt32() : hwnd.whole_window.ToInt32(), + xevent.MotionEvent.x, xevent.MotionEvent.y); + msg.message = Msg.WM_NCMOUSEMOVE; + + if (!hwnd.Enabled) { + msg.hwnd = hwnd.EnabledHwnd; + XTranslateCoordinates(DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, xevent.MotionEvent.x, xevent.MotionEvent.y, out xevent.MotionEvent.x, out xevent.MotionEvent.y, out dummy); + msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X); + } + + ht = NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y); + NativeWindow.WndProc(hwnd.client_window, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)ht); + + mouse_position.X = xevent.MotionEvent.x; + mouse_position.Y = xevent.MotionEvent.y; + } + + break; + } + + case XEventName.EnterNotify: { + if (!hwnd.Enabled) { + goto ProcessNextMessage; + } + if (xevent.CrossingEvent.mode == NotifyMode.NotifyGrab || xevent.AnyEvent.window != hwnd.client_window) { + goto ProcessNextMessage; + } + if (xevent.CrossingEvent.mode == NotifyMode.NotifyUngrab) { // Pseudo motion caused by grabbing + if (LastPointerWindow == xevent.AnyEvent.window) + goto ProcessNextMessage; + + if (LastPointerWindow != IntPtr.Zero) { + Point enter_loc = new Point (xevent.ButtonEvent.x, xevent.ButtonEvent.y); + + // We need this due to EnterNotify being fired on all the parent Widgets + // of the Widget being grabbed, and obviously in that scenario we are not + // actuallty entering them + Widget ctrl = Widget.FromHandle (hwnd.client_window); + foreach (Widget child_Widget in ctrl.Widgets.GetAllWidgets ()) + if (child_Widget.Bounds.Contains (enter_loc)) + goto ProcessNextMessage; + + // A MouseLeave/LeaveNotify event is sent to the previous window + // until the mouse is ungrabbed, not when actually leaving its bounds + int x = xevent.CrossingEvent.x_root; + int y = xevent.CrossingEvent.y_root; + ScreenToClient (LastPointerWindow, ref x, ref y); + + XEvent leaveEvent = new XEvent (); + leaveEvent.type = XEventName.LeaveNotify; + leaveEvent.CrossingEvent.display = DisplayHandle; + leaveEvent.CrossingEvent.window = LastPointerWindow; + leaveEvent.CrossingEvent.x = x; + leaveEvent.CrossingEvent.y = y; + leaveEvent.CrossingEvent.mode = NotifyMode.NotifyNormal; + Hwnd last_pointer_hwnd = Hwnd.ObjectFromHandle (LastPointerWindow); + last_pointer_hwnd.Queue.EnqueueLocked (leaveEvent); + } + } + + LastPointerWindow = xevent.AnyEvent.window; + + msg.message = Msg.WM_MOUSE_ENTER; + HoverState.X = xevent.CrossingEvent.x; + HoverState.Y = xevent.CrossingEvent.y; + HoverState.Timer.Enabled = true; + HoverState.Window = xevent.CrossingEvent.window; + + // Win32 sends a WM_MOUSEMOVE after mouse enter + XEvent motionEvent = new XEvent (); + motionEvent.type = XEventName.MotionNotify; + motionEvent.MotionEvent.display = DisplayHandle; + motionEvent.MotionEvent.window = xevent.ButtonEvent.window; + motionEvent.MotionEvent.x = xevent.ButtonEvent.x; + motionEvent.MotionEvent.y = xevent.ButtonEvent.y; + hwnd.Queue.EnqueueLocked (motionEvent); + break; + } + + case XEventName.LeaveNotify: { + if (xevent.CrossingEvent.mode == NotifyMode.NotifyUngrab) { + WindowUngrabbed (hwnd.Handle); + goto ProcessNextMessage; + } + if (!hwnd.Enabled) { + goto ProcessNextMessage; + } + if ((xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) || (xevent.CrossingEvent.window != hwnd.client_window)) { + goto ProcessNextMessage; + } + // If a grab is taking place, ignore it - we handle it in EnterNotify + if (Grab.Hwnd != IntPtr.Zero) + goto ProcessNextMessage; + + // Reset the cursor explicitly on X11. + // X11 remembers the last set cursor for the window and in cases where + // the Widget won't get a WM_SETCURSOR X11 will restore the last + // known cursor, which we don't want. + // + SetCursor (hwnd.client_window, IntPtr.Zero); + + msg.message=Msg.WM_MOUSELEAVE; + HoverState.Timer.Enabled = false; + HoverState.Window = IntPtr.Zero; + break; + } + + #if later + case XEventName.CreateNotify: { + if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { + msg.message = WM_CREATE; + // Set up CreateStruct + } else { + goto ProcessNextMessage; + } + break; + } + #endif + + + case XEventName.ReparentNotify: { + if (hwnd.parent == null) { // Toplevel + if ((xevent.ReparentEvent.parent != IntPtr.Zero) && (xevent.ReparentEvent.window == hwnd.whole_window)) { + hwnd.Reparented = true; + + // The location given by the event is not reliable between different wm's, + // so use an alternative way of getting it. + Point location = GetTopLevelWindowLocation (hwnd); + hwnd.X = location.X; + hwnd.Y = location.Y; + + if (hwnd.opacity != 0xffffffff) { + IntPtr opacity; + + opacity = (IntPtr)(Int32)hwnd.opacity; + XChangeProperty(DisplayHandle, XGetParent(hwnd.whole_window), _NET_WM_WINDOW_OPACITY, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1); + } + SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, msg.wParam, msg.lParam); + goto ProcessNextMessage; + } else { + hwnd.Reparented = false; + goto ProcessNextMessage; + } + } + goto ProcessNextMessage; + } + + case XEventName.ConfigureNotify: { + if (!client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas + DriverDebug("GetMessage(): Window {0:X} ConfigureNotify x={1} y={2} width={3} height={4}", + hwnd.client_window.ToInt32(), xevent.ConfigureEvent.x, + xevent.ConfigureEvent.y, xevent.ConfigureEvent.width, xevent.ConfigureEvent.height); + + lock (hwnd.configure_lock) { + Form form = Widget.FromHandle (hwnd.client_window) as Form; + if (form != null && !hwnd.resizing_or_moving) { + if (hwnd.x != form.Bounds.X || hwnd.y != form.Bounds.Y) { + SendMessage (form.Handle, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_MOVE, IntPtr.Zero); + hwnd.resizing_or_moving = true; + } else if (hwnd.width != form.Bounds.Width || hwnd.height != form.Bounds.Height) { + SendMessage (form.Handle, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_SIZE, IntPtr.Zero); + hwnd.resizing_or_moving = true; + } + if (hwnd.resizing_or_moving) + SendMessage (form.Handle, Msg.WM_ENTERSIZEMOVE, IntPtr.Zero, IntPtr.Zero); + } + + SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + hwnd.configure_pending = false; + + // We need to adjust our client window to track the resize of whole_window + if (hwnd.whole_window != hwnd.client_window) + PerformNCCalc(hwnd); + } + } + goto ProcessNextMessage; + } + + case XEventName.FocusIn: { + // We received focus. We use X11 focus only to know if the app window does or does not have focus + // We do not track the actual focussed window via it. Instead, this is done via FocusWindow internally + // Receiving focus means we've gotten activated and therefore we need to let the actual FocusWindow know + // about it having focus again + if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) { + goto ProcessNextMessage; + } + + + if (FocusWindow == IntPtr.Zero) { + Widget c = Widget.FromHandle (hwnd.client_window); + + if (c == null) + goto ProcessNextMessage; + Form form = c.FindForm (); + if (form == null) + goto ProcessNextMessage; + + if (ActiveWindow != form.Handle) { + ActiveWindow = form.Handle; + SendMessage (ActiveWindow, Msg.WM_ACTIVATE, (IntPtr) WindowActiveFlags.WA_ACTIVE, IntPtr.Zero); + } + goto ProcessNextMessage; + } + Keyboard.FocusIn (FocusWindow); + SendMessage(FocusWindow, Msg.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero); + goto ProcessNextMessage; + } + + case XEventName.FocusOut: { + // Se the comment for our FocusIn handler + if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) { + goto ProcessNextMessage; + } + + while (Keyboard.ResetKeyState(FocusWindow, ref msg)) { + SendMessage(FocusWindow, msg.message, msg.wParam, msg.lParam); + } + + Keyboard.FocusOut(hwnd.client_window); + SendMessage(FocusWindow, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero); + goto ProcessNextMessage; + } + + // We are already firing WM_SHOWWINDOW messages in the proper places, but I'm leaving this code + // in case we break a scenario not taken into account in the tests + case XEventName.MapNotify: { + /*if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas + hwnd.mapped = true; + msg.message = Msg.WM_SHOWWINDOW; + msg.wParam = (IntPtr) 1; + // XXX we're missing the lParam.. + break; + }*/ + goto ProcessNextMessage; + } + + case XEventName.UnmapNotify: { + /*if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas + hwnd.mapped = false; + msg.message = Msg.WM_SHOWWINDOW; + msg.wParam = (IntPtr) 0; + // XXX we're missing the lParam.. + break; + }*/ + goto ProcessNextMessage; + } + + case XEventName.Expose: { + if (!hwnd.Mapped) { + if (client) { + hwnd.expose_pending = false; + } else { + hwnd.nc_expose_pending = false; + } + goto ProcessNextMessage; + } + + if (client) { + if (!hwnd.expose_pending) { + goto ProcessNextMessage; + } + } else { + if (!hwnd.nc_expose_pending) { + goto ProcessNextMessage; + } + + switch (hwnd.border_style) { + case FormBorderStyle.Fixed3D: { + Graphics g; + + g = Graphics.FromHwnd(hwnd.whole_window); + if (hwnd.border_static) + WidgetPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.SunkenOuter); + else + WidgetPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.Sunken); + g.Dispose(); + break; + } + + case FormBorderStyle.FixedSingle: { + Graphics g; + + g = Graphics.FromHwnd(hwnd.whole_window); + WidgetPaint.DrawBorder(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Color.Black, ButtonBorderStyle.Solid); + g.Dispose(); + break; + } + } + DriverDebug("GetMessage(): Window {0:X} Exposed non-client area {1},{2} {3}x{4}", + hwnd.client_window.ToInt32(), xevent.ExposeEvent.x, xevent.ExposeEvent.y, + xevent.ExposeEvent.width, xevent.ExposeEvent.height); + + Rectangle rect = new Rectangle (xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height); + Region region = new Region (rect); + IntPtr hrgn = region.GetHrgn (null); // Graphics object isn't needed + msg.message = Msg.WM_NCPAINT; + msg.wParam = hrgn == IntPtr.Zero ? (IntPtr)1 : hrgn; + msg.refobject = region; + break; + } + DriverDebug("GetMessage(): Window {0:X} Exposed area {1},{2} {3}x{4}", + hwnd.client_window.ToInt32(), xevent.ExposeEvent.x, xevent.ExposeEvent.y, + xevent.ExposeEvent.width, xevent.ExposeEvent.height); + if (Caret.Visible == true) { + Caret.Paused = true; + HideCaret(); + } + + if (Caret.Visible == true) { + ShowCaret(); + Caret.Paused = false; + } + msg.message = Msg.WM_PAINT; + break; + } + + case XEventName.DestroyNotify: { + + // This is a bit tricky, we don't receive our own DestroyNotify, we only get those for our children + hwnd = Hwnd.ObjectFromHandle(xevent.DestroyWindowEvent.window); + + // We may get multiple for the same window, act only one the first (when Hwnd still knows about it) + if ((hwnd != null) && (hwnd.client_window == xevent.DestroyWindowEvent.window)) { + CleanupCachedWindows (hwnd); + + DriverDebug("Received X11 Destroy Notification for {0}", XplatUI.Window(hwnd.client_window)); + + msg.hwnd = hwnd.client_window; + msg.message=Msg.WM_DESTROY; + hwnd.Dispose(); + } else { + goto ProcessNextMessage; + } + + break; + } + + case XEventName.ClientMessage: { + if (Dnd.HandleClientMessage (ref xevent)) { + goto ProcessNextMessage; + } + + if (xevent.ClientMessageEvent.message_type == AsyncAtom) { + XplatUIDriverSupport.ExecuteClientMessage((GCHandle)xevent.ClientMessageEvent.ptr1); + goto ProcessNextMessage; + } + + if (xevent.ClientMessageEvent.message_type == HoverState.Atom) { + msg.message = Msg.WM_MOUSEHOVER; + msg.wParam = GetMousewParam(0); + msg.lParam = (IntPtr) (xevent.ClientMessageEvent.ptr1); + return true; + } + + if (xevent.ClientMessageEvent.message_type == (IntPtr)PostAtom) { + DebugHelper.Indent (); + DebugHelper.WriteLine (String.Format ("Posted message:" + (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 () + " for 0x{0:x}", xevent.ClientMessageEvent.ptr1.ToInt32 ())); + DebugHelper.Unindent (); + msg.hwnd = xevent.ClientMessageEvent.ptr1; + msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 (); + msg.wParam = xevent.ClientMessageEvent.ptr3; + msg.lParam = xevent.ClientMessageEvent.ptr4; + if (msg.message == (Msg)Msg.WM_QUIT) + return false; + else + return true; + } + + if (xevent.ClientMessageEvent.message_type == _XEMBED) { +#if DriverDebugXEmbed + Console.WriteLine("GOT EMBED MESSAGE {0:X}, detail {1:X}", xevent.ClientMessageEvent.ptr2.ToInt32(), xevent.ClientMessageEvent.ptr3.ToInt32()); +#endif + + if (xevent.ClientMessageEvent.ptr2.ToInt32() == (int)XEmbedMessage.EmbeddedNotify) { + XSizeHints hints = new XSizeHints(); + IntPtr dummy; + + XGetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints, out dummy); + + hwnd.width = hints.max_width; + hwnd.height = hints.max_height; + hwnd.ClientRect = Rectangle.Empty; + SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + } + } + + if (xevent.ClientMessageEvent.message_type == WM_PROTOCOLS) { + if (xevent.ClientMessageEvent.ptr1 == WM_DELETE_WINDOW) { + SendMessage (msg.hwnd, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_CLOSE, IntPtr.Zero); + msg.message = Msg.WM_CLOSE; + return true; + } + + // We should not get this, but I'll leave the code in case we need it in the future + if (xevent.ClientMessageEvent.ptr1 == WM_TAKE_FOCUS) { + goto ProcessNextMessage; + } + } + goto ProcessNextMessage; + } + + default: { + goto ProcessNextMessage; + } + } + + return true; + } + + HitTest NCHitTest (Hwnd hwnd, int x, int y) + { + // The hit test is sent in screen coordinates + IntPtr dummy; + int screen_x, screen_y; + XTranslateCoordinates (DisplayHandle, hwnd.WholeWindow, RootWindow, x, y, out screen_x, out screen_y, out dummy); + return (HitTest) NativeWindow.WndProc (hwnd.client_window, Msg.WM_NCHITTEST, IntPtr.Zero, + (IntPtr) (screen_y << 16 | screen_x & 0xFFFF)); + } + + // Our very basic implementation of MoveResize - we can extend it later + // *if* needed + internal override void BeginMoveResize (IntPtr handle) + { + // We *need* to ungrab the pointer in the current display + XplatUI.UngrabWindow (Grab.Hwnd); + + int x_root, y_root; + GetCursorPos (IntPtr.Zero, out x_root, out y_root); + + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + SendNetWMMessage (hwnd.whole_window, _NET_WM_MOVERESIZE, (IntPtr) x_root, (IntPtr) y_root, + (IntPtr) NetWmMoveResize._NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT, + (IntPtr) 1); // left button + } + + internal override bool GetText(IntPtr handle, out string text) + { + + lock (XlibLock) { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + + XGetWindowProperty(DisplayHandle, handle, + _NET_WM_NAME, IntPtr.Zero, new IntPtr (1), false, + UTF8_STRING, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + + if ((long)nitems > 0 && prop != IntPtr.Zero) { + text = Marshal.PtrToStringUni (prop, (int)nitems); + XFree (prop); + return true; + } + else { + // fallback on the non-_NET property + IntPtr textptr; + + textptr = IntPtr.Zero; + + XFetchName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, ref textptr); + if (textptr != IntPtr.Zero) { + text = Marshal.PtrToStringAnsi(textptr); + XFree(textptr); + return true; + } else { + text = ""; + return false; + } + } + } + } + + internal override void GetWindowPos(IntPtr handle, bool is_toplevel, out int x, out int y, out int width, out int height, out int client_width, out int client_height) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd != null) { + x = hwnd.x; + y = hwnd.y; + width = hwnd.width; + height = hwnd.height; + + PerformNCCalc(hwnd); + + client_width = hwnd.ClientRect.Width; + client_height = hwnd.ClientRect.Height; + + return; + } + + // Should we throw an exception or fail silently? + // throw new ArgumentException("Called with an invalid window handle", "handle"); + + x = 0; + y = 0; + width = 0; + height = 0; + client_width = 0; + client_height = 0; + } + + internal override FormWindowState GetWindowState(IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd.cached_window_state == (FormWindowState)(-1)) + hwnd.cached_window_state = UpdateWindowState (handle); + + return hwnd.cached_window_state; + } + + FormWindowState UpdateWindowState (IntPtr handle) { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + IntPtr atom; + int maximized; + bool minimized; + XWindowAttributes attributes; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + maximized = 0; + minimized = false; + XGetWindowProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE, IntPtr.Zero, new IntPtr (256), false, (IntPtr)Atom.XA_ATOM, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + if (((long)nitems > 0) && (prop != IntPtr.Zero)) { + for (int i = 0; i < (long)nitems; i++) { + atom = (IntPtr)Marshal.ReadInt32(prop, i * 4); + if ((atom == _NET_WM_STATE_MAXIMIZED_HORZ) || (atom == _NET_WM_STATE_MAXIMIZED_VERT)) { + maximized++; + } else if (atom == _NET_WM_STATE_HIDDEN) { + minimized = true; + } + } + XFree(prop); + } + + if (minimized) { + return FormWindowState.Minimized; + } else if (maximized == 2) { + return FormWindowState.Maximized; + } + + attributes = new XWindowAttributes(); + XGetWindowAttributes(DisplayHandle, hwnd.client_window, ref attributes); + if (attributes.map_state == MapState.IsUnmapped) { + return (FormWindowState)(-1); + } + + + return FormWindowState.Normal; + } + + internal override void GrabInfo(out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea) + { + handle = Grab.Hwnd; + GrabConfined = Grab.Confined; + GrabArea = Grab.Area; + } + + internal override void GrabWindow(IntPtr handle, IntPtr confine_to_handle) + { + Hwnd hwnd; + IntPtr confine_to_window; + + confine_to_window = IntPtr.Zero; + + if (confine_to_handle != IntPtr.Zero) { + XWindowAttributes attributes = new XWindowAttributes(); + + hwnd = Hwnd.ObjectFromHandle(confine_to_handle); + + lock (XlibLock) { + XGetWindowAttributes(DisplayHandle, hwnd.client_window, ref attributes); + } + Grab.Area.X = attributes.x; + Grab.Area.Y = attributes.y; + Grab.Area.Width = attributes.width; + Grab.Area.Height = attributes.height; + Grab.Confined = true; + confine_to_window = hwnd.client_window; + } + + Grab.Hwnd = handle; + + hwnd = Hwnd.ObjectFromHandle(handle); + + lock (XlibLock) { + XGrabPointer(DisplayHandle, hwnd.client_window, false, + EventMask.ButtonPressMask | EventMask.ButtonMotionMask | + EventMask.ButtonReleaseMask | EventMask.PointerMotionMask | + EventMask.PointerMotionHintMask | EventMask.LeaveWindowMask, + GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, IntPtr.Zero, IntPtr.Zero); + } + } + + internal override void UngrabWindow(IntPtr hwnd) + { + lock (XlibLock) { + XUngrabPointer(DisplayHandle, IntPtr.Zero); + XFlush(DisplayHandle); + } + WindowUngrabbed (hwnd); + } + + void WindowUngrabbed (IntPtr hwnd) { + bool was_grabbed = Grab.Hwnd != IntPtr.Zero; + + Grab.Hwnd = IntPtr.Zero; + Grab.Confined = false; + + if (was_grabbed) { + // lparam should be the handle to the window gaining the mouse capture, + // but X doesn't seem to give us that information. + // Also only generate WM_CAPTURECHANGED if the window actually was grabbed. + // X will send a NotifyUngrab, but since it comes late sometimes we're + // calling WindowUngrabbed directly from UngrabWindow in order to send + // this WM right away. + SendMessage (hwnd, Msg.WM_CAPTURECHANGED, IntPtr.Zero, IntPtr.Zero); + } + } + + internal override void HandleException(Exception e) + { + StackTrace st = new StackTrace(e, true); + Console.WriteLine("Exception '{0}'", e.Message+st.ToString()); + Console.WriteLine("{0}{1}", e.Message, st.ToString()); + } + + internal override void Invalidate(IntPtr handle, Rectangle rc, bool clear) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (clear) { + AddExpose (hwnd, true, hwnd.X, hwnd.Y, hwnd.Width, hwnd.Height); + } else { + AddExpose (hwnd, true, rc.X, rc.Y, rc.Width, rc.Height); + } + } + + internal override void InvalidateNC (IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + AddExpose (hwnd, hwnd.WholeWindow == hwnd.ClientWindow, 0, 0, hwnd.Width, hwnd.Height); + } + + internal override bool IsEnabled(IntPtr handle) + { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + return (hwnd != null && hwnd.Enabled); + } + + internal override bool IsVisible(IntPtr handle) + { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + return (hwnd != null && hwnd.visible); + } + + internal override void KillTimer(Timer timer) + { + XEventQueue queue = (XEventQueue) MessageQueues [timer.thread]; + + if (queue == null) { + // This isn't really an error, MS doesn't start the timer if + // it has no assosciated queue. In this case, remove the timer + // from the list of unattached timers (if it was enabled). + lock (unattached_timer_list) { + if (unattached_timer_list.Contains (timer)) + unattached_timer_list.Remove (timer); + } + return; + } + queue.timer_list.Remove (timer); + } + + internal override void MenuToScreen(IntPtr handle, ref int x, ref int y) + { + int dest_x_return; + int dest_y_return; + IntPtr child; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + lock (XlibLock) { + XTranslateCoordinates(DisplayHandle, hwnd.whole_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child); + } + + x = dest_x_return; + y = dest_y_return; + } + + internal override void OverrideCursor(IntPtr cursor) + { + if (Grab.Hwnd != IntPtr.Zero) { + XChangeActivePointerGrab (DisplayHandle, + EventMask.ButtonMotionMask | + EventMask.PointerMotionMask | + EventMask.PointerMotionHintMask | + EventMask.ButtonPressMask | + EventMask.ButtonReleaseMask, + cursor, IntPtr.Zero); + return; + } + + OverrideCursorHandle = cursor; + } + + internal override PaintEventArgs PaintEventStart(ref Message msg, IntPtr handle, bool client) + { + PaintEventArgs paint_event; + Hwnd hwnd; + Hwnd paint_hwnd; + + // + // handle (and paint_hwnd) refers to the window that is should be painted. + // msg.HWnd (and hwnd) refers to the window that got the paint message. + // + + hwnd = Hwnd.ObjectFromHandle(msg.HWnd); + if (msg.HWnd == handle) { + paint_hwnd = hwnd; + } else { + paint_hwnd = Hwnd.ObjectFromHandle (handle); + } + + if (Caret.Visible == true) { + Caret.Paused = true; + HideCaret(); + } + + Graphics dc; + + if (client) { + dc = Graphics.FromHwnd (paint_hwnd.client_window); + + Region clip_region = new Region (); + clip_region.MakeEmpty(); + + foreach (Rectangle r in hwnd.ClipRectangles) { + /* Expand the region slightly. + * See bug 464464. + */ + Rectangle r2 = Rectangle.FromLTRB (r.Left, r.Top, r.Right, r.Bottom + 1); + clip_region.Union (r2); + } + + if (hwnd.UserClip != null) { + clip_region.Intersect(hwnd.UserClip); + } + + dc.Clip = clip_region; + paint_event = new PaintEventArgs(dc, hwnd.Invalid); + hwnd.expose_pending = false; + + hwnd.ClearInvalidArea(); + + hwnd.drawing_stack.Push (paint_event); + hwnd.drawing_stack.Push (dc); + + return paint_event; + } else { + dc = Graphics.FromHwnd (paint_hwnd.whole_window); + + if (!hwnd.nc_invalid.IsEmpty) { + dc.SetClip (hwnd.nc_invalid); + paint_event = new PaintEventArgs(dc, hwnd.nc_invalid); + } else { + paint_event = new PaintEventArgs(dc, new Rectangle(0, 0, hwnd.width, hwnd.height)); + } + hwnd.nc_expose_pending = false; + + hwnd.ClearNcInvalidArea (); + + hwnd.drawing_stack.Push (paint_event); + hwnd.drawing_stack.Push (dc); + + return paint_event; + } + } + + internal override void PaintEventEnd(ref Message msg, IntPtr handle, bool client) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (msg.HWnd); + + Graphics dc = (Graphics)hwnd.drawing_stack.Pop (); + dc.Flush(); + dc.Dispose(); + + PaintEventArgs pe = (PaintEventArgs)hwnd.drawing_stack.Pop(); + pe.SetGraphics (null); + pe.Dispose (); + + if (Caret.Visible == true) { + ShowCaret(); + Caret.Paused = false; + } + } + + [MonoTODO("Implement filtering and PM_NOREMOVE")] + internal override bool PeekMessage(Object queue_id, ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) + { + XEventQueue queue = (XEventQueue) queue_id; + bool pending; + + if ((flags & (uint)PeekMessageFlags.PM_REMOVE) == 0) { + throw new NotImplementedException("PeekMessage PM_NOREMOVE is not implemented yet"); // FIXME - Implement PM_NOREMOVE flag + } + + pending = false; + if (queue.Count > 0) { + pending = true; + } else { + // Only call UpdateMessageQueue if real events are pending + // otherwise we go to sleep on the socket + if (XPending(DisplayHandle) != 0) { + UpdateMessageQueue((XEventQueue)queue_id); + pending = true; + } else if (((XEventQueue)queue_id).Paint.Count > 0) { + pending = true; + } + } + + CheckTimers(queue.timer_list, DateTime.UtcNow); + + if (!pending) { + return false; + } + return GetMessage(queue_id, ref msg, hWnd, wFilterMin, wFilterMax); + } + + internal override bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam) + { + XEvent xevent = new XEvent (); + Hwnd hwnd = Hwnd.ObjectFromHandle(handle); + + xevent.type = XEventName.ClientMessage; + xevent.ClientMessageEvent.display = DisplayHandle; + + if (hwnd != null) { + xevent.ClientMessageEvent.window = hwnd.whole_window; + } else { + xevent.ClientMessageEvent.window = IntPtr.Zero; + } + + xevent.ClientMessageEvent.message_type = (IntPtr) PostAtom; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = handle; + xevent.ClientMessageEvent.ptr2 = (IntPtr) message; + xevent.ClientMessageEvent.ptr3 = wparam; + xevent.ClientMessageEvent.ptr4 = lparam; + + if (hwnd != null) + hwnd.Queue.EnqueueLocked (xevent); + else + ThreadQueue(Thread.CurrentThread).EnqueueLocked (xevent); + + return true; + } + + internal override void PostQuitMessage(int exitCode) + { + ApplicationContext ctx = Application.MWFThread.Current.Context; + Form f = ctx != null ? ctx.MainForm : null; + if (f != null) + PostMessage (Application.MWFThread.Current.Context.MainForm.window.Handle, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero); + else + PostMessage (FosterParent, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero); + XFlush(DisplayHandle); + } + + internal override void RequestAdditionalWM_NCMessages(IntPtr hwnd, bool hover, bool leave) + { + // TODO + } + + internal override void RequestNCRecalc(IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd == null) { + return; + } + + PerformNCCalc(hwnd); + SendMessage(handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + InvalidateNC(handle); + } + + internal override void ResetMouseHover(IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + if (hwnd == null) { + return; + } + + HoverState.Timer.Enabled = true; + HoverState.X = mouse_position.X; + HoverState.Y = mouse_position.Y; + HoverState.Window = handle; + } + + + internal override void ScreenToClient(IntPtr handle, ref int x, ref int y) + { + int dest_x_return; + int dest_y_return; + IntPtr child; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + lock (XlibLock) { + XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.client_window, x, y, out dest_x_return, out dest_y_return, out child); + } + + x = dest_x_return; + y = dest_y_return; + } + + internal override void ScreenToMenu(IntPtr handle, ref int x, ref int y) + { + int dest_x_return; + int dest_y_return; + IntPtr child; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + lock (XlibLock) { + XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.whole_window, x, y, out dest_x_return, out dest_y_return, out child); + } + + Form form = Widget.FromHandle (handle) as Form; + if (form != null && form.window_manager != null) { + dest_y_return -= form.window_manager.TitleBarHeight; + } + + x = dest_x_return; + y = dest_y_return; + } + + bool GraphicsExposePredicate (IntPtr display, ref XEvent xevent, IntPtr arg) + { + return (xevent.type == XEventName.GraphicsExpose || xevent.type == XEventName.NoExpose) && + arg == xevent.GraphicsExposeEvent.drawable; + } + + delegate bool EventPredicate (IntPtr display, ref XEvent xevent, IntPtr arg); + + void ProcessGraphicsExpose (Hwnd hwnd) + { + XEvent xevent = new XEvent (); + IntPtr handle = Hwnd.HandleFromObject (hwnd); + EventPredicate predicate = GraphicsExposePredicate; + + for (;;) { + XIfEvent (Display, ref xevent, predicate, handle); + if (xevent.type != XEventName.GraphicsExpose) + break; + + AddExpose (hwnd, xevent.ExposeEvent.window == hwnd.ClientWindow, xevent.GraphicsExposeEvent.x, xevent.GraphicsExposeEvent.y, + xevent.GraphicsExposeEvent.width, xevent.GraphicsExposeEvent.height); + + if (xevent.GraphicsExposeEvent.count == 0) + break; + } + } + + internal override void ScrollWindow(IntPtr handle, Rectangle area, int XAmount, int YAmount, bool with_children) + { + Hwnd hwnd; + IntPtr gc; + XGCValues gc_values; + + hwnd = Hwnd.ObjectFromHandle(handle); + + Rectangle r = Rectangle.Intersect (hwnd.Invalid, area); + if (!r.IsEmpty) { + /* We have an invalid area in the window we're scrolling. + Adjust our stored invalid rectangle to to match the scrolled amount */ + + r.X += XAmount; + r.Y += YAmount; + + if (r.X < 0) { + r.Width += r.X; + r.X =0; + } + + if (r.Y < 0) { + r.Height += r.Y; + r.Y =0; + } + + if (area.Contains (hwnd.Invalid)) + hwnd.ClearInvalidArea (); + hwnd.AddInvalidArea(r); + } + + gc_values = new XGCValues(); + + if (with_children) { + gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors; + } + + gc = XCreateGC(DisplayHandle, hwnd.client_window, IntPtr.Zero, ref gc_values); + + Rectangle visible_rect = GetTotalVisibleArea (hwnd.client_window); + visible_rect.Intersect (area); + + Rectangle dest_rect = visible_rect; + dest_rect.Y += YAmount; + dest_rect.X += XAmount; + dest_rect.Intersect (area); + + Point src = new Point (dest_rect.X - XAmount, dest_rect.Y - YAmount); + XCopyArea (DisplayHandle, hwnd.client_window, hwnd.client_window, gc, src.X, src.Y, + dest_rect.Width, dest_rect.Height, dest_rect.X, dest_rect.Y); + + Rectangle dirty_area = GetDirtyArea (area, dest_rect, XAmount, YAmount); + AddExpose (hwnd, true, dirty_area.X, dirty_area.Y, dirty_area.Width, dirty_area.Height); + + ProcessGraphicsExpose (hwnd); + + XFreeGC(DisplayHandle, gc); + } + + internal override void ScrollWindow(IntPtr handle, int XAmount, int YAmount, bool with_children) + { + Hwnd hwnd; + Rectangle rect; + + hwnd = Hwnd.GetObjectFromWindow(handle); + + rect = hwnd.ClientRect; + rect.X = 0; + rect.Y = 0; + ScrollWindow(handle, rect, XAmount, YAmount, with_children); + } + + Rectangle GetDirtyArea (Rectangle total_area, Rectangle valid_area, int XAmount, int YAmount) + { + Rectangle dirty_area = total_area; + + if (YAmount > 0) + dirty_area.Height -= valid_area.Height; + else if (YAmount < 0) { + dirty_area.Height -= valid_area.Height; + dirty_area.Y += valid_area.Height; + } + + if (XAmount > 0) + dirty_area.Width -= valid_area.Width; + else if (XAmount < 0) { + dirty_area.Width -= valid_area.Width; + dirty_area.X += valid_area.Width; + } + + return dirty_area; + } + + Rectangle GetTotalVisibleArea (IntPtr handle) + { + Widget c = Widget.FromHandle (handle); + + Rectangle visible_area = c.ClientRectangle; + visible_area.Location = c.PointToScreen (Point.Empty); + + for (Widget parent = c.Parent; parent != null; parent = parent.Parent) { + if (!parent.IsHandleCreated || !parent.Visible) + return visible_area; // Non visible, not need to finish computations + + Rectangle r = parent.ClientRectangle; + r.Location = parent.PointToScreen (Point.Empty); + + visible_area.Intersect (r); + } + + visible_area.Location = c.PointToClient (visible_area.Location); + return visible_area; + } + + internal override void SendAsyncMethod (AsyncMethodData method) + { + Hwnd hwnd; + XEvent xevent = new XEvent (); + + hwnd = Hwnd.ObjectFromHandle(method.Handle); + + xevent.type = XEventName.ClientMessage; + xevent.ClientMessageEvent.display = DisplayHandle; + xevent.ClientMessageEvent.window = method.Handle; + xevent.ClientMessageEvent.message_type = (IntPtr)AsyncAtom; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = (IntPtr) GCHandle.Alloc (method); + + hwnd.Queue.EnqueueLocked (xevent); + + WakeupMain (); + } + + delegate IntPtr WndProcDelegate (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam); + + internal override IntPtr SendMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam) + { + Hwnd h; + h = Hwnd.ObjectFromHandle(hwnd); + + if (h != null && h.queue != ThreadQueue (Thread.CurrentThread)) { + AsyncMethodResult result; + AsyncMethodData data; + + result = new AsyncMethodResult (); + data = new AsyncMethodData (); + + data.Handle = hwnd; + data.Method = new WndProcDelegate (NativeWindow.WndProc); + data.Args = new object[] { hwnd, message, wParam, lParam }; + data.Result = result; + + SendAsyncMethod (data); + DriverDebug("Sending {0} message across.", message); + + return IntPtr.Zero; + } + string key = hwnd + ":" + message; + if (messageHold[key] != null) + messageHold[key] = ((int)messageHold[key]) - 1; + return NativeWindow.WndProc(hwnd, message, wParam, lParam); + } + + internal override int SendInput(IntPtr handle, Queue keys) + { + if (handle == IntPtr.Zero) + return 0; + + int count = keys.Count; + Hwnd hwnd = Hwnd.ObjectFromHandle(handle); + + while (keys.Count > 0) { + + MSG msg = (MSG)keys.Dequeue(); + + XEvent xevent = new XEvent (); + + xevent.type = (msg.message == Msg.WM_KEYUP ? XEventName.KeyRelease : XEventName.KeyPress); + xevent.KeyEvent.display = DisplayHandle; + + if (hwnd != null) { + xevent.KeyEvent.window = hwnd.whole_window; + } else { + xevent.KeyEvent.window = IntPtr.Zero; + } + + xevent.KeyEvent.keycode = Keyboard.ToKeycode((int)msg.wParam); + + hwnd.Queue.EnqueueLocked (xevent); + } + return count; + } + + internal override void SetAllowDrop (IntPtr handle, bool value) + { + // We allow drop on all windows + } + + internal override DragDropEffects StartDrag (IntPtr handle, object data, + DragDropEffects allowed_effects) + { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd == null) + throw new ArgumentException ("Attempt to begin drag from invalid window handle (" + handle.ToInt32 () + ")."); + + return Dnd.StartDrag (hwnd.client_window, data, allowed_effects); + } + + internal override void SetBorderStyle(IntPtr handle, FormBorderStyle border_style) + { + Form form = Widget.FromHandle (handle) as Form; + if (form != null && form.window_manager == null) { + CreateParams cp = form.GetCreateParams (); + if (border_style == FormBorderStyle.FixedToolWindow || + border_style == FormBorderStyle.SizableToolWindow || + cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) { + form.window_manager = new ToolWindowManager (form); + } + } + + RequestNCRecalc(handle); + } + + internal override void SetCaretPos(IntPtr handle, int x, int y) + { + if (Caret.Hwnd == handle) { + Caret.Timer.Stop(); + HideCaret(); + + Caret.X = x; + Caret.Y = y; + + Keyboard.SetCaretPos (Caret, handle, x, y); + + if (Caret.Visible == true) { + ShowCaret(); + Caret.Timer.Start(); + } + } + } + + internal override void SetClipRegion(IntPtr handle, Region region) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + if (hwnd == null) { + return; + } + + hwnd.UserClip = region; + } + + internal override void SetCursor(IntPtr handle, IntPtr cursor) + { + Hwnd hwnd; + + if (OverrideCursorHandle == IntPtr.Zero) { + if ((LastCursorWindow == handle) && (LastCursorHandle == cursor)) { + return; + } + + LastCursorHandle = cursor; + LastCursorWindow = handle; + + hwnd = Hwnd.ObjectFromHandle(handle); + lock (XlibLock) { + if (cursor != IntPtr.Zero) { + XDefineCursor(DisplayHandle, hwnd.whole_window, cursor); + } else { + XUndefineCursor(DisplayHandle, hwnd.whole_window); + } + XFlush(DisplayHandle); + } + return; + } + + hwnd = Hwnd.ObjectFromHandle(handle); + lock (XlibLock) { + XDefineCursor(DisplayHandle, hwnd.whole_window, OverrideCursorHandle); + } + } + + void QueryPointer (IntPtr display, IntPtr w, out IntPtr root, out IntPtr child, + out int root_x, out int root_y, out int child_x, out int child_y, + out int mask) + { + /* this code was written with the help of + glance at gdk. I never would have realized we + needed a loop in order to traverse down in the + hierarchy. I would have assumed you'd get the + most deeply nested child and have to do + XQueryTree to move back up the hierarchy.. + stupid me, of course. */ + IntPtr c; + + XGrabServer (display); + + XQueryPointer(display, w, out root, out c, + out root_x, out root_y, out child_x, out child_y, + out mask); + + if (root != w) + c = root; + + IntPtr child_last = IntPtr.Zero; + while (c != IntPtr.Zero) { + child_last = c; + XQueryPointer(display, c, out root, out c, + out root_x, out root_y, out child_x, out child_y, + out mask); + } + XUngrabServer (display); + XFlush (display); + + child = child_last; + } + + internal override void SetCursorPos(IntPtr handle, int x, int y) + { + if (handle == IntPtr.Zero) { + lock (XlibLock) { + IntPtr root, child; + int root_x, root_y, child_x, child_y, mask; + + /* we need to do a + * QueryPointer before warping + * because if the warp is on + * the RootWindow, the x/y are + * relative to the current + * mouse position + */ + QueryPointer (DisplayHandle, RootWindow, + out root, + out child, + out root_x, out root_y, + out child_x, out child_y, + out mask); + + XWarpPointer(DisplayHandle, IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, x - root_x, y - root_y); + + XFlush (DisplayHandle); + + /* then we need to a + * QueryPointer after warping + * to manually generate a + * motion event for the window + * we move into. + */ + QueryPointer (DisplayHandle, RootWindow, + out root, + out child, + out root_x, out root_y, + out child_x, out child_y, + out mask); + + Hwnd child_hwnd = Hwnd.ObjectFromHandle(child); + if (child_hwnd == null) { + return; + } + + XEvent xevent = new XEvent (); + + xevent.type = XEventName.MotionNotify; + xevent.MotionEvent.display = DisplayHandle; + xevent.MotionEvent.window = child_hwnd.client_window; + xevent.MotionEvent.root = RootWindow; + xevent.MotionEvent.x = child_x; + xevent.MotionEvent.y = child_y; + xevent.MotionEvent.x_root = root_x; + xevent.MotionEvent.y_root = root_y; + xevent.MotionEvent.state = mask; + + child_hwnd.Queue.EnqueueLocked (xevent); + } + } else { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + lock (XlibLock) { + XWarpPointer(DisplayHandle, IntPtr.Zero, hwnd.client_window, 0, 0, 0, 0, x, y); + } + } + } + + internal override void SetFocus(IntPtr handle) + { + Hwnd hwnd; + IntPtr prev_focus_window; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd.client_window == FocusWindow) { + return; + } + + // Win32 doesn't do anything if disabled + if (!hwnd.enabled) + return; + + prev_focus_window = FocusWindow; + FocusWindow = hwnd.client_window; + + if (prev_focus_window != IntPtr.Zero) { + SendMessage(prev_focus_window, Msg.WM_KILLFOCUS, FocusWindow, IntPtr.Zero); + } + Keyboard.FocusIn (FocusWindow); + SendMessage(FocusWindow, Msg.WM_SETFOCUS, prev_focus_window, IntPtr.Zero); + + //XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).client_window, RevertTo.None, IntPtr.Zero); + } + + internal override void SetIcon(IntPtr handle, Icon icon) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + if (hwnd != null) { + SetIcon(hwnd, icon); + } + } + + internal override void SetMenu(IntPtr handle, Menu menu) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + hwnd.menu = menu; + + RequestNCRecalc(handle); + } + + internal override void SetModal(IntPtr handle, bool Modal) + { + if (Modal) { + ModalWindows.Push(handle); + } else { + if (ModalWindows.Contains(handle)) { + ModalWindows.Pop(); + } + if (ModalWindows.Count > 0) { + Activate((IntPtr)ModalWindows.Peek()); + } + } + + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + Widget ctrl = Widget.FromHandle (handle); + SetWMStyles (hwnd, ctrl.GetCreateParams ()); + } + + internal override IntPtr SetParent(IntPtr handle, IntPtr parent) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + hwnd.parent = Hwnd.ObjectFromHandle(parent); + + lock (XlibLock) { + DriverDebug("Parent for window {0} = {1}", XplatUI.Window(hwnd.Handle), XplatUI.Window(hwnd.parent != null ? hwnd.parent.Handle : IntPtr.Zero)); + XReparentWindow(DisplayHandle, hwnd.whole_window, hwnd.parent == null ? FosterParent : hwnd.parent.client_window, hwnd.x, hwnd.y); + } + + return IntPtr.Zero; + } + + internal override void SetTimer (Timer timer) + { + XEventQueue queue = (XEventQueue) MessageQueues [timer.thread]; + + if (queue == null) { + // This isn't really an error, MS doesn't start the timer if + // it has no assosciated queue at this stage (it will be + // enabled when a window is activated). + unattached_timer_list.Add (timer); + return; + } + queue.timer_list.Add (timer); + WakeupMain (); + } + + internal override bool SetTopmost(IntPtr handle, bool enabled) + { + + Hwnd hwnd = Hwnd.ObjectFromHandle(handle); + hwnd.topmost = enabled; + + if (enabled) { + lock (XlibLock) { + if (hwnd.Mapped) { + SendNetWMMessage(hwnd.WholeWindow, _NET_WM_STATE, (IntPtr) NetWmStateRequest._NET_WM_STATE_ADD, _NET_WM_STATE_ABOVE, IntPtr.Zero); + } else { + int[] atoms = new int[8]; + atoms[0] = _NET_WM_STATE_ABOVE.ToInt32(); + XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1); + } + } + } else { + lock (XlibLock) { + if (hwnd.Mapped) + SendNetWMMessage(hwnd.WholeWindow, _NET_WM_STATE, (IntPtr) NetWmStateRequest._NET_WM_STATE_REMOVE, _NET_WM_STATE_ABOVE, IntPtr.Zero); + else + XDeleteProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE); + } + } + return true; + } + + internal override bool SetOwner(IntPtr handle, IntPtr handle_owner) + { + Hwnd hwnd; + Hwnd hwnd_owner; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (handle_owner != IntPtr.Zero) { + hwnd_owner = Hwnd.ObjectFromHandle(handle_owner); + lock (XlibLock) { + int[] atoms; + + atoms = new int[8]; + + atoms[0] = _NET_WM_WINDOW_TYPE_NORMAL.ToInt32(); + XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1); + + if (hwnd_owner != null) { + XSetTransientForHint(DisplayHandle, hwnd.whole_window, hwnd_owner.whole_window); + } else { + XSetTransientForHint(DisplayHandle, hwnd.whole_window, RootWindow); + } + } + } else { + lock (XlibLock) { + XDeleteProperty(DisplayHandle, hwnd.whole_window, (IntPtr)Atom.XA_WM_TRANSIENT_FOR); + } + } + return true; + } + + internal override bool SetVisible (IntPtr handle, bool visible, bool activate) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + hwnd.visible = visible; + + lock (XlibLock) { + if (visible) { + MapWindow(hwnd, WindowType.Both); + + if (Widget.FromHandle(handle) is Form) { + FormWindowState s; + + s = ((Form)Widget.FromHandle(handle)).WindowState; + + switch(s) { + case FormWindowState.Minimized: SetWindowState(handle, FormWindowState.Minimized); break; + case FormWindowState.Maximized: SetWindowState(handle, FormWindowState.Maximized); break; + } + } + + SendMessage(handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + } + else { + UnmapWindow(hwnd, WindowType.Both); + } + } + return true; + } + + internal override void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max) + { + Widget ctrl = Widget.FromHandle (handle); + SetWindowMinMax (handle, maximized, min, max, ctrl != null ? ctrl.GetCreateParams () : null); + } + + internal void SetWindowMinMax (IntPtr handle, Rectangle maximized, Size min, Size max, CreateParams cp) + { + Hwnd hwnd; + XSizeHints hints; + IntPtr dummy; + + hwnd = Hwnd.ObjectFromHandle(handle); + if (hwnd == null) { + return; + } + + min.Width = Math.Max (min.Width, SystemInformation.MinimumWindowSize.Width); + min.Height = Math.Max (min.Height, SystemInformation.MinimumWindowSize.Height); + + hints = new XSizeHints(); + + XGetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints, out dummy); + if ((min != Size.Empty) && (min.Width > 0) && (min.Height > 0)) { + if (cp != null) + min = TranslateWindowSizeToXWindowSize (cp, min); + hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize); + hints.min_width = min.Width; + hints.min_height = min.Height; + } + + if ((max != Size.Empty) && (max.Width > 0) && (max.Height > 0)) { + if (cp != null) + max = TranslateWindowSizeToXWindowSize (cp, max); + hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize); + hints.max_width = max.Width; + hints.max_height = max.Height; + } + + if (hints.flags != IntPtr.Zero) { + // The Metacity team has decided that they won't care about this when clicking the maximize icon, + // they will maximize the window to fill the screen/parent no matter what. + // http://bugzilla.ximian.com/show_bug.cgi?id=80021 + XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints); + } + + if ((maximized != Rectangle.Empty) && (maximized.Width > 0) && (maximized.Height > 0)) { + if (cp != null) + maximized.Size = TranslateWindowSizeToXWindowSize (cp); + hints.flags = (IntPtr)XSizeHintsFlags.PPosition; + hints.x = maximized.X; + hints.y = maximized.Y; + hints.width = maximized.Width; + hints.height = maximized.Height; + + // Metacity does not seem to follow this constraint for maximized (zoomed) windows + XSetZoomHints(DisplayHandle, hwnd.whole_window, ref hints); + } + } + + + internal override void SetWindowPos(IntPtr handle, int x, int y, int width, int height) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd == null) { + return; + } + + // Win32 automatically changes negative width/height to 0. + if (width < 0) + width = 0; + if (height < 0) + height = 0; + + // X requires a sanity check for width & height; otherwise it dies + if (hwnd.zero_sized && width > 0 && height > 0) { + if (hwnd.visible) { + MapWindow(hwnd, WindowType.Whole); + } + hwnd.zero_sized = false; + } + + if ((width < 1) || (height < 1)) { + hwnd.zero_sized = true; + UnmapWindow(hwnd, WindowType.Whole); + } + + // Save a server roundtrip (and prevent a feedback loop) + if ((hwnd.x == x) && (hwnd.y == y) && + (hwnd.width == width) && (hwnd.height == height)) { + return; + } + + if (!hwnd.zero_sized) { + //Hack? + hwnd.x = x; + hwnd.y = y; + hwnd.width = width; + hwnd.height = height; + SendMessage(hwnd.client_window, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); + + if (hwnd.fixed_size) { + SetWindowMinMax(handle, Rectangle.Empty, new Size(width, height), new Size(width, height)); + } + + lock (XlibLock) { + Widget ctrl = Widget.FromHandle (handle); + Size TranslatedSize = TranslateWindowSizeToXWindowSize (ctrl.GetCreateParams (), new Size (width, height)); + MoveResizeWindow (DisplayHandle, hwnd.whole_window, x, y, TranslatedSize.Width, TranslatedSize.Height); + PerformNCCalc(hwnd); + } + } + + // Update our position/size immediately, so + // that future calls to SetWindowPos aren't + // kept from calling XMoveResizeWindow (by the + // "Save a server roundtrip" block above). + hwnd.x = x; + hwnd.y = y; + hwnd.width = width; + hwnd.height = height; + hwnd.ClientRect = Rectangle.Empty; + } + + internal override void SetWindowState(IntPtr handle, FormWindowState state) + { + FormWindowState current_state; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + current_state = GetWindowState(handle); + + if (current_state == state) { + return; + } + + switch(state) { + case FormWindowState.Normal: { + lock (XlibLock) { + if (current_state == FormWindowState.Minimized) { + MapWindow(hwnd, WindowType.Both); + } else if (current_state == FormWindowState.Maximized) { + SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)2 /* toggle */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT); + } + } + Activate(handle); + return; + } + + case FormWindowState.Minimized: { + lock (XlibLock) { + if (current_state == FormWindowState.Maximized) { + SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)2 /* toggle */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT); + } + XIconifyWindow(DisplayHandle, hwnd.whole_window, ScreenNo); + } + return; + } + + case FormWindowState.Maximized: { + lock (XlibLock) { + if (current_state == FormWindowState.Minimized) { + MapWindow(hwnd, WindowType.Both); + } + + SendNetWMMessage(hwnd.whole_window, _NET_WM_STATE, (IntPtr)1 /* Add */, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT); + } + Activate(handle); + return; + } + } + } + + internal override void SetWindowStyle(IntPtr handle, CreateParams cp) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + SetHwndStyles(hwnd, cp); + SetWMStyles(hwnd, cp); + } + + internal override double GetWindowTransparency(IntPtr handle) + { + return 1.0; + } + + internal override void SetWindowTransparency(IntPtr handle, double transparency, Color key) + { + Hwnd hwnd; + IntPtr opacity; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (hwnd == null) { + return; + } + + hwnd.opacity = (uint)(0xffffffff * transparency); + opacity = (IntPtr)hwnd.opacity; + + if (transparency >= 1.0) { + XDeleteProperty (DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_OPACITY); + } else { + XChangeProperty (DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_OPACITY, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1); + } + } + + internal override bool SetZOrder(IntPtr handle, IntPtr after_handle, bool top, bool bottom) + { + Hwnd hwnd = Hwnd.ObjectFromHandle(handle); + + if (!hwnd.mapped) { + return false; + } + + if (top) { + lock (XlibLock) { + XRaiseWindow(DisplayHandle, hwnd.whole_window); + } + return true; + } else if (!bottom) { + Hwnd after_hwnd = null; + + if (after_handle != IntPtr.Zero) { + after_hwnd = Hwnd.ObjectFromHandle(after_handle); + } + + XWindowChanges values = new XWindowChanges(); + + if (after_hwnd == null) { + // Work around metacity 'issues' + int[] atoms; + + atoms = new int[2]; + atoms[0] = unixtime(); + XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_USER_TIME, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, atoms, 1); + + XRaiseWindow(DisplayHandle, hwnd.whole_window); + SendNetWMMessage(hwnd.whole_window, _NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero); + return true; + //throw new ArgumentNullException("after_handle", "Need sibling to adjust z-order"); + } + + values.sibling = after_hwnd.whole_window; + values.stack_mode = StackMode.Below; + + lock (XlibLock) { + XConfigureWindow(DisplayHandle, hwnd.whole_window, ChangeWindowFlags.CWStackMode | ChangeWindowFlags.CWSibling, ref values); + } + } else { + // Bottom + lock (XlibLock) { + XLowerWindow(DisplayHandle, hwnd.whole_window); + } + return true; + } + return false; + } + + internal override void ShowCursor(bool show) + { + ; // FIXME - X11 doesn't 'hide' the cursor. we could create an empty cursor + } + + internal override object StartLoop(Thread thread) + { + XEventQueue q = ThreadQueue(thread); + return q; + } + + internal override TransparencySupport SupportsTransparency() + { + // We need to check if the x compositing manager is running + return TransparencySupport.Set; + } + + internal override bool SystrayAdd(IntPtr handle, string tip, Icon icon, out ToolTip tt) + { + GetSystrayManagerWindow(); + + if (SystrayMgrWindow != IntPtr.Zero) { + XSizeHints size_hints; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + DriverDebug("Adding Systray Whole:{0:X}, Client:{1:X}", hwnd.whole_window.ToInt32(), hwnd.client_window.ToInt32()); + + // Oh boy. + if (hwnd.client_window != hwnd.whole_window) { + Keyboard.DestroyICForWindow (hwnd.client_window); + XDestroyWindow(DisplayHandle, hwnd.client_window); + hwnd.client_window = hwnd.whole_window; + } + + /* by virtue of the way the tests are ordered when determining if it's PAINT + or NCPAINT, client_window == whole_window will always be PAINT. So, if we're + waiting on an nc_expose, drop it and remove the hwnd from the list (unless + there's a pending expose). */ + if (hwnd.nc_expose_pending) { + hwnd.nc_expose_pending = false; + if (!hwnd.expose_pending) + hwnd.Queue.Paint.Remove (hwnd); + } + + // We are going to be directly mapped by the system tray, so mark as mapped + // so we can later properly unmap it. + hwnd.mapped = true; + + size_hints = new XSizeHints(); + + size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize); + + size_hints.min_width = 24; + size_hints.min_height = 24; + size_hints.max_width = 24; + size_hints.max_height = 24; + size_hints.base_width = 24; + size_hints.base_height = 24; + + XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref size_hints); + + int[] atoms = new int[2]; + atoms [0] = 1; // Version 1 + atoms [1] = 1; // we want to be mapped + + // This line cost me 3 days... + XChangeProperty(DisplayHandle, hwnd.whole_window, _XEMBED_INFO, _XEMBED_INFO, 32, PropertyMode.Replace, atoms, 2); + + // Need to pick some reasonable defaults + tt = new ToolTip(); + tt.AutomaticDelay = 350; + tt.InitialDelay = 250; + tt.ReshowDelay = 250; + tt.ShowAlways = true; + + if ((tip != null) && (tip != string.Empty)) { + tt.SetToolTip(Widget.FromHandle(handle), tip); + tt.Active = true; + } else { + tt.Active = false; + } + + SendNetClientMessage(SystrayMgrWindow, _NET_SYSTEM_TRAY_OPCODE, IntPtr.Zero, (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK, hwnd.whole_window); + + return true; + } + tt = null; + return false; + } + + internal override bool SystrayChange(IntPtr handle, string tip, Icon icon, ref ToolTip tt) + { + Widget Widget; + + Widget = Widget.FromHandle(handle); + if (Widget != null && tt != null) { + tt.SetToolTip(Widget, tip); + tt.Active = true; + SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero); + return true; + } else { + return false; + } + } + + internal override void SystrayRemove(IntPtr handle, ref ToolTip tt) + { + + SetVisible (handle, false, false); + + // The caller can now re-dock it later... + if (tt != null) { + tt.Dispose(); + tt = null; + } + // Close any balloon window *we* fired. + ThemeEngine.Current.HideBalloonWindow (handle); + } + + internal override void SystrayBalloon(IntPtr handle, int timeout, string title, string text, ToolTipIcon icon) + { + ThemeEngine.Current.ShowBalloonWindow (handle, timeout, title, text, icon); + SendMessage(handle, Msg.WM_USER, IntPtr.Zero, (IntPtr) Msg.NIN_BALLOONSHOW); + } + + internal override bool Text(IntPtr handle, string text) +{ + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + lock (XlibLock) { + XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_NAME, UTF8_STRING, 8, + PropertyMode.Replace, text, Encoding.UTF8.GetByteCount (text)); + + // XXX this has problems with UTF8. + // we need to either use the actual + // text if it's latin-1, or convert it + // to compound text if it's in a + // different charset. + XStoreName(DisplayHandle, Hwnd.ObjectFromHandle(handle).whole_window, text); + } + return true; + } + + internal override bool TranslateMessage(ref MSG msg) + { + return Keyboard.TranslateMessage (ref msg); + } + + internal override void UpdateWindow(IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(handle); + + if (!hwnd.visible || !hwnd.expose_pending || !hwnd.Mapped) { + return; + } + + SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero); + hwnd.Queue.Paint.Remove(hwnd); + } + + internal override void CreateOffscreenDrawable (IntPtr handle, + int width, int height, + out object offscreen_drawable) + { + IntPtr root_out; + int x_out, y_out, width_out, height_out, border_width_out, depth_out; + + XGetGeometry (DisplayHandle, handle, + out root_out, + out x_out, out y_out, + out width_out, out height_out, + out border_width_out, out depth_out); + + IntPtr pixmap = XCreatePixmap (DisplayHandle, handle, width, height, depth_out); + + offscreen_drawable = pixmap; + + } + + internal override void DestroyOffscreenDrawable (object offscreen_drawable) + { + XFreePixmap (DisplayHandle, (IntPtr)offscreen_drawable); + } + + internal override Graphics GetOffscreenGraphics (object offscreen_drawable) + { + return Graphics.FromHwnd ((IntPtr) offscreen_drawable); + } + + internal override void BlitFromOffscreen (IntPtr dest_handle, + Graphics dest_dc, + object offscreen_drawable, + Graphics offscreen_dc, + Rectangle r) + { + XGCValues gc_values; + IntPtr gc; + + gc_values = new XGCValues(); + + gc = XCreateGC (DisplayHandle, dest_handle, IntPtr.Zero, ref gc_values); + + XCopyArea (DisplayHandle, (IntPtr)offscreen_drawable, dest_handle, + gc, r.X, r.Y, r.Width, r.Height, r.X, r.Y); + + XFreeGC (DisplayHandle, gc); + } + + #endregion // Public Static Methods + + #region Events + internal override event EventHandler Idle; + #endregion // Events + + +#if TRACE && false + +#region Xcursor imports + [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadCursor")] + internal extern static IntPtr XcursorLibraryLoadCursor (IntPtr display, [MarshalAs (UnmanagedType.LPStr)] string name); + + [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadImages")] + internal extern static IntPtr XcursorLibraryLoadImages ([MarshalAs (UnmanagedType.LPStr)] string file, IntPtr theme, int size); + + [DllImport ("libXcursor", EntryPoint = "XcursorImagesDestroy")] + internal extern static void XcursorImagesDestroy (IntPtr images); + + [DllImport ("libXcursor", EntryPoint = "XcursorGetDefaultSize")] + internal extern static int XcursorGetDefaultSize (IntPtr display); + + [DllImport ("libXcursor", EntryPoint = "XcursorImageLoadCursor")] + internal extern static IntPtr XcursorImageLoadCursor (IntPtr display, IntPtr image); + + [DllImport ("libXcursor", EntryPoint = "XcursorGetTheme")] + internal extern static IntPtr XcursorGetTheme (IntPtr display); +#endregion +#region X11 Imports + [DllImport ("libX11", EntryPoint="XOpenDisplay")] + internal extern static IntPtr XOpenDisplay(IntPtr display); + [DllImport ("libX11", EntryPoint="XCloseDisplay")] + internal extern static int XCloseDisplay(IntPtr display); + [DllImport ("libX11", EntryPoint="XSynchronize")] + internal extern static IntPtr XSynchronize(IntPtr display, bool onoff); + + [DllImport ("libX11", EntryPoint="XCreateWindow")] + internal extern static IntPtr _XCreateWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, int depth, int xclass, IntPtr visual, UIntPtr valuemask, ref XSetWindowAttributes attributes); + internal static IntPtr XCreateWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, int depth, int xclass, IntPtr visual, UIntPtr valuemask, ref XSetWindowAttributes attributes) + { + DebugHelper.TraceWriteLine ("XCreateWindow"); + return _XCreateWindow(display, parent, x, y, width, height, + border_width, depth, xclass, visual, valuemask, ref attributes); + } + [DllImport ("libX11", EntryPoint="XCreateSimpleWindow")] + internal extern static IntPtr _XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, UIntPtr border, UIntPtr background); + internal static IntPtr XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, UIntPtr border, UIntPtr background) + { + DebugHelper.TraceWriteLine ("XCreateSimpleWindow"); + return _XCreateSimpleWindow(display, parent, x, y, width, height, border_width, border, background); + } + [DllImport ("libX11", EntryPoint="XMapWindow")] + internal extern static int _XMapWindow(IntPtr display, IntPtr window); + internal static int XMapWindow(IntPtr display, IntPtr window) + { + DebugHelper.TraceWriteLine ("XMapWindow"); + return _XMapWindow(display, window); + } + [DllImport ("libX11", EntryPoint="XMapRaised")] + internal extern static int _XMapRaised(IntPtr display, IntPtr window); + internal static int XMapRaised(IntPtr display, IntPtr window) + { + DebugHelper.TraceWriteLine ("XMapRaised"); + return _XMapRaised(display, window); + } + [DllImport ("libX11", EntryPoint="XUnmapWindow")] + internal extern static int _XUnmapWindow(IntPtr display, IntPtr window); + internal static int XUnmapWindow(IntPtr display, IntPtr window) + { + DebugHelper.TraceWriteLine ("XUnmapWindow"); + return _XUnmapWindow(display, window); + } + [DllImport ("libX11", EntryPoint="XMapSubwindows")] + internal extern static int _XMapSubindows(IntPtr display, IntPtr window); + internal static int XMapSubindows(IntPtr display, IntPtr window) + { + DebugHelper.TraceWriteLine ("XMapSubindows"); + return _XMapSubindows(display, window); + } + [DllImport ("libX11", EntryPoint="XUnmapSubwindows")] + internal extern static int _XUnmapSubwindows(IntPtr display, IntPtr window); + internal static int XUnmapSubwindows(IntPtr display, IntPtr window) + { + DebugHelper.TraceWriteLine ("XUnmapSubwindows"); + return _XUnmapSubwindows(display, window); + } + [DllImport ("libX11", EntryPoint="XRootWindow")] + internal extern static IntPtr _XRootWindow(IntPtr display, int screen_number); + internal static IntPtr XRootWindow(IntPtr display, int screen_number) + { + DebugHelper.TraceWriteLine ("XRootWindow"); + return _XRootWindow(display, screen_number); + } + [DllImport ("libX11", EntryPoint="XNextEvent")] + internal extern static IntPtr _XNextEvent(IntPtr display, ref XEvent xevent); + internal static IntPtr XNextEvent(IntPtr display, ref XEvent xevent) + { + DebugHelper.TraceWriteLine ("XNextEvent"); + return _XNextEvent(display, ref xevent); + } + [DllImport ("libX11", EntryPoint="XConnectionNumber")] + internal extern static int _XConnectionNumber (IntPtr display); + internal static int XConnectionNumber (IntPtr display) + { + DebugHelper.TraceWriteLine ("XConnectionNumber"); + return _XConnectionNumber (display); + } + [DllImport ("libX11", EntryPoint="XPending")] + internal extern static int _XPending (IntPtr display); + internal static int XPending (IntPtr display) + { + DebugHelper.TraceWriteLine ("XPending"); + DebugHelper.DumpCallers (3); + return _XPending (display); + } + [DllImport ("libX11", EntryPoint="XSelectInput")] + internal extern static IntPtr _XSelectInput(IntPtr display, IntPtr window, IntPtr mask); + internal static IntPtr XSelectInput(IntPtr display, IntPtr window, IntPtr mask) + { + DebugHelper.TraceWriteLine ("XSelectInput"); + return _XSelectInput(display, window, mask); + } + + [DllImport ("libX11", EntryPoint="XDestroyWindow")] + internal extern static int _XDestroyWindow(IntPtr display, IntPtr window); + internal static int XDestroyWindow(IntPtr display, IntPtr window) + { + DebugHelper.TraceWriteLine ("XDestroyWindow 0x{0:x}", window.ToInt32()); + return _XDestroyWindow(display, window); + } + + [DllImport ("libX11", EntryPoint="XReparentWindow")] + internal extern static int _XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y); + internal static int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y) + { + DebugHelper.TraceWriteLine ("XReparentWindow"); + return _XReparentWindow(display, window, parent, x, y); + } + + [DllImport ("libX11", EntryPoint="XMoveResizeWindow")] + extern static int _XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height); + static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height) { + DebugHelper.TraceWriteLine ("XMoveResizeWindow"); + return _XMoveResizeWindow(display, window, x, y, width, height); + } + + internal static int MoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height) + { + int ret = XMoveResizeWindow (display, window, x, y, width, height); + Keyboard.MoveCurrentCaretPos (); + return ret; + } + + [DllImport ("libX11", EntryPoint="XResizeWindow")] + internal extern static int _XResizeWindow(IntPtr display, IntPtr window, int width, int height); + internal static int XResizeWindow(IntPtr display, IntPtr window, int width, int height) + { + DebugHelper.TraceWriteLine ("XResizeWindow"); + return _XResizeWindow(display, window, width, height); + } + + [DllImport ("libX11", EntryPoint="XGetWindowAttributes")] + internal extern static int _XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes); + internal static int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes) + { + DebugHelper.TraceWriteLine ("XGetWindowAttributes"); + return _XGetWindowAttributes(display, window, ref attributes); + } + + [DllImport ("libX11", EntryPoint="XFlush")] + internal extern static int _XFlush(IntPtr display); + internal static int XFlush(IntPtr display) + { + DebugHelper.TraceWriteLine ("XFlush"); + return _XFlush(display); + } + + [DllImport ("libX11", EntryPoint="XSetWMName")] + internal extern static int _XSetWMName(IntPtr display, IntPtr window, ref XTextProperty text_prop); + internal static int XSetWMName(IntPtr display, IntPtr window, ref XTextProperty text_prop) + { + DebugHelper.TraceWriteLine ("XSetWMName"); + return _XSetWMName(display, window, ref text_prop); + } + + [DllImport ("libX11", EntryPoint="XStoreName")] + internal extern static int _XStoreName(IntPtr display, IntPtr window, string window_name); + internal static int XStoreName(IntPtr display, IntPtr window, string window_name) + { + DebugHelper.TraceWriteLine ("XStoreName"); + return _XStoreName(display, window, window_name); + } + + [DllImport ("libX11", EntryPoint="XFetchName")] + internal extern static int _XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name); + internal static int XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name) + { + DebugHelper.TraceWriteLine ("XFetchName"); + return _XFetchName(display, window, ref window_name); + } + + [DllImport ("libX11", EntryPoint="XSendEvent")] + internal extern static int _XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask, ref XEvent send_event); + internal static int XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask, ref XEvent send_event) + { + DebugHelper.TraceWriteLine ("XSendEvent"); + return _XSendEvent(display, window, propagate, event_mask, ref send_event); + } + + [DllImport ("libX11", EntryPoint="XQueryTree")] + internal extern static int _XQueryTree(IntPtr display, IntPtr window, out IntPtr root_return, out IntPtr parent_return, out IntPtr children_return, out int nchildren_return); + internal static int XQueryTree(IntPtr display, IntPtr window, out IntPtr root_return, out IntPtr parent_return, out IntPtr children_return, out int nchildren_return) + { + DebugHelper.TraceWriteLine ("XQueryTree"); + return _XQueryTree(display, window, out root_return, out parent_return, out children_return, out nchildren_return); + } + + [DllImport ("libX11", EntryPoint="XFree")] + internal extern static int _XFree(IntPtr data); + internal static int XFree(IntPtr data) + { + DebugHelper.TraceWriteLine ("XFree"); + return _XFree(data); + } + + [DllImport ("libX11", EntryPoint="XRaiseWindow")] + internal extern static int _XRaiseWindow(IntPtr display, IntPtr window); + internal static int XRaiseWindow(IntPtr display, IntPtr window) + { + DebugHelper.TraceWriteLine ("XRaiseWindow"); + return _XRaiseWindow(display, window); + } + + [DllImport ("libX11", EntryPoint="XLowerWindow")] + internal extern static uint _XLowerWindow(IntPtr display, IntPtr window); + internal static uint XLowerWindow(IntPtr display, IntPtr window) + { + DebugHelper.TraceWriteLine ("XLowerWindow"); + return _XLowerWindow(display, window); + } + + [DllImport ("libX11", EntryPoint="XConfigureWindow")] + internal extern static uint _XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values); + internal static uint XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values) + { + DebugHelper.TraceWriteLine ("XConfigureWindow"); + return _XConfigureWindow(display, window, value_mask, ref values); + } + + [DllImport ("libX11", EntryPoint="XInternAtom")] + internal extern static IntPtr _XInternAtom(IntPtr display, string atom_name, bool only_if_exists); + internal static IntPtr XInternAtom(IntPtr display, string atom_name, bool only_if_exists) + { + DebugHelper.TraceWriteLine ("XInternAtom"); + return _XInternAtom(display, atom_name, only_if_exists); + } + + [DllImport ("libX11", EntryPoint="XInternAtoms")] + internal extern static int _XInternAtoms(IntPtr display, string[] atom_names, int atom_count, bool only_if_exists, IntPtr[] atoms); + internal static int XInternAtoms(IntPtr display, string[] atom_names, int atom_count, bool only_if_exists, IntPtr[] atoms) + { + DebugHelper.TraceWriteLine ("XInternAtoms"); + return _XInternAtoms(display, atom_names, atom_count, only_if_exists, atoms); + } + + [DllImport ("libX11", EntryPoint="XSetWMProtocols")] + internal extern static int _XSetWMProtocols(IntPtr display, IntPtr window, IntPtr[] protocols, int count); + internal static int XSetWMProtocols(IntPtr display, IntPtr window, IntPtr[] protocols, int count) + { + DebugHelper.TraceWriteLine ("XSetWMProtocols"); + return _XSetWMProtocols(display, window, protocols, count); + } + + [DllImport ("libX11", EntryPoint="XGrabPointer")] + internal extern static int _XGrabPointer(IntPtr display, IntPtr window, bool owner_events, EventMask event_mask, GrabMode pointer_mode, GrabMode keyboard_mode, IntPtr confine_to, IntPtr cursor, IntPtr timestamp); + internal static int XGrabPointer(IntPtr display, IntPtr window, bool owner_events, EventMask event_mask, GrabMode pointer_mode, GrabMode keyboard_mode, IntPtr confine_to, IntPtr cursor, IntPtr timestamp) + { + DebugHelper.TraceWriteLine ("XGrabPointer"); + return _XGrabPointer(display, window, owner_events, event_mask, pointer_mode, keyboard_mode, confine_to, cursor, timestamp); + } + + [DllImport ("libX11", EntryPoint="XUngrabPointer")] + internal extern static int _XUngrabPointer(IntPtr display, IntPtr timestamp); + internal static int XUngrabPointer(IntPtr display, IntPtr timestamp) + { + DebugHelper.TraceWriteLine ("XUngrabPointer"); + return _XUngrabPointer(display, timestamp); + } + + [DllImport ("libX11", EntryPoint="XQueryPointer")] + internal extern static bool _XQueryPointer(IntPtr display, IntPtr window, out IntPtr root, out IntPtr child, out int root_x, out int root_y, out int win_x, out int win_y, out int keys_buttons); + internal static bool XQueryPointer(IntPtr display, IntPtr window, out IntPtr root, out IntPtr child, out int root_x, out int root_y, out int win_x, out int win_y, out int keys_buttons) + { + DebugHelper.TraceWriteLine ("XQueryPointer"); + return _XQueryPointer(display, window, out root, out child, out root_x, out root_y, out win_x, out win_y, out keys_buttons); + } + + [DllImport ("libX11", EntryPoint="XTranslateCoordinates")] + internal extern static bool _XTranslateCoordinates (IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, out int intdest_x_return, out int dest_y_return, out IntPtr child_return); + internal static bool XTranslateCoordinates (IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, out int intdest_x_return, out int dest_y_return, out IntPtr child_return) + { + DebugHelper.TraceWriteLine ("XTranslateCoordinates"); + return _XTranslateCoordinates (display, src_w, dest_w, src_x, src_y, out intdest_x_return, out dest_y_return, out child_return); + } + + [DllImport ("libX11", EntryPoint="XGetGeometry")] + internal extern static bool _XGetGeometry(IntPtr display, IntPtr window, out IntPtr root, out int x, out int y, out int width, out int height, out int border_width, out int depth); + internal static bool XGetGeometry(IntPtr display, IntPtr window, out IntPtr root, out int x, out int y, out int width, out int height, out int border_width, out int depth) + { + DebugHelper.TraceWriteLine ("XGetGeometry"); + return _XGetGeometry(display, window, out root, out x, out y, out width, out height, out border_width, out depth); + } + + [DllImport ("libX11", EntryPoint="XGetGeometry")] + internal extern static bool _XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, out int width, out int height, IntPtr border_width, IntPtr depth); + internal static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, out int width, out int height, IntPtr border_width, IntPtr depth) + { + DebugHelper.TraceWriteLine ("XGetGeometry"); + return _XGetGeometry(display, window, root, out x, out y, out width, out height, border_width, depth); + } + + [DllImport ("libX11", EntryPoint="XGetGeometry")] + internal extern static bool _XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, IntPtr width, IntPtr height, IntPtr border_width, IntPtr depth); + internal static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, IntPtr width, IntPtr height, IntPtr border_width, IntPtr depth) + { + DebugHelper.TraceWriteLine ("XGetGeometry"); + return _XGetGeometry(display, window, root, out x, out y, width, height, border_width, depth); + } + + [DllImport ("libX11", EntryPoint="XGetGeometry")] + internal extern static bool _XGetGeometry(IntPtr display, IntPtr window, IntPtr root, IntPtr x, IntPtr y, out int width, out int height, IntPtr border_width, IntPtr depth); + internal static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, IntPtr x, IntPtr y, out int width, out int height, IntPtr border_width, IntPtr depth) + { + DebugHelper.TraceWriteLine ("XGetGeometry"); + return _XGetGeometry(display, window, root, x, y, out width, out height, border_width, depth); + } + + [DllImport ("libX11", EntryPoint="XWarpPointer")] + internal extern static uint _XWarpPointer(IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, uint src_width, uint src_height, int dest_x, int dest_y); + internal static uint XWarpPointer(IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, uint src_width, uint src_height, int dest_x, int dest_y) + { + DebugHelper.TraceWriteLine ("XWarpPointer"); + return _XWarpPointer(display, src_w, dest_w, src_x, src_y, src_width, src_height, dest_x, dest_y); + } + + [DllImport ("libX11", EntryPoint="XClearWindow")] + internal extern static int _XClearWindow(IntPtr display, IntPtr window); + internal static int XClearWindow(IntPtr display, IntPtr window) + { + DebugHelper.TraceWriteLine ("XClearWindow"); + return _XClearWindow(display, window); + } + + [DllImport ("libX11", EntryPoint="XClearArea")] + internal extern static int _XClearArea(IntPtr display, IntPtr window, int x, int y, int width, int height, bool exposures); + internal static int XClearArea(IntPtr display, IntPtr window, int x, int y, int width, int height, bool exposures) + { + DebugHelper.TraceWriteLine ("XClearArea"); + return _XClearArea(display, window, x, y, width, height, exposures); + } + + // Colormaps + [DllImport ("libX11", EntryPoint="XDefaultScreenOfDisplay")] + internal extern static IntPtr _XDefaultScreenOfDisplay(IntPtr display); + internal static IntPtr XDefaultScreenOfDisplay(IntPtr display) + { + DebugHelper.TraceWriteLine ("XDefaultScreenOfDisplay"); + return _XDefaultScreenOfDisplay(display); + } + + [DllImport ("libX11", EntryPoint="XScreenNumberOfScreen")] + internal extern static int _XScreenNumberOfScreen(IntPtr display, IntPtr Screen); + internal static int XDefaultScreenOfDisplay(IntPtr display, IntPtr Screen) + { + DebugHelper.TraceWriteLine ("XDefaultScreenOfDisplay"); + return _XScreenNumberOfScreen(display, Screen); + } + + [DllImport ("libX11", EntryPoint="XDefaultVisual")] + internal extern static IntPtr _XDefaultVisual(IntPtr display, int screen_number); + internal static IntPtr XDefaultScreenOfDisplay(IntPtr display, int screen_number) + { + DebugHelper.TraceWriteLine ("XDefaultScreenOfDisplay"); + return _XDefaultVisual(display, screen_number); + } + + [DllImport ("libX11", EntryPoint="XDefaultDepth")] + internal extern static uint _XDefaultDepth(IntPtr display, int screen_number); + internal static uint XDefaultDepth(IntPtr display, int screen_number) + { + DebugHelper.TraceWriteLine ("XDefaultDepth"); + return _XDefaultDepth(display, screen_number); + } + + [DllImport ("libX11", EntryPoint="XDefaultScreen")] + internal extern static int _XDefaultScreen(IntPtr display); + internal static int XDefaultScreen(IntPtr display) + { + DebugHelper.TraceWriteLine ("XDefaultScreen"); + return _XDefaultScreen(display); + } + + [DllImport ("libX11", EntryPoint="XDefaultColormap")] + internal extern static IntPtr _XDefaultColormap(IntPtr display, int screen_number); + internal static IntPtr XDefaultColormap(IntPtr display, int screen_number) + { + DebugHelper.TraceWriteLine ("XDefaultColormap"); + return _XDefaultColormap(display, screen_number); + } + + [DllImport ("libX11", EntryPoint="XLookupColor")] + internal extern static int _XLookupColor(IntPtr display, IntPtr Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color); + internal static int XLookupColor(IntPtr display, IntPtr Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color) + { + DebugHelper.TraceWriteLine ("XLookupColor"); + return _XLookupColor(display, Colormap, Coloranem, ref exact_def_color, ref screen_def_color); + } + + [DllImport ("libX11", EntryPoint="XAllocColor")] + internal extern static int _XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def); + internal static int XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def) + { + DebugHelper.TraceWriteLine ("XAllocColor"); + return _XAllocColor(display, Colormap, ref colorcell_def); + } + + [DllImport ("libX11", EntryPoint="XSetTransientForHint")] + internal extern static int _XSetTransientForHint(IntPtr display, IntPtr window, IntPtr prop_window); + internal static int XSetTransientForHint(IntPtr display, IntPtr window, IntPtr prop_window) + { + DebugHelper.TraceWriteLine ("XSetTransientForHint"); + return _XSetTransientForHint(display, window, prop_window); + } + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int _XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref MotifWmHints data, int nelements); + internal static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref MotifWmHints data, int nelements) + { + DebugHelper.TraceWriteLine ("XChangeProperty"); + return _XChangeProperty(display, window, property, type, format, mode, ref data, nelements); + } + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int _XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref uint value, int nelements); + internal static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref uint value, int nelements) + { + DebugHelper.TraceWriteLine ("XChangeProperty"); + return _XChangeProperty(display, window, property, type, format, mode, ref value, nelements); + } + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int _XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref IntPtr value, int nelements); + internal static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref IntPtr value, int nelements) + { + DebugHelper.TraceWriteLine ("XChangeProperty"); + return _XChangeProperty(display, window, property, type, format, mode, ref value, nelements); + } + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int _XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, uint[] data, int nelements); + internal static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, uint[] data, int nelements) + { + DebugHelper.TraceWriteLine ("XChangeProperty"); + return _XChangeProperty(display, window, property, type, format, mode, data, nelements); + } + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int _XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, int[] data, int nelements); + internal static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, int[] data, int nelements) + { + DebugHelper.TraceWriteLine ("XChangeProperty"); + return _XChangeProperty(display, window, property, type, format, mode, data, nelements); + } + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int _XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr[] data, int nelements); + internal static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr[] data, int nelements) + { + DebugHelper.TraceWriteLine ("XChangeProperty"); + return _XChangeProperty(display, window, property, type, format, mode, data, nelements); + } + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int _XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr atoms, int nelements); + internal static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr atoms, int nelements) + { + DebugHelper.TraceWriteLine ("XChangeProperty"); + return _XChangeProperty(display, window, property, type, format, mode, atoms, nelements); + } + + [DllImport ("libX11", EntryPoint="XChangeProperty", CharSet=CharSet.Ansi)] + internal extern static int _XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, string text, int text_length); + internal static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, string text, int text_length) + { + DebugHelper.TraceWriteLine ("XChangeProperty"); + return _XChangeProperty(display, window, property, type, format, mode, text, text_length); + } + + [DllImport ("libX11", EntryPoint="XDeleteProperty")] + internal extern static int _XDeleteProperty(IntPtr display, IntPtr window, IntPtr property); + internal static int XDeleteProperty(IntPtr display, IntPtr window, IntPtr property) + { + DebugHelper.TraceWriteLine ("XDeleteProperty"); + return _XDeleteProperty(display, window, property); + } + + // Drawing + [DllImport ("libX11", EntryPoint="XCreateGC")] + internal extern static IntPtr _XCreateGC(IntPtr display, IntPtr window, IntPtr valuemask, ref XGCValues values); + internal static IntPtr XCreateGC(IntPtr display, IntPtr window, IntPtr valuemask, ref XGCValues values) + { + DebugHelper.TraceWriteLine ("XCreateGC"); + return _XCreateGC(display, window, valuemask, ref values); + } + + [DllImport ("libX11", EntryPoint="XFreeGC")] + internal extern static int _XFreeGC(IntPtr display, IntPtr gc); + internal static int XFreeGC(IntPtr display, IntPtr gc) + { + DebugHelper.TraceWriteLine ("XFreeGC"); + return _XFreeGC(display, gc); + } + + [DllImport ("libX11", EntryPoint="XSetFunction")] + internal extern static int _XSetFunction(IntPtr display, IntPtr gc, GXFunction function); + internal static int XSetFunction(IntPtr display, IntPtr gc, GXFunction function) + { + DebugHelper.TraceWriteLine ("XSetFunction"); + return _XSetFunction(display, gc, function); + } + + [DllImport ("libX11", EntryPoint="XSetLineAttributes")] + internal extern static int _XSetLineAttributes(IntPtr display, IntPtr gc, int line_width, GCLineStyle line_style, GCCapStyle cap_style, GCJoinStyle join_style); + internal static int XSetLineAttributes(IntPtr display, IntPtr gc, int line_width, GCLineStyle line_style, GCCapStyle cap_style, GCJoinStyle join_style) + { + DebugHelper.TraceWriteLine ("XSetLineAttributes"); + return _XSetLineAttributes(display, gc, line_width, line_style, cap_style, join_style); + } + + [DllImport ("libX11", EntryPoint="XDrawLine")] + internal extern static int _XDrawLine(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2); + internal static int XDrawLine(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2) + { + DebugHelper.TraceWriteLine ("XDrawLine"); + return _XDrawLine(display, drawable, gc, x1, y1, x2, y2); + } + + [DllImport ("libX11", EntryPoint="XDrawRectangle")] + internal extern static int _XDrawRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height); + internal static int XDrawRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height) + { + DebugHelper.TraceWriteLine ("XDrawRectangle"); + return _XDrawRectangle(display, drawable, gc, x1, y1, width, height); + } + + [DllImport ("libX11", EntryPoint="XFillRectangle")] + internal extern static int _XFillRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height); + internal static int XFillRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height) + { + DebugHelper.TraceWriteLine ("XFillRectangle"); + return _XFillRectangle(display, drawable, gc, x1, y1, width, height); + } + + [DllImport ("libX11", EntryPoint="XSetWindowBackground")] + internal extern static int _XSetWindowBackground(IntPtr display, IntPtr window, IntPtr background); + internal static int XSetWindowBackground(IntPtr display, IntPtr window, IntPtr background) + { + DebugHelper.TraceWriteLine ("XSetWindowBackground"); + return _XSetWindowBackground(display, window, background); + } + + [DllImport ("libX11", EntryPoint="XCopyArea")] + internal extern static int _XCopyArea(IntPtr display, IntPtr src, IntPtr dest, IntPtr gc, int src_x, int src_y, int width, int height, int dest_x, int dest_y); + internal static int XCopyArea(IntPtr display, IntPtr src, IntPtr dest, IntPtr gc, int src_x, int src_y, int width, int height, int dest_x, int dest_y) + { + DebugHelper.TraceWriteLine ("XCopyArea"); + return _XCopyArea(display, src, dest, gc, src_x, src_y, width, height, dest_x, dest_y); + } + + [DllImport ("libX11", EntryPoint="XGetWindowProperty")] + internal extern static int _XGetWindowProperty(IntPtr display, IntPtr window, IntPtr atom, IntPtr long_offset, IntPtr long_length, bool delete, IntPtr req_type, out IntPtr actual_type, out int actual_format, out IntPtr nitems, out IntPtr bytes_after, ref IntPtr prop); + internal static int XGetWindowProperty(IntPtr display, IntPtr window, IntPtr atom, IntPtr long_offset, IntPtr long_length, bool delete, IntPtr req_type, out IntPtr actual_type, out int actual_format, out IntPtr nitems, out IntPtr bytes_after, ref IntPtr prop) + { + DebugHelper.TraceWriteLine ("XGetWindowProperty"); + return _XGetWindowProperty(display, window, atom, long_offset, long_length, delete, req_type, out actual_type, out actual_format, out nitems, out bytes_after, ref prop); + } + + [DllImport ("libX11", EntryPoint="XSetInputFocus")] + internal extern static int _XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time); + internal static int XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time) + { + DebugHelper.TraceWriteLine ("XSetInputFocus"); + return _XSetInputFocus(display, window, revert_to, time); + } + + [DllImport ("libX11", EntryPoint="XIconifyWindow")] + internal extern static int _XIconifyWindow(IntPtr display, IntPtr window, int screen_number); + internal static int XIconifyWindow(IntPtr display, IntPtr window, int screen_number) + { + DebugHelper.TraceWriteLine ("XIconifyWindow"); + return _XIconifyWindow(display, window, screen_number); + } + + [DllImport ("libX11", EntryPoint="XDefineCursor")] + internal extern static int _XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor); + internal static int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor) + { + DebugHelper.TraceWriteLine ("XDefineCursor"); + return _XDefineCursor(display, window, cursor); + } + + [DllImport ("libX11", EntryPoint="XUndefineCursor")] + internal extern static int _XUndefineCursor(IntPtr display, IntPtr window); + internal static int XUndefineCursor(IntPtr display, IntPtr window) + { + DebugHelper.TraceWriteLine ("XUndefineCursor"); + return _XUndefineCursor(display, window); + } + + [DllImport ("libX11", EntryPoint="XFreeCursor")] + internal extern static int _XFreeCursor(IntPtr display, IntPtr cursor); + internal static int XFreeCursor(IntPtr display, IntPtr cursor) + { + DebugHelper.TraceWriteLine ("XFreeCursor"); + return _XFreeCursor(display, cursor); + } + + [DllImport ("libX11", EntryPoint="XCreateFontCursor")] + internal extern static IntPtr _XCreateFontCursor(IntPtr display, CursorFontShape shape); + internal static IntPtr XCreateFontCursor(IntPtr display, CursorFontShape shape) + { + DebugHelper.TraceWriteLine ("XCreateFontCursor"); + return _XCreateFontCursor(display, shape); + } + + [DllImport ("libX11", EntryPoint="XCreatePixmapCursor")] + internal extern static IntPtr _XCreatePixmapCursor(IntPtr display, IntPtr source, IntPtr mask, ref XColor foreground_color, ref XColor background_color, int x_hot, int y_hot); + internal static IntPtr XCreatePixmapCursor(IntPtr display, IntPtr source, IntPtr mask, ref XColor foreground_color, ref XColor background_color, int x_hot, int y_hot) + { + DebugHelper.TraceWriteLine ("XCreatePixmapCursor"); + return _XCreatePixmapCursor(display, source, mask, ref foreground_color, ref background_color, x_hot, y_hot); + } + + [DllImport ("libX11", EntryPoint="XCreatePixmapFromBitmapData")] + internal extern static IntPtr _XCreatePixmapFromBitmapData(IntPtr display, IntPtr drawable, byte[] data, int width, int height, IntPtr fg, IntPtr bg, int depth); + internal static IntPtr XCreatePixmapFromBitmapData(IntPtr display, IntPtr drawable, byte[] data, int width, int height, IntPtr fg, IntPtr bg, int depth) + { + DebugHelper.TraceWriteLine ("XCreatePixmapFromBitmapData"); + return _XCreatePixmapFromBitmapData(display, drawable, data, width, height, fg, bg, depth); + } + + [DllImport ("libX11", EntryPoint="XCreatePixmap")] + internal extern static IntPtr _XCreatePixmap(IntPtr display, IntPtr d, int width, int height, int depth); + internal static IntPtr XCreatePixmap(IntPtr display, IntPtr d, int width, int height, int depth) + { + DebugHelper.TraceWriteLine ("XCreatePixmap"); + return _XCreatePixmap(display, d, width, height, depth); + } + + [DllImport ("libX11", EntryPoint="XFreePixmap")] + internal extern static IntPtr _XFreePixmap(IntPtr display, IntPtr pixmap); + internal static IntPtr XFreePixmap(IntPtr display, IntPtr pixmap) + { + DebugHelper.TraceWriteLine ("XFreePixmap"); + return _XFreePixmap(display, pixmap); + } + + [DllImport ("libX11", EntryPoint="XQueryBestCursor")] + internal extern static int _XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, out int best_width, out int best_height); + internal static int XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, out int best_width, out int best_height) + { + DebugHelper.TraceWriteLine ("XQueryBestCursor"); + return _XQueryBestCursor(display, drawable, width, height, out best_width, out best_height); + } + + [DllImport ("libX11", EntryPoint="XQueryExtension")] + internal extern static int _XQueryExtension(IntPtr display, string extension_name, ref int major, ref int first_event, ref int first_error); + internal static int XQueryExtension(IntPtr display, string extension_name, ref int major, ref int first_event, ref int first_error) + { + DebugHelper.TraceWriteLine ("XQueryExtension"); + return _XQueryExtension(display, extension_name, ref major, ref first_event, ref first_error); + } + + [DllImport ("libX11", EntryPoint="XWhitePixel")] + internal extern static IntPtr _XWhitePixel(IntPtr display, int screen_no); + internal static IntPtr XWhitePixel(IntPtr display, int screen_no) + { + DebugHelper.TraceWriteLine ("XWhitePixel"); + return _XWhitePixel(display, screen_no); + } + + [DllImport ("libX11", EntryPoint="XBlackPixel")] + internal extern static IntPtr _XBlackPixel(IntPtr display, int screen_no); + internal static IntPtr XBlackPixel(IntPtr display, int screen_no) + { + DebugHelper.TraceWriteLine ("XBlackPixel"); + return _XBlackPixel(display, screen_no); + } + + [DllImport ("libX11", EntryPoint="XGrabServer")] + internal extern static void _XGrabServer(IntPtr display); + internal static void XGrabServer(IntPtr display) + { + DebugHelper.TraceWriteLine ("XGrabServer"); + _XGrabServer(display); + } + + [DllImport ("libX11", EntryPoint="XUngrabServer")] + internal extern static void _XUngrabServer(IntPtr display); + internal static void XUngrabServer(IntPtr display) + { + DebugHelper.TraceWriteLine ("XUngrabServer"); + _XUngrabServer(display); + } + + [DllImport ("libX11", EntryPoint="XGetWMNormalHints")] + internal extern static void _XGetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints, out IntPtr supplied_return); + internal static void XGetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints, out IntPtr supplied_return) + { + DebugHelper.TraceWriteLine ("XGetWMNormalHints"); + _XGetWMNormalHints(display, window, ref hints, out supplied_return); + } + + [DllImport ("libX11", EntryPoint="XSetWMNormalHints")] + internal extern static void _XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints); + internal static void XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints) + { + DebugHelper.TraceWriteLine ("XSetWMNormalHints"); + _XSetWMNormalHints(display, window, ref hints); + } + + [DllImport ("libX11", EntryPoint="XSetZoomHints")] + internal extern static void _XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints); + internal static void XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints) + { + DebugHelper.TraceWriteLine ("XSetZoomHints"); + _XSetZoomHints(display, window, ref hints); + } + + [DllImport ("libX11", EntryPoint="XSetWMHints")] + internal extern static void _XSetWMHints(IntPtr display, IntPtr window, ref XWMHints wmhints); + internal static void XSetWMHints(IntPtr display, IntPtr window, ref XWMHints wmhints) + { + DebugHelper.TraceWriteLine ("XSetWMHints"); + _XSetWMHints(display, window, ref wmhints); + } + + [DllImport ("libX11", EntryPoint="XGetIconSizes")] + internal extern static int _XGetIconSizes(IntPtr display, IntPtr window, out IntPtr size_list, out int count); + internal static int XGetIconSizes(IntPtr display, IntPtr window, out IntPtr size_list, out int count) + { + DebugHelper.TraceWriteLine ("XGetIconSizes"); + return _XGetIconSizes(display, window, out size_list, out count); + } + + [DllImport ("libX11", EntryPoint="XSetErrorHandler")] + internal extern static IntPtr _XSetErrorHandler(XErrorHandler error_handler); + internal static IntPtr XSetErrorHandler(XErrorHandler error_handler) + { + DebugHelper.TraceWriteLine ("XSetErrorHandler"); + return _XSetErrorHandler(error_handler); + } + + [DllImport ("libX11", EntryPoint="XGetErrorText")] + internal extern static IntPtr _XGetErrorText(IntPtr display, byte code, StringBuilder buffer, int length); + internal static IntPtr XGetErrorText(IntPtr display, byte code, StringBuilder buffer, int length) + { + DebugHelper.TraceWriteLine ("XGetErrorText"); + return _XGetErrorText(display, code, buffer, length); + } + + [DllImport ("libX11", EntryPoint="XInitThreads")] + internal extern static int _XInitThreads(); + internal static int XInitThreads() + { + DebugHelper.TraceWriteLine ("XInitThreads"); + return _XInitThreads(); + } + + [DllImport ("libX11", EntryPoint="XConvertSelection")] + internal extern static int _XConvertSelection(IntPtr display, IntPtr selection, IntPtr target, IntPtr property, IntPtr requestor, IntPtr time); + internal static int XConvertSelection(IntPtr display, IntPtr selection, IntPtr target, IntPtr property, IntPtr requestor, IntPtr time) + { + DebugHelper.TraceWriteLine ("XConvertSelection"); + return _XConvertSelection(display, selection, target, property, requestor, time); + } + + [DllImport ("libX11", EntryPoint="XGetSelectionOwner")] + internal extern static IntPtr _XGetSelectionOwner(IntPtr display, IntPtr selection); + internal static IntPtr XGetSelectionOwner(IntPtr display, IntPtr selection) + { + DebugHelper.TraceWriteLine ("XGetSelectionOwner"); + return _XGetSelectionOwner(display, selection); + } + + [DllImport ("libX11", EntryPoint="XSetSelectionOwner")] + internal extern static int _XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, IntPtr time); + internal static int XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, IntPtr time) + { + DebugHelper.TraceWriteLine ("XSetSelectionOwner"); + return _XSetSelectionOwner(display, selection, owner, time); + } + + [DllImport ("libX11", EntryPoint="XSetPlaneMask")] + internal extern static int _XSetPlaneMask(IntPtr display, IntPtr gc, IntPtr mask); + internal static int XSetPlaneMask(IntPtr display, IntPtr gc, IntPtr mask) + { + DebugHelper.TraceWriteLine ("XSetPlaneMask"); + return _XSetPlaneMask(display, gc, mask); + } + + [DllImport ("libX11", EntryPoint="XSetForeground")] + internal extern static int _XSetForeground(IntPtr display, IntPtr gc, UIntPtr foreground); + internal static int XSetForeground(IntPtr display, IntPtr gc, UIntPtr foreground) + { + DebugHelper.TraceWriteLine ("XSetForeground"); + return _XSetForeground(display, gc, foreground); + } + + [DllImport ("libX11", EntryPoint="XSetBackground")] + internal extern static int _XSetBackground(IntPtr display, IntPtr gc, UIntPtr background); + internal static int XSetBackground(IntPtr display, IntPtr gc, UIntPtr background) + { + DebugHelper.TraceWriteLine ("XSetBackground"); + return _XSetBackground(display, gc, background); + } + + [DllImport ("libX11", EntryPoint="XBell")] + internal extern static int _XBell(IntPtr display, int percent); + internal static int XBell(IntPtr display, int percent) + { + DebugHelper.TraceWriteLine ("XBell"); + return _XBell(display, percent); + } + + [DllImport ("libX11", EntryPoint="XChangeActivePointerGrab")] + internal extern static int _XChangeActivePointerGrab (IntPtr display, EventMask event_mask, IntPtr cursor, IntPtr time); + internal static int XChangeActivePointerGrab (IntPtr display, EventMask event_mask, IntPtr cursor, IntPtr time) + { + DebugHelper.TraceWriteLine ("XChangeActivePointerGrab"); + return _XChangeActivePointerGrab (display, event_mask, cursor, time); + } + + [DllImport ("libX11", EntryPoint="XFilterEvent")] + internal extern static bool _XFilterEvent(ref XEvent xevent, IntPtr window); + internal static bool XFilterEvent(ref XEvent xevent, IntPtr window) + { + DebugHelper.TraceWriteLine ("XFilterEvent"); + return _XFilterEvent(ref xevent, window); + } + + [DllImport ("libX11", EntryPoint="XkbSetDetectableAutoRepeat")] + internal extern static void _XkbSetDetectableAutoRepeat (IntPtr display, bool detectable, IntPtr supported); + internal static void XkbSetDetectableAutoRepeat (IntPtr display, bool detectable, IntPtr supported) + { + DebugHelper.TraceWriteLine ("XkbSetDetectableAutoRepeat"); + _XkbSetDetectableAutoRepeat (display, detectable, supported); + } + + [DllImport ("libX11", EntryPoint="XPeekEvent")] + internal extern static void _XPeekEvent (IntPtr display, ref XEvent xevent); + internal static void XPeekEvent (IntPtr display, ref XEvent xevent) + { + DebugHelper.TraceWriteLine ("XPeekEvent"); + _XPeekEvent (display, ref xevent); + } + + [DllImport ("libX11", EntryPoint="XIfEvent")] + internal extern static void _XIfEvent (IntPtr display, ref XEvent xevent, Delegate event_predicate, IntPtr arg); + internal static void XIfEvent (IntPtr display, ref XEvent xevent, Delegate event_predicate, IntPtr arg) + { + DebugHelper.TraceWriteLine ("XIfEvent"); + _XIfEvent (display, ref xevent, event_predicate, arg); + } +#endregion + +#region Xinerama imports + [DllImport ("libXinerama", EntryPoint="XineramaQueryScreens")] + extern static IntPtr _XineramaQueryScreens (IntPtr display, out int number); + internal static IntPtr XineramaQueryScreens (IntPtr display, out int number) + { + DebugHelper.TraceWriteLine ("XineramaQueryScreens"); + return _XineramaQueryScreens (display, out number); + } + + [DllImport ("libXinerama", EntryPoint="XineramaIsActive")] + extern static bool _XineramaIsActive (IntPtr display); + static bool XineramaNotInstalled; + + internal static bool XineramaIsActive (IntPtr display) + { + DebugHelper.TraceWriteLine ("XineramaIsActive"); + + if (XineramaNotInstalled) + return false; + try { + return _XineramaIsActive (display); + } catch (DllNotFoundException) { + // Xinerama isn't installed + XineramaNotInstalled = true; + return false; + } + } +#endregion + +#else //no TRACE defined + +#region Xcursor imports + [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadCursor")] + internal extern static IntPtr XcursorLibraryLoadCursor (IntPtr display, [MarshalAs (UnmanagedType.LPStr)] string name); + + [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadImages")] + internal extern static IntPtr XcursorLibraryLoadImages ([MarshalAs (UnmanagedType.LPStr)] string file, IntPtr theme, int size); + + [DllImport ("libXcursor", EntryPoint = "XcursorImagesDestroy")] + internal extern static void XcursorImagesDestroy (IntPtr images); + + [DllImport ("libXcursor", EntryPoint = "XcursorGetDefaultSize")] + internal extern static int XcursorGetDefaultSize (IntPtr display); + + [DllImport ("libXcursor", EntryPoint = "XcursorImageLoadCursor")] + internal extern static IntPtr XcursorImageLoadCursor (IntPtr display, IntPtr image); + + [DllImport ("libXcursor", EntryPoint = "XcursorGetTheme")] + internal extern static IntPtr XcursorGetTheme (IntPtr display); +#endregion + #region X11 Imports + [DllImport ("libX11", EntryPoint="XOpenDisplay")] + internal extern static IntPtr XOpenDisplay(IntPtr display); + [DllImport ("libX11", EntryPoint="XCloseDisplay")] + internal extern static int XCloseDisplay(IntPtr display); + [DllImport ("libX11", EntryPoint="XSynchronize")] + internal extern static IntPtr XSynchronize(IntPtr display, bool onoff); + + [DllImport ("libX11", EntryPoint="XCreateWindow")] + internal extern static IntPtr XCreateWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, int depth, int xclass, IntPtr visual, UIntPtr valuemask, ref XSetWindowAttributes attributes); + + [DllImport ("libX11", EntryPoint="XCreateSimpleWindow")] + internal extern static IntPtr XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, UIntPtr border, UIntPtr background); + + [DllImport ("libX11", EntryPoint="XMapWindow")] + internal extern static int XMapWindow(IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XMapRaised")] + internal extern static int XMapRaised(IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XUnmapWindow")] + internal extern static int XUnmapWindow(IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XMapSubwindows")] + internal extern static int XMapSubindows(IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XUnmapSubwindows")] + internal extern static int XUnmapSubwindows(IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XRootWindow")] + internal extern static IntPtr XRootWindow(IntPtr display, int screen_number); + + [DllImport ("libX11", EntryPoint="XNextEvent")] + internal extern static IntPtr XNextEvent(IntPtr display, ref XEvent xevent); + + [DllImport ("libX11", EntryPoint="XConnectionNumber")] + internal extern static int XConnectionNumber (IntPtr display); + + [DllImport ("libX11", EntryPoint="XPending")] + internal extern static int XPending (IntPtr display); + + [DllImport ("libX11", EntryPoint="XSelectInput")] + internal extern static IntPtr XSelectInput(IntPtr display, IntPtr window, IntPtr mask); + + [DllImport ("libX11", EntryPoint="XDestroyWindow")] + internal extern static int XDestroyWindow(IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XReparentWindow")] + internal extern static int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y); + + [DllImport ("libX11", EntryPoint="XMoveResizeWindow")] + extern static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height); + internal static int MoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height) + { + int ret = XMoveResizeWindow (display, window, x, y, width, height); + Keyboard.MoveCurrentCaretPos (); + return ret; + } + + [DllImport ("libX11", EntryPoint="XResizeWindow")] + internal extern static int XResizeWindow(IntPtr display, IntPtr window, int width, int height); + + [DllImport ("libX11", EntryPoint="XGetWindowAttributes")] + internal extern static int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes); + + [DllImport ("libX11", EntryPoint="XFlush")] + internal extern static int XFlush(IntPtr display); + + [DllImport ("libX11", EntryPoint="XSetWMName")] + internal extern static int XSetWMName(IntPtr display, IntPtr window, ref XTextProperty text_prop); + + [DllImport ("libX11", EntryPoint="XStoreName")] + internal extern static int XStoreName(IntPtr display, IntPtr window, string window_name); + + [DllImport ("libX11", EntryPoint="XFetchName")] + internal extern static int XFetchName(IntPtr display, IntPtr window, ref IntPtr window_name); + + [DllImport ("libX11", EntryPoint="XSendEvent")] + internal extern static int XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask, ref XEvent send_event); + + [DllImport ("libX11", EntryPoint="XQueryTree")] + internal extern static int XQueryTree(IntPtr display, IntPtr window, out IntPtr root_return, out IntPtr parent_return, out IntPtr children_return, out int nchildren_return); + + [DllImport ("libX11", EntryPoint="XFree")] + internal extern static int XFree(IntPtr data); + + [DllImport ("libX11", EntryPoint="XRaiseWindow")] + internal extern static int XRaiseWindow(IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XLowerWindow")] + internal extern static uint XLowerWindow(IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XConfigureWindow")] + internal extern static uint XConfigureWindow(IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values); + + [DllImport ("libX11", EntryPoint="XInternAtom")] + internal extern static IntPtr XInternAtom(IntPtr display, string atom_name, bool only_if_exists); + + [DllImport ("libX11", EntryPoint="XInternAtoms")] + internal extern static int XInternAtoms(IntPtr display, string[] atom_names, int atom_count, bool only_if_exists, IntPtr[] atoms); + + [DllImport ("libX11", EntryPoint="XSetWMProtocols")] + internal extern static int XSetWMProtocols(IntPtr display, IntPtr window, IntPtr[] protocols, int count); + + [DllImport ("libX11", EntryPoint="XGrabPointer")] + internal extern static int XGrabPointer(IntPtr display, IntPtr window, bool owner_events, EventMask event_mask, GrabMode pointer_mode, GrabMode keyboard_mode, IntPtr confine_to, IntPtr cursor, IntPtr timestamp); + + [DllImport ("libX11", EntryPoint="XUngrabPointer")] + internal extern static int XUngrabPointer(IntPtr display, IntPtr timestamp); + + [DllImport ("libX11", EntryPoint="XQueryPointer")] + internal extern static bool XQueryPointer(IntPtr display, IntPtr window, out IntPtr root, out IntPtr child, out int root_x, out int root_y, out int win_x, out int win_y, out int keys_buttons); + + [DllImport ("libX11", EntryPoint="XTranslateCoordinates")] + internal extern static bool XTranslateCoordinates (IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, out int intdest_x_return, out int dest_y_return, out IntPtr child_return); + + [DllImport ("libX11", EntryPoint="XGetGeometry")] + internal extern static bool XGetGeometry(IntPtr display, IntPtr window, out IntPtr root, out int x, out int y, out int width, out int height, out int border_width, out int depth); + + [DllImport ("libX11", EntryPoint="XGetGeometry")] + internal extern static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, out int width, out int height, IntPtr border_width, IntPtr depth); + + [DllImport ("libX11", EntryPoint="XGetGeometry")] + internal extern static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, out int x, out int y, IntPtr width, IntPtr height, IntPtr border_width, IntPtr depth); + + [DllImport ("libX11", EntryPoint="XGetGeometry")] + internal extern static bool XGetGeometry(IntPtr display, IntPtr window, IntPtr root, IntPtr x, IntPtr y, out int width, out int height, IntPtr border_width, IntPtr depth); + + [DllImport ("libX11", EntryPoint="XWarpPointer")] + internal extern static uint XWarpPointer(IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, uint src_width, uint src_height, int dest_x, int dest_y); + + [DllImport ("libX11", EntryPoint="XClearWindow")] + internal extern static int XClearWindow(IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XClearArea")] + internal extern static int XClearArea(IntPtr display, IntPtr window, int x, int y, int width, int height, bool exposures); + + // Colormaps + [DllImport ("libX11", EntryPoint="XDefaultScreenOfDisplay")] + internal extern static IntPtr XDefaultScreenOfDisplay(IntPtr display); + + [DllImport ("libX11", EntryPoint="XScreenNumberOfScreen")] + internal extern static int XScreenNumberOfScreen(IntPtr display, IntPtr Screen); + + [DllImport ("libX11", EntryPoint="XDefaultVisual")] + internal extern static IntPtr XDefaultVisual(IntPtr display, int screen_number); + + [DllImport ("libX11", EntryPoint="XDefaultDepth")] + internal extern static uint XDefaultDepth(IntPtr display, int screen_number); + + [DllImport ("libX11", EntryPoint="XDefaultScreen")] + internal extern static int XDefaultScreen(IntPtr display); + + [DllImport ("libX11", EntryPoint="XDefaultColormap")] + internal extern static IntPtr XDefaultColormap(IntPtr display, int screen_number); + + [DllImport ("libX11", EntryPoint="XLookupColor")] + internal extern static int XLookupColor(IntPtr display, IntPtr Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color); + + [DllImport ("libX11", EntryPoint="XAllocColor")] + internal extern static int XAllocColor(IntPtr display, IntPtr Colormap, ref XColor colorcell_def); + + [DllImport ("libX11", EntryPoint="XSetTransientForHint")] + internal extern static int XSetTransientForHint(IntPtr display, IntPtr window, IntPtr prop_window); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref MotifWmHints data, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref uint value, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, ref IntPtr value, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, uint[] data, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, int[] data, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr[] data, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, IntPtr atoms, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty", CharSet=CharSet.Ansi)] + internal extern static int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, int format, PropertyMode mode, string text, int text_length); + + [DllImport ("libX11", EntryPoint="XDeleteProperty")] + internal extern static int XDeleteProperty(IntPtr display, IntPtr window, IntPtr property); + + // Drawing + [DllImport ("libX11", EntryPoint="XCreateGC")] + internal extern static IntPtr XCreateGC(IntPtr display, IntPtr window, IntPtr valuemask, ref XGCValues values); + + [DllImport ("libX11", EntryPoint="XFreeGC")] + internal extern static int XFreeGC(IntPtr display, IntPtr gc); + + [DllImport ("libX11", EntryPoint="XSetFunction")] + internal extern static int XSetFunction(IntPtr display, IntPtr gc, GXFunction function); + + [DllImport ("libX11", EntryPoint="XSetLineAttributes")] + internal extern static int XSetLineAttributes(IntPtr display, IntPtr gc, int line_width, GCLineStyle line_style, GCCapStyle cap_style, GCJoinStyle join_style); + + [DllImport ("libX11", EntryPoint="XDrawLine")] + internal extern static int XDrawLine(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2); + + [DllImport ("libX11", EntryPoint="XDrawRectangle")] + internal extern static int XDrawRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height); + + [DllImport ("libX11", EntryPoint="XFillRectangle")] + internal extern static int XFillRectangle(IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height); + + [DllImport ("libX11", EntryPoint="XSetWindowBackground")] + internal extern static int XSetWindowBackground(IntPtr display, IntPtr window, IntPtr background); + + [DllImport ("libX11", EntryPoint="XCopyArea")] + internal extern static int XCopyArea(IntPtr display, IntPtr src, IntPtr dest, IntPtr gc, int src_x, int src_y, int width, int height, int dest_x, int dest_y); + + [DllImport ("libX11", EntryPoint="XGetWindowProperty")] + internal extern static int XGetWindowProperty(IntPtr display, IntPtr window, IntPtr atom, IntPtr long_offset, IntPtr long_length, bool delete, IntPtr req_type, out IntPtr actual_type, out int actual_format, out IntPtr nitems, out IntPtr bytes_after, ref IntPtr prop); + + [DllImport ("libX11", EntryPoint="XSetInputFocus")] + internal extern static int XSetInputFocus(IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time); + + [DllImport ("libX11", EntryPoint="XIconifyWindow")] + internal extern static int XIconifyWindow(IntPtr display, IntPtr window, int screen_number); + + [DllImport ("libX11", EntryPoint="XDefineCursor")] + internal extern static int XDefineCursor(IntPtr display, IntPtr window, IntPtr cursor); + + [DllImport ("libX11", EntryPoint="XUndefineCursor")] + internal extern static int XUndefineCursor(IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XFreeCursor")] + internal extern static int XFreeCursor(IntPtr display, IntPtr cursor); + + [DllImport ("libX11", EntryPoint="XCreateFontCursor")] + internal extern static IntPtr XCreateFontCursor(IntPtr display, CursorFontShape shape); + + [DllImport ("libX11", EntryPoint="XCreatePixmapCursor")] + internal extern static IntPtr XCreatePixmapCursor(IntPtr display, IntPtr source, IntPtr mask, ref XColor foreground_color, ref XColor background_color, int x_hot, int y_hot); + + [DllImport ("libX11", EntryPoint="XCreatePixmapFromBitmapData")] + internal extern static IntPtr XCreatePixmapFromBitmapData(IntPtr display, IntPtr drawable, byte[] data, int width, int height, IntPtr fg, IntPtr bg, int depth); + + [DllImport ("libX11", EntryPoint="XCreatePixmap")] + internal extern static IntPtr XCreatePixmap(IntPtr display, IntPtr d, int width, int height, int depth); + + [DllImport ("libX11", EntryPoint="XFreePixmap")] + internal extern static IntPtr XFreePixmap(IntPtr display, IntPtr pixmap); + + [DllImport ("libX11", EntryPoint="XQueryBestCursor")] + internal extern static int XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, out int best_width, out int best_height); + + [DllImport ("libX11", EntryPoint="XQueryExtension")] + internal extern static int XQueryExtension(IntPtr display, string extension_name, ref int major, ref int first_event, ref int first_error); + + [DllImport ("libX11", EntryPoint="XWhitePixel")] + internal extern static IntPtr XWhitePixel(IntPtr display, int screen_no); + + [DllImport ("libX11", EntryPoint="XBlackPixel")] + internal extern static IntPtr XBlackPixel(IntPtr display, int screen_no); + + [DllImport ("libX11", EntryPoint="XGrabServer")] + internal extern static void XGrabServer(IntPtr display); + + [DllImport ("libX11", EntryPoint="XUngrabServer")] + internal extern static void XUngrabServer(IntPtr display); + + [DllImport ("libX11", EntryPoint="XGetWMNormalHints")] + internal extern static void XGetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints, out IntPtr supplied_return); + + [DllImport ("libX11", EntryPoint="XSetWMNormalHints")] + internal extern static void XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints); + + [DllImport ("libX11", EntryPoint="XSetZoomHints")] + internal extern static void XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints); + + [DllImport ("libX11", EntryPoint="XSetWMHints")] + internal extern static void XSetWMHints(IntPtr display, IntPtr window, ref XWMHints wmhints); + + [DllImport ("libX11", EntryPoint="XGetIconSizes")] + internal extern static int XGetIconSizes(IntPtr display, IntPtr window, out IntPtr size_list, out int count); + + [DllImport ("libX11", EntryPoint="XSetErrorHandler")] + internal extern static IntPtr XSetErrorHandler(XErrorHandler error_handler); + + [DllImport ("libX11", EntryPoint="XGetErrorText")] + internal extern static IntPtr XGetErrorText(IntPtr display, byte code, StringBuilder buffer, int length); + + [DllImport ("libX11", EntryPoint="XInitThreads")] + internal extern static int XInitThreads(); + + [DllImport ("libX11", EntryPoint="XConvertSelection")] + internal extern static int XConvertSelection(IntPtr display, IntPtr selection, IntPtr target, IntPtr property, IntPtr requestor, IntPtr time); + + [DllImport ("libX11", EntryPoint="XGetSelectionOwner")] + internal extern static IntPtr XGetSelectionOwner(IntPtr display, IntPtr selection); + + [DllImport ("libX11", EntryPoint="XSetSelectionOwner")] + internal extern static int XSetSelectionOwner(IntPtr display, IntPtr selection, IntPtr owner, IntPtr time); + + [DllImport ("libX11", EntryPoint="XSetPlaneMask")] + internal extern static int XSetPlaneMask(IntPtr display, IntPtr gc, IntPtr mask); + + [DllImport ("libX11", EntryPoint="XSetForeground")] + internal extern static int XSetForeground(IntPtr display, IntPtr gc, UIntPtr foreground); + + [DllImport ("libX11", EntryPoint="XSetBackground")] + internal extern static int XSetBackground(IntPtr display, IntPtr gc, UIntPtr background); + + [DllImport ("libX11", EntryPoint="XBell")] + internal extern static int XBell(IntPtr display, int percent); + + [DllImport ("libX11", EntryPoint="XChangeActivePointerGrab")] + internal extern static int XChangeActivePointerGrab (IntPtr display, EventMask event_mask, IntPtr cursor, IntPtr time); + + [DllImport ("libX11", EntryPoint="XFilterEvent")] + internal extern static bool XFilterEvent(ref XEvent xevent, IntPtr window); + + [DllImport ("libX11", EntryPoint="XkbSetDetectableAutoRepeat")] + internal extern static void XkbSetDetectableAutoRepeat (IntPtr display, bool detectable, IntPtr supported); + + [DllImport ("libX11", EntryPoint="XPeekEvent")] + internal extern static void XPeekEvent (IntPtr display, ref XEvent xevent); + + [DllImport ("libX11", EntryPoint="XIfEvent")] + internal extern static void XIfEvent (IntPtr display, ref XEvent xevent, Delegate event_predicate, IntPtr arg); + + [DllImport ("libX11", EntryPoint="XGetInputFocus")] + internal extern static void XGetInputFocus (IntPtr display, out IntPtr focus, out IntPtr revert_to); + #endregion +#region Gtk/Gdk imports + [DllImport("libgdk-x11-2.0")] + internal extern static IntPtr gdk_atom_intern (string atomName, bool onlyIfExists); + + [DllImport("libgtk-x11-2.0")] + internal extern static IntPtr gtk_clipboard_get (IntPtr atom); + + [DllImport("libgtk-x11-2.0")] + internal extern static void gtk_clipboard_store (IntPtr clipboard); + + [DllImport("libgtk-x11-2.0")] + internal extern static void gtk_clipboard_set_text (IntPtr clipboard, string text, int len); +#endregion + + +#region Xinerama imports + [DllImport ("libXinerama")] + internal extern static IntPtr XineramaQueryScreens (IntPtr display, out int number); + + [DllImport ("libXinerama", EntryPoint = "XineramaIsActive")] + extern static bool _XineramaIsActive (IntPtr display); + static bool XineramaNotInstalled; + + internal static bool XineramaIsActive (IntPtr display) + { + if (XineramaNotInstalled) + return false; + try { + return _XineramaIsActive (display); + } catch (DllNotFoundException) { + // Xinerama isn't installed + XineramaNotInstalled = true; + return false; + } + } +#endregion + +#endif + } +} diff --git a/source/ShiftUI/Internal/XplatUIX11GTK.cs b/source/ShiftUI/Internal/XplatUIX11GTK.cs new file mode 100644 index 0000000..03ea185 --- /dev/null +++ b/source/ShiftUI/Internal/XplatUIX11GTK.cs @@ -0,0 +1,4634 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// Alexander Olk alex.olk@googlemail.com +// +// + +// NOTE: +// This driver understands the following environment variables: (Set the var to enable feature) +// +// MONO_XEXCEPTIONS = throw an exception when a X11 error is encountered; +// by default a message is displayed but execution continues +// +// MONO_XSYNC = perform all X11 commands synchronous; this is slower but +// helps in debugging errors +// + +// NOT COMPLETE - WORK IN PROGRESS + +// One feature of the driver is, that PaintEventstart returns a graphics context created from a offscreen drawable (pixmap) + +// define to log Window handles and relationships to stdout +#undef DriverDebug + +// Extra detailed debug +#undef DriverDebugExtra + +using System; +using System.ComponentModel; +using System.Collections; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + +// Only do the poll when building with mono for now +#if __MonoCS__ +using Mono.Unix.Native; +#endif + +/// X11 Version +namespace ShiftUI { + internal class XplatUIX11GTK : XplatUIDriver { + + internal enum GdkWindowClass { + GDK_INPUT_OUTPUT, + GDK_INPUT_ONLY + } + + internal enum GdkWindowType { + GDK_WINDOW_ROOT, + GDK_WINDOW_TOPLEVEL, + GDK_WINDOW_CHILD, + GDK_WINDOW_DIALOG, + GDK_WINDOW_TEMP, + GDK_WINDOW_FOREIGN + } + + internal enum GdkWindowHints { + GDK_HINT_POS = 1 << 0, + GDK_HINT_MIN_SIZE = 1 << 1, + GDK_HINT_MAX_SIZE = 1 << 2, + GDK_HINT_BASE_SIZE = 1 << 3, + GDK_HINT_ASPECT = 1 << 4, + GDK_HINT_RESIZE_INC = 1 << 5, + GDK_HINT_WIN_GRAVITY = 1 << 6, + GDK_HINT_USER_POS = 1 << 7, + GDK_HINT_USER_SIZE = 1 << 8 + } + + internal enum GdkGravity { + GDK_GRAVITY_NORTH_WEST = 1, + GDK_GRAVITY_NORTH, + GDK_GRAVITY_NORTH_EAST, + GDK_GRAVITY_WEST, + GDK_GRAVITY_CENTER, + GDK_GRAVITY_EAST, + GDK_GRAVITY_SOUTH_WEST, + GDK_GRAVITY_SOUTH, + GDK_GRAVITY_SOUTH_EAST, + GDK_GRAVITY_STATIC + } + + internal enum GdkWindowEdge { + GDK_WINDOW_EDGE_NORTH_WEST, + GDK_WINDOW_EDGE_NORTH, + GDK_WINDOW_EDGE_NORTH_EAST, + GDK_WINDOW_EDGE_WEST, + GDK_WINDOW_EDGE_EAST, + GDK_WINDOW_EDGE_SOUTH_WEST, + GDK_WINDOW_EDGE_SOUTH, + GDK_WINDOW_EDGE_SOUTH_EAST + } + + internal enum GdkWindowTypeHint { + GDK_WINDOW_TYPE_HINT_NORMAL, + GDK_WINDOW_TYPE_HINT_DIALOG, + GDK_WINDOW_TYPE_HINT_MENU, + GDK_WINDOW_TYPE_HINT_TOOLBAR, + GDK_WINDOW_TYPE_HINT_SPLASHSCREEN, + GDK_WINDOW_TYPE_HINT_UTILITY, + GDK_WINDOW_TYPE_HINT_DOCK, + GDK_WINDOW_TYPE_HINT_DESKTOP + } + + internal enum GdkWindowAttributesType { + GDK_WA_TITLE = 1 << 1, + GDK_WA_X = 1 << 2, + GDK_WA_Y = 1 << 3, + GDK_WA_CURSOR = 1 << 4, + GDK_WA_COLORMAP = 1 << 5, + GDK_WA_VISUAL = 1 << 6, + GDK_WA_WMCLASS = 1 << 7, + GDK_WA_NOREDIR = 1 << 8 + } + + internal enum GdkEventMask { + GDK_EXPOSURE_MASK = 1 << 1, + GDK_POINTER_MOTION_MASK = 1 << 2, + GDK_POINTER_MOTION_HINT_MASK = 1 << 3, + GDK_BUTTON_MOTION_MASK = 1 << 4, + GDK_BUTTON1_MOTION_MASK = 1 << 5, + GDK_BUTTON2_MOTION_MASK = 1 << 6, + GDK_BUTTON3_MOTION_MASK = 1 << 7, + GDK_BUTTON_PRESS_MASK = 1 << 8, + GDK_BUTTON_RELEASE_MASK = 1 << 9, + GDK_KEY_PRESS_MASK = 1 << 10, + GDK_KEY_RELEASE_MASK = 1 << 11, + GDK_ENTER_NOTIFY_MASK = 1 << 12, + GDK_LEAVE_NOTIFY_MASK = 1 << 13, + GDK_FOCUS_CHANGE_MASK = 1 << 14, + GDK_STRUCTURE_MASK = 1 << 15, + GDK_PROPERTY_CHANGE_MASK = 1 << 16, + GDK_VISIBILITY_NOTIFY_MASK = 1 << 17, + GDK_PROXIMITY_IN_MASK = 1 << 18, + GDK_PROXIMITY_OUT_MASK = 1 << 19, + GDK_SUBSTRUCTURE_MASK = 1 << 20, + GDK_SCROLL_MASK = 1 << 21, + GDK_ALL_EVENTS_MASK = 0x3FFFFE + } + + internal enum GdkEventType { + GDK_NOTHING = -1, + GDK_DELETE = 0, + GDK_DESTROY = 1, + GDK_EXPOSE = 2, + GDK_MOTION_NOTIFY = 3, + GDK_BUTTON_PRESS = 4, + GDK_2BUTTON_PRESS = 5, + GDK_3BUTTON_PRESS = 6, + GDK_BUTTON_RELEASE = 7, + GDK_KEY_PRESS = 8, + GDK_KEY_RELEASE = 9, + GDK_ENTER_NOTIFY = 10, + GDK_LEAVE_NOTIFY = 11, + GDK_FOCUS_CHANGE = 12, + GDK_CONFIGURE = 13, + GDK_MAP = 14, + GDK_UNMAP = 15, + GDK_PROPERTY_NOTIFY = 16, + GDK_SELECTION_CLEAR = 17, + GDK_SELECTION_REQUEST = 18, + GDK_SELECTION_NOTIFY = 19, + GDK_PROXIMITY_IN = 20, + GDK_PROXIMITY_OUT = 21, + GDK_DRAG_ENTER = 22, + GDK_DRAG_LEAVE = 23, + GDK_DRAG_MOTION = 24, + GDK_DRAG_STATUS = 25, + GDK_DROP_START = 26, + GDK_DROP_FINISHED = 27, + GDK_CLIENT_EVENT = 28, + GDK_VISIBILITY_NOTIFY = 29, + GDK_NO_EXPOSE = 30, + GDK_SCROLL = 31, + GDK_WINDOW_STATE = 32, + GDK_SETTING = 33, + GDK_OWNER_CHANGE = 34, + GDK_GRAB_BROKEN = 35 + } + + internal enum GdkWMDecoration { + GDK_DECOR_ALL = 1 << 0, + GDK_DECOR_BORDER = 1 << 1, + GDK_DECOR_RESIZEH = 1 << 2, + GDK_DECOR_TITLE = 1 << 3, + GDK_DECOR_MENU = 1 << 4, + GDK_DECOR_MINIMIZE = 1 << 5, + GDK_DECOR_MAXIMIZE = 1 << 6 + } + + internal enum GdkWMFunction { + GDK_FUNC_ALL = 1 << 0, + GDK_FUNC_RESIZE = 1 << 1, + GDK_FUNC_MOVE = 1 << 2, + GDK_FUNC_MINIMIZE = 1 << 3, + GDK_FUNC_MAXIMIZE = 1 << 4, + GDK_FUNC_CLOSE = 1 << 5 + } + + internal enum GdkCursorType { + GDK_X_CURSOR = 0, + GDK_ARROW = 2, + GDK_BASED_ARROW_DOWN = 4, + GDK_BASED_ARROW_UP = 6, + GDK_BOAT = 8, + GDK_BOGOSITY = 10, + GDK_BOTTOM_LEFT_CORNER = 12, + GDK_BOTTOM_RIGHT_CORNER = 14, + GDK_BOTTOM_SIDE = 16, + GDK_BOTTOM_TEE = 18, + GDK_BOX_SPIRAL = 20, + GDK_CENTER_PTR = 22, + GDK_CIRCLE = 24, + GDK_CLOCK = 26, + GDK_COFFEE_MUG = 28, + GDK_CROSS = 30, + GDK_CROSS_REVERSE = 32, + GDK_CROSSHAIR = 34, + GDK_DIAMOND_CROSS = 36, + GDK_DOT = 38, + GDK_DOTBOX = 40, + GDK_DOUBLE_ARROW = 42, + GDK_DRAFT_LARGE = 44, + GDK_DRAFT_SMALL = 46, + GDK_DRAPED_BOX = 48, + GDK_EXCHANGE = 50, + GDK_FLEUR = 52, + GDK_GOBBLER = 54, + GDK_GUMBY = 56, + GDK_HAND1 = 58, + GDK_HAND2 = 60, + GDK_HEART = 62, + GDK_ICON = 64, + GDK_IRON_CROSS = 66, + GDK_LEFT_PTR = 68, + GDK_LEFT_SIDE = 70, + GDK_LEFT_TEE = 72, + GDK_LEFTBUTTON = 74, + GDK_LL_ANGLE = 76, + GDK_LR_ANGLE = 78, + GDK_MAN = 80, + GDK_MIDDLEBUTTON = 82, + GDK_MOUSE = 84, + GDK_PENCIL = 86, + GDK_PIRATE = 88, + GDK_PLUS = 90, + GDK_QUESTION_ARROW = 92, + GDK_RIGHT_PTR = 94, + GDK_RIGHT_SIDE = 96, + GDK_RIGHT_TEE = 98, + GDK_RIGHTBUTTON = 100, + GDK_RTL_LOGO = 102, + GDK_SAILBOAT = 104, + GDK_SB_DOWN_ARROW = 106, + GDK_SB_H_DOUBLE_ARROW = 108, + GDK_SB_LEFT_ARROW = 110, + GDK_SB_RIGHT_ARROW = 112, + GDK_SB_UP_ARROW = 114, + GDK_SB_V_DOUBLE_ARROW = 116, + GDK_SHUTTLE = 118, + GDK_SIZING = 120, + GDK_SPIDER = 122, + GDK_SPRAYCAN = 124, + GDK_STAR = 126, + GDK_TARGET = 128, + GDK_TCROSS = 130, + GDK_TOP_LEFT_ARROW = 132, + GDK_TOP_LEFT_CORNER = 134, + GDK_TOP_RIGHT_CORNER = 136, + GDK_TOP_SIDE = 138, + GDK_TOP_TEE = 140, + GDK_TREK = 142, + GDK_UL_ANGLE = 144, + GDK_UMBRELLA = 146, + GDK_UR_ANGLE = 148, + GDK_WATCH = 150, + GDK_XTERM = 152, + GDK_LAST_CURSOR, + GDK_CURSOR_IS_PIXMAP = -1 + } + + internal enum GdkPropMode { + GDK_PROP_MODE_REPLACE, + GDK_PROP_MODE_PREPEND, + GDK_PROP_MODE_APPEND + } + + [StructLayout (LayoutKind.Sequential)] + internal struct GdkGeometry { + internal int min_width; + internal int min_height; + internal int max_width; + internal int max_height; + internal int base_width; + internal int base_height; + internal int width_inc; + internal int height_inc; + internal double min_aspect; + internal double max_aspect; + internal GdkGravity win_gravity; + } + + [StructLayout (LayoutKind.Sequential)] + internal struct GdkWindowAttr { + internal string title; + internal int event_mask; + internal int x, y; + internal int width; + internal int height; + internal GdkWindowClass wclass; + internal IntPtr visual; + internal IntPtr colormap; + internal GdkWindowType window_type; + internal IntPtr cursor; + internal string wmclass_name; + internal string wmclass_class; + internal bool override_redirect; + } + + #region Local Variables + // General + static volatile XplatUIX11GTK Instance; + private static int RefCount; + private static object XlibLock; // Our locking object + + // General X11 + private static IntPtr DisplayHandle; // X11 handle to display + private static IntPtr GdkDisplayHandle; // gdk handle to display + private static int ScreenNo; // Screen number used + private static IntPtr GdkScreen; + private static IntPtr DefaultColormap; // Colormap for screen + private static IntPtr GdkDefaultColormap; // Gdk Colormap for screen + private static IntPtr CustomVisual; // Visual for window creation + private static IntPtr GdkCustomVisual; + private static IntPtr CustomColormap; // Colormap for window creation + private static IntPtr GdkCustomColormap; + private static int VisualBestDepth; + private static IntPtr RootWindow; // Handle of the root window for the screen/display + private static IntPtr GdkRootWindow; // Gdk handle of the root window for the screen/display + private static IntPtr FosterParent; // Container to hold child windows until their parent exists + private static IntPtr GdkFosterParent; // Container to hold child windows until their parent exists + private static XErrorHandler ErrorHandler; // Error handler delegate + private static bool ErrorExceptions; // Throw exceptions on X errors + private static bool PostQuitState; // True if we've got an pending exit + + // Clipboard + private static IntPtr ClipMagic = new IntPtr(27051977); + + // Communication + private static int PostAtom; // PostMessage atom + private static int AsyncAtom; // Support for async messages + + // Message Loop + private static XEventQueue MessageQueue; // Holds our queued up events + #if __MonoCS__ // + private static Pollfd[] pollfds; // For watching the X11 socket + #endif // + private static X11Keyboard Keyboard; // + private static X11Dnd Dnd; + private static Socket listen; // + private static Socket wake; // + private static Socket wake_receive; // + private static byte[] network_buffer; // + + + // Focus tracking + private static IntPtr ActiveWindow; // Handle of the active window + private static IntPtr FocusWindow; // Handle of the window with keyboard focus (if any) + + // Modality support + private static Stack ModalWindows; // Stack of our modal windows + + // Systray + private static IntPtr SystrayMgrWindow; // Handle of the Systray Manager window + + // Cursors + private static IntPtr LastCursorWindow; // The last window we set the cursor on + private static IntPtr LastCursorHandle; // The handle that was last set on LastCursorWindow + private static IntPtr OverrideCursorHandle; // The cursor that is set to override any other cursors + + // Caret + private static CaretStruct Caret; // + + // Support for Window Styles + private static int[] NetAtoms; // All atoms we know + + // mouse hover message generation + private static HoverStruct HoverState; // + + // double click message generation + private static ClickStruct ClickPending; // + + // Support for mouse grab + private static GrabStruct Grab; // + + // State + private static Point MousePosition; // Last position of mouse, in screen coords + internal static MouseButtons MouseState; // Last state of mouse buttons + + // Timers + private static ArrayList TimerList; // Holds SWF.Timers + + // 'Constants' + private static int DoubleClickInterval; // msec; max interval between clicks to count as double click + + const GdkEventMask GdkSelectInputMask = GdkEventMask.GDK_BUTTON_PRESS_MASK | + GdkEventMask.GDK_BUTTON_RELEASE_MASK | + GdkEventMask.GDK_KEY_PRESS_MASK | + GdkEventMask.GDK_KEY_RELEASE_MASK | + GdkEventMask.GDK_ENTER_NOTIFY_MASK | + GdkEventMask.GDK_LEAVE_NOTIFY_MASK | + GdkEventMask.GDK_EXPOSURE_MASK | + GdkEventMask.GDK_FOCUS_CHANGE_MASK | + GdkEventMask.GDK_POINTER_MOTION_MASK | + GdkEventMask.GDK_VISIBILITY_NOTIFY_MASK | + GdkEventMask.GDK_SUBSTRUCTURE_MASK | + GdkEventMask.GDK_STRUCTURE_MASK; + + static readonly object lockobj = new object (); + + static Hashtable backing_store = new Hashtable (5); + + #endregion // Local Variables + #region Constructors + private XplatUIX11GTK () + { + Console.WriteLine ("XplatUIX11GTK ctor..."); + // Handle singleton stuff first + RefCount = 0; + + // init gdk + gdk_init_check (IntPtr.Zero, IntPtr.Zero); + + // Now regular initialization + XlibLock = new object (); + MessageQueue = new XEventQueue (); + TimerList = new ArrayList (); + XInitThreads (); + + ErrorExceptions = false; + + // X11 Initialization + SetDisplay (gdk_x11_display_get_xdisplay (gdk_display_get_default ())); + X11DesktopColors.Initialize (); + + // Handle any upcoming errors; we re-set it here, X11DesktopColor stuff might have stolen it (gtk does) + ErrorHandler = new XErrorHandler (HandleError); + XSetErrorHandler (ErrorHandler); + } + #endregion // Constructors + + #region Singleton Specific Code + public static XplatUIX11GTK GetInstance () + { + lock (lockobj) { + if (Instance == null) { + Instance = new XplatUIX11GTK (); + } + RefCount++; + } + return Instance; + } + + public int Reference { + get { + return RefCount; + } + } + #endregion + + #region Internal Properties + internal static IntPtr Display { + get { + return DisplayHandle; + } + + set { + XplatUIX11GTK.GetInstance ().SetDisplay (value); + } + } + + internal static int Screen { + get { + return ScreenNo; + } + + set { + ScreenNo = value; + } + } + + internal static IntPtr RootWindowHandle { + get { + return RootWindow; + } + + set { + RootWindow = value; + } + } + + internal static IntPtr Visual { + get { + return CustomVisual; + } + + set { + CustomVisual = value; + } + } + + internal static IntPtr ColorMap { + get { + return CustomColormap; + } + + set { + CustomColormap = value; + } + } + #endregion + + #region XExceptionClass + internal class XException : ApplicationException { + IntPtr Display; + IntPtr ResourceID; + IntPtr Serial; + XRequest RequestCode; + byte ErrorCode; + byte MinorCode; + + public XException (IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) + { + this.Display = Display; + this.ResourceID = ResourceID; + this.Serial = Serial; + this.RequestCode = RequestCode; + this.ErrorCode = ErrorCode; + this.MinorCode = MinorCode; + } + + public override string Message { + get { + return GetMessage (Display, ResourceID, Serial, ErrorCode, RequestCode, MinorCode); + } + } + + public static string GetMessage (IntPtr Display, IntPtr ResourceID, IntPtr Serial, byte ErrorCode, XRequest RequestCode, byte MinorCode) + { + StringBuilder sb; + string x_error_text; + string error; + + sb = new StringBuilder (160); + XGetErrorText (Display, ErrorCode, sb, sb.Capacity); + x_error_text = sb.ToString (); + + error = String.Format ("\n Error: {0}\n Request: {1:D} ({2})\n Resource ID: 0x{3:x}\n Serial: {4}", x_error_text, RequestCode, RequestCode, ResourceID.ToInt32 (), Serial); + return error; + } + } + #endregion // XExceptionClass + + #region Internal Methods + // native X display handle + internal void SetDisplay (IntPtr display_handle) + { + if (display_handle != IntPtr.Zero) { + Hwnd hwnd; + + if ((GdkDisplayHandle != IntPtr.Zero) && (GdkFosterParent != IntPtr.Zero)) { + hwnd = Hwnd.ObjectFromHandle (gdk_x11_drawable_get_xid (GdkFosterParent)); + gdk_window_destroy (GdkFosterParent); + hwnd.Dispose (); + } + + if (GdkDisplayHandle != IntPtr.Zero) { + gdk_display_close (GdkDisplayHandle); + } + + DisplayHandle = display_handle; + GdkDisplayHandle = gdk_x11_lookup_xdisplay (display_handle); + + // We need to tell System.Drawing our DisplayHandle. FromHdcInternal has + // been hacked to do this for us. + Graphics.FromHdcInternal (DisplayHandle); + + // Debugging support + if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) { + XSynchronize (DisplayHandle, true); + } + + if (Environment.GetEnvironmentVariable ("MONO_XEXCEPTIONS") != null) { + ErrorExceptions = true; + } + + // Generic X11 setup + GdkScreen = gdk_screen_get_default (); + // or gdk_x11_get_default_screen + ScreenNo = gdk_screen_get_number (GdkScreen); + GdkRootWindow = gdk_get_default_root_window (); + RootWindow = gdk_x11_drawable_get_xid (GdkRootWindow); + GdkDefaultColormap = gdk_colormap_get_system (); + DefaultColormap = gdk_x11_colormap_get_xcolormap (GdkDefaultColormap); + + VisualBestDepth = gdk_visual_get_best_depth (); + //Console.WriteLine (VisualBestDepth); + + // Create the foster parent + FosterParent = XCreateSimpleWindow (DisplayHandle, RootWindow, 0, 0, 1, 1, 4, 0, 0); + GdkFosterParent = gdk_window_foreign_new (FosterParent); + + if (GdkFosterParent == IntPtr.Zero) { + Console.WriteLine ("XplatUIX11GTK Constructor failed to create FosterParent"); + } + + hwnd = new Hwnd (); + + hwnd.WholeWindow = FosterParent; + hwnd.ClientWindow = FosterParent; + + // For sleeping on the X11 socket + listen = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); + IPEndPoint ep = new IPEndPoint (IPAddress.Loopback, 0); + listen.Bind (ep); + listen.Listen (1); + + // To wake up when a timer is ready + network_buffer = new byte [10]; + + wake = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); + wake.Connect (listen.LocalEndPoint); + wake_receive = listen.Accept (); + + #if __MonoCS__ + pollfds = new Pollfd [2]; + pollfds [0] = new Pollfd (); + pollfds [0].fd = XConnectionNumber (DisplayHandle); + pollfds [0].events = PollEvents.POLLIN; + + pollfds [1] = new Pollfd (); + pollfds [1].fd = wake_receive.Handle.ToInt32 (); + pollfds [1].events = PollEvents.POLLIN; + #endif + + Keyboard = new X11Keyboard (DisplayHandle); + Dnd = new X11Dnd (DisplayHandle); + + PostQuitState = false; + + DoubleClickInterval = 500; + + HoverState.Interval = 500; + HoverState.Timer = new Timer (); + HoverState.Timer.Enabled = false; + HoverState.Timer.Interval = HoverState.Interval; + HoverState.Timer.Tick += new EventHandler (MouseHover); + HoverState.X = -1; + HoverState.Y = -1; + + ActiveWindow = IntPtr.Zero; + FocusWindow = IntPtr.Zero; + ModalWindows = new Stack (3); + + MouseState = MouseButtons.None; + MousePosition = new Point (0, 0); + + Caret.Timer = new Timer (); + Caret.Timer.Interval = 500; // FIXME - where should this number come from? + Caret.Timer.Tick += new EventHandler (CaretCallback); + + SetupAtoms (); + + // Grab atom changes off the root window to catch certain WM events + gdk_window_set_events (GdkRootWindow, (int)GdkEventMask.GDK_PROPERTY_CHANGE_MASK); + + // Handle any upcoming errors + ErrorHandler = new XErrorHandler (HandleError); + XSetErrorHandler (ErrorHandler); + } else { + throw new ArgumentNullException ("Display", "Could not open display (X-Server required. Check your DISPLAY environment variable)"); + } + } + #endregion // Internal Methods + + #region Private Methods + private static void SetupAtoms () + { + NetAtoms = new int [(int)NA.LAST_NET_ATOM]; + + NetAtoms [(int)NA.WM_PROTOCOLS] = XInternAtom (DisplayHandle, "WM_PROTOCOLS", false); + NetAtoms [(int)NA.WM_DELETE_WINDOW] = XInternAtom (DisplayHandle, "WM_DELETE_WINDOW", false); + NetAtoms [(int)NA.WM_TAKE_FOCUS] = XInternAtom (DisplayHandle, "WM_TAKE_FOCUS", false); + + NetAtoms [(int)NA._NET_SUPPORTED] = XInternAtom (DisplayHandle, "_NET_SUPPORTED", false); + NetAtoms [(int)NA._NET_CLIENT_LIST] = XInternAtom (DisplayHandle, "_NET_CLIENT_LIST", false); + NetAtoms [(int)NA._NET_NUMBER_OF_DESKTOPS] = XInternAtom (DisplayHandle, "_NET_NUMBER_OF_DESKTOPS", false); + NetAtoms [(int)NA._NET_DESKTOP_GEOMETRY] = XInternAtom (DisplayHandle, "_NET_DESKTOP_GEOMETRY", false); + NetAtoms [(int)NA._NET_DESKTOP_VIEWPORT] = XInternAtom (DisplayHandle, "_NET_DESKTOP_VIEWPORT", false); + NetAtoms [(int)NA._NET_CURRENT_DESKTOP] = XInternAtom (DisplayHandle, "_NET_CURRENT_DESKTOP", false); + NetAtoms [(int)NA._NET_DESKTOP_NAMES] = XInternAtom (DisplayHandle, "_NET_DESKTOP_NAMES", false); + NetAtoms [(int)NA._NET_ACTIVE_WINDOW] = XInternAtom (DisplayHandle, "_NET_ACTIVE_WINDOW", false); + NetAtoms [(int)NA._NET_WORKAREA] = XInternAtom (DisplayHandle, "_NET_WORKAREA", false); + NetAtoms [(int)NA._NET_SUPPORTING_WM_CHECK] = XInternAtom (DisplayHandle, "_NET_SUPPORTING_WM_CHECK", false); + NetAtoms [(int)NA._NET_VIRTUAL_ROOTS] = XInternAtom (DisplayHandle, "_NET_VIRTUAL_ROOTS", false); + NetAtoms [(int)NA._NET_DESKTOP_LAYOUT] = XInternAtom (DisplayHandle, "_NET_DESKTOP_LAYOUT", false); + NetAtoms [(int)NA._NET_SHOWING_DESKTOP] = XInternAtom (DisplayHandle, "_NET_SHOWING_DESKTOP", false); + + NetAtoms [(int)NA._NET_CLOSE_WINDOW] = XInternAtom (DisplayHandle, "_NET_CLOSE_WINDOW", false); + NetAtoms [(int)NA._NET_MOVERESIZE_WINDOW] = XInternAtom (DisplayHandle, "_NET_MOVERESIZE_WINDOW", false); + NetAtoms [(int)NA._NET_WM_MOVERESIZE] = XInternAtom (DisplayHandle, "_NET_WM_MOVERESIZE", false); + NetAtoms [(int)NA._NET_RESTACK_WINDOW] = XInternAtom (DisplayHandle, "_NET_RESTACK_WINDOW", false); + NetAtoms [(int)NA._NET_REQUEST_FRAME_EXTENTS] = XInternAtom (DisplayHandle, "_NET_REQUEST_FRAME_EXTENTS", false); + + NetAtoms [(int)NA._NET_WM_NAME] = XInternAtom (DisplayHandle, "_NET_WM_NAME", false); + NetAtoms [(int)NA._NET_WM_VISIBLE_NAME] = XInternAtom (DisplayHandle, "_NET_WM_VISIBLE_NAME", false); + NetAtoms [(int)NA._NET_WM_ICON_NAME] = XInternAtom (DisplayHandle, "_NET_WM_ICON_NAME", false); + NetAtoms [(int)NA._NET_WM_VISIBLE_ICON_NAME] = XInternAtom (DisplayHandle, "_NET_WM_VISIBLE_ICON_NAME", false); + NetAtoms [(int)NA._NET_WM_DESKTOP] = XInternAtom (DisplayHandle, "_NET_WM_DESKTOP", false); + NetAtoms [(int)NA._NET_WM_WINDOW_TYPE] = XInternAtom (DisplayHandle, "_NET_WM_WINDOW_TYPE", false); + NetAtoms [(int)NA._NET_WM_STATE] = XInternAtom (DisplayHandle, "_NET_WM_STATE", false); + NetAtoms [(int)NA._NET_WM_ALLOWED_ACTIONS] = XInternAtom (DisplayHandle, "_NET_WM_ALLOWED_ACTIONS", false); + NetAtoms [(int)NA._NET_WM_STRUT] = XInternAtom (DisplayHandle, "_NET_WM_STRUT", false); + NetAtoms [(int)NA._NET_WM_STRUT_PARTIAL] = XInternAtom (DisplayHandle, "_NET_WM_STRUT_PARTIAL", false); + NetAtoms [(int)NA._NET_WM_ICON_GEOMETRY] = XInternAtom (DisplayHandle, "_NET_WM_ICON_GEOMETRY", false); + NetAtoms [(int)NA._NET_WM_ICON] = XInternAtom (DisplayHandle, "_NET_WM_ICON", false); + NetAtoms [(int)NA._NET_WM_PID] = XInternAtom (DisplayHandle, "_NET_WM_PID", false); + NetAtoms [(int)NA._NET_WM_HANDLED_ICONS] = XInternAtom (DisplayHandle, "_NET_WM_HANDLED_ICONS", false); + NetAtoms [(int)NA._NET_WM_USER_TIME] = XInternAtom (DisplayHandle, "_NET_WM_USER_TIME", false); + NetAtoms [(int)NA._NET_FRAME_EXTENTS] = XInternAtom (DisplayHandle, "_NET_FRAME_EXTENTS", false); + + NetAtoms [(int)NA._NET_WM_PING] = XInternAtom (DisplayHandle, "_NET_WM_PING", false); + NetAtoms [(int)NA._NET_WM_SYNC_REQUEST] = XInternAtom (DisplayHandle, "_NET_WM_SYNC_REQUEST", false); + + NetAtoms [(int)NA._NET_SYSTEM_TRAY_S] = XInternAtom (DisplayHandle, "_NET_SYSTEM_TRAY_S" + ScreenNo.ToString (), false); + NetAtoms [(int)NA._NET_SYSTEM_TRAY_OPCODE] = XInternAtom (DisplayHandle, "_NET_SYSTEM_TRAY_OPCODE", false); + NetAtoms [(int)NA._NET_SYSTEM_TRAY_ORIENTATION] = XInternAtom (DisplayHandle, "_NET_SYSTEM_TRAY_ORIENTATION", false); + + NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_HORZ] = XInternAtom (DisplayHandle, "_NET_WM_STATE_MAXIMIZED_HORZ", false); + NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_VERT] = XInternAtom (DisplayHandle, "_NET_WM_STATE_MAXIMIZED_VERT", false); + NetAtoms [(int)NA._NET_WM_STATE_HIDDEN] = XInternAtom (DisplayHandle, "_NET_WM_STATE_HIDDEN", false); + + NetAtoms [(int)NA._XEMBED] = XInternAtom (DisplayHandle, "_XEMBED", false); + NetAtoms [(int)NA._XEMBED_INFO] = XInternAtom (DisplayHandle, "_XEMBED_INFO", false); + + NetAtoms [(int)NA._MOTIF_WM_HINTS] = XInternAtom (DisplayHandle, "_MOTIF_WM_HINTS", false); + + NetAtoms [(int)NA._NET_WM_STATE_NO_TASKBAR] = XInternAtom (DisplayHandle, "_NET_WM_STATE_NO_TASKBAR", false); + NetAtoms [(int)NA._NET_WM_STATE_ABOVE] = XInternAtom (DisplayHandle, "_NET_WM_STATE_ABOVE", false); + NetAtoms [(int)NA._NET_WM_STATE_MODAL] = XInternAtom (DisplayHandle, "_NET_WM_STATE_MODAL", false); + NetAtoms [(int)NA._NET_WM_CONTEXT_HELP] = XInternAtom (DisplayHandle, "_NET_WM_CONTEXT_HELP", false); + NetAtoms [(int)NA._NET_WM_WINDOW_OPACITY] = XInternAtom (DisplayHandle, "_NET_WM_WINDOW_OPACITY", false); + + // Clipboard support + NetAtoms [(int)NA.CLIPBOARD] = XInternAtom (DisplayHandle, "CLIPBOARD", false); + NetAtoms [(int)NA.DIB] = (int)Atom.XA_PIXMAP; + NetAtoms [(int)NA.OEMTEXT] = XInternAtom (DisplayHandle, "COMPOUND_TEXT", false); + NetAtoms [(int)NA.UNICODETEXT] = XInternAtom (DisplayHandle, "UTF8_STRING", false); + NetAtoms [(int)NA.TARGETS] = XInternAtom (DisplayHandle, "TARGETS", false); + + // Special Atoms + AsyncAtom = XInternAtom (DisplayHandle, "_SWF_AsyncAtom", false); + PostAtom = XInternAtom (DisplayHandle, "_SWF_PostMessageAtom", false); + HoverState.Atom = XInternAtom (DisplayHandle, "_SWF_HoverAtom", false); + } + + private void GetSystrayManagerWindow () + { + gdk_x11_grab_server (); + SystrayMgrWindow = XGetSelectionOwner (DisplayHandle, NetAtoms [(int)NA._NET_SYSTEM_TRAY_S]); + gdk_x11_ungrab_server (); + gdk_display_flush (GdkDisplayHandle); + } + + private void SendNetWMMessage (IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) + { + XEvent xev; + + xev = new XEvent (); + xev.ClientMessageEvent.type = XEventName.ClientMessage; + xev.ClientMessageEvent.send_event = true; + xev.ClientMessageEvent.window = window; + xev.ClientMessageEvent.message_type = message_type; + xev.ClientMessageEvent.format = 32; + xev.ClientMessageEvent.ptr1 = l0; + xev.ClientMessageEvent.ptr2 = l1; + xev.ClientMessageEvent.ptr3 = l2; + XSendEvent (DisplayHandle, RootWindow, false, EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask, ref xev); + } + + private void SendNetClientMessage (IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) + { + XEvent xev; + + xev = new XEvent (); + xev.ClientMessageEvent.type = XEventName.ClientMessage; + xev.ClientMessageEvent.send_event = true; + xev.ClientMessageEvent.window = window; + xev.ClientMessageEvent.message_type = message_type; + xev.ClientMessageEvent.format = 32; + xev.ClientMessageEvent.ptr1 = l0; + xev.ClientMessageEvent.ptr2 = l1; + xev.ClientMessageEvent.ptr3 = l2; + XSendEvent (DisplayHandle, window, false, EventMask.NoEventMask, ref xev); + } + + private void DeriveStyles (IntPtr handle, int Style, int ExStyle, out FormBorderStyle border_style, out TitleStyle title_style, out int caption_height, out int tool_caption_height) + { + + // Only MDI windows get caption_heights + caption_height = 0; + tool_caption_height = 19; + + if ((Style & (int) WindowStyles.WS_CHILD) != 0) { + if ((Style & (int) WindowStyles.WS_BORDER) == 0) { + border_style = FormBorderStyle.None; + } else if ((ExStyle & (int) WindowStyles.WS_EX_CLIENTEDGE) != 0) { + border_style = FormBorderStyle.Fixed3D; + } else { + border_style = FormBorderStyle.FixedSingle; + } + title_style = TitleStyle.None; + } else { + bool is_mdi = false; + + if ((ExStyle & (int) WindowStyles.WS_EX_MDICHILD) != 0) { + caption_height = 26; + is_mdi = true; + } + + title_style = TitleStyle.None; + if ((Style & (int)WindowStyles.WS_CAPTION) != 0) { + if ((ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) { + title_style = TitleStyle.Tool; + } else { + title_style = TitleStyle.Normal; + } + } + + if (!is_mdi) { + border_style = FormBorderStyle.None; + + if ((Style & (int)WindowStyles.WS_THICKFRAME) != 0) { + if ((ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) { + border_style = FormBorderStyle.SizableToolWindow; + } else { + border_style = FormBorderStyle.Sizable; + } + } else { + if ((ExStyle & (int)WindowStyles.WS_EX_CLIENTEDGE) != 0) { + border_style = FormBorderStyle.Fixed3D; + } else if ((ExStyle & (int)WindowStyles.WS_EX_DLGMODALFRAME) != 0) { + border_style = FormBorderStyle.FixedDialog; + } else if ((ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) { + border_style = FormBorderStyle.FixedToolWindow; + } else if ((Style & (int)WindowStyles.WS_BORDER) != 0) { + border_style = FormBorderStyle.Sizable; + } else { + border_style = FormBorderStyle.None; + } + } + } else { + if ((Style & (int) WindowStyles.WS_OVERLAPPEDWINDOW) != 0 || + (ExStyle & (int) WindowStyles.WS_EX_TOOLWINDOW) != 0) { + border_style = (FormBorderStyle) 0xFFFF; + } else { + border_style = FormBorderStyle.None; + } + } + } + } + + private void SetHwndStyles (Hwnd hwnd, CreateParams cp) + { + DeriveStyles (hwnd.Handle, cp.Style, cp.ExStyle, out hwnd.border_style, out hwnd.title_style, out hwnd.caption_height, out hwnd.tool_caption_height); + } + + private void SetWMStyles (Hwnd hwnd, CreateParams cp) + { + GdkWMDecoration decorations = GdkWMDecoration.GDK_DECOR_ALL; + + if ((cp.Style & (int)WindowStyles.WS_CAPTION) != 0) { + decorations |= GdkWMDecoration.GDK_DECOR_TITLE | GdkWMDecoration.GDK_DECOR_MENU; + } + + if ((cp.Style & ((int)WindowStyles.WS_THICKFRAME)) != 0) { + decorations |= GdkWMDecoration.GDK_DECOR_BORDER | GdkWMDecoration.GDK_DECOR_RESIZEH; + } + if ((cp.Style & ((int)WindowStyles.WS_MINIMIZEBOX)) != 0) { + decorations |= GdkWMDecoration.GDK_DECOR_MINIMIZE; + } + + if ((cp.Style & ((int)WindowStyles.WS_MAXIMIZEBOX)) != 0) { + decorations |= GdkWMDecoration.GDK_DECOR_MAXIMIZE; + } + + // is this needed ? most window managers do not even honour any MotifFunctions... +// if ((cp.Style & ((int)WindowStyles.WS_SYSMENU)) != 0) { +// functions |= MotifFunctions.Close; +// } + + if ((cp.ExStyle & ((int)WindowStyles.WS_EX_DLGMODALFRAME)) != 0) { + decorations |= GdkWMDecoration.GDK_DECOR_BORDER; + } + + if ((cp.Style & ((int)WindowStyles.WS_DLGFRAME)) != 0) { + decorations |= GdkWMDecoration.GDK_DECOR_BORDER; + } + + if ((cp.Style & ((int)WindowStyles.WS_BORDER)) != 0) { + decorations |= GdkWMDecoration.GDK_DECOR_BORDER; + } + + if ((cp.ExStyle & ((int)WindowStyles.WS_EX_TOOLWINDOW)) != 0) { + decorations = 0; + } + + gdk_window_set_decorations (gdk_window_foreign_new (hwnd.whole_window), (int)decorations); + } + + private void SetIcon (Hwnd hwnd, Icon icon) + { + Bitmap bitmap; + int size; + uint[] data; + int index; + + bitmap = icon.ToBitmap (); + index = 0; + size = bitmap.Width * bitmap.Height + 2; + data = new uint [size]; + + data [index++] = (uint)bitmap.Width; + data [index++] = (uint)bitmap.Height; + + for (int y = 0; y < bitmap.Height; y++) { + for (int x = 0; x < bitmap.Width; x++) { + data [index++] = (uint)bitmap.GetPixel (x, y).ToArgb (); + } + } + XChangeProperty (DisplayHandle, hwnd.whole_window, NetAtoms [(int)NA._NET_WM_ICON], Atom.XA_CARDINAL, 32, PropertyMode.Replace, data, size); + } + + private IntPtr ImageToPixmap (Image image) + { + return IntPtr.Zero; + } + + private void WakeupMain () + { + wake.Send (new byte [] { 0xFF }); + } + + private void TranslatePropertyToClipboard (int property) + { + Atom actual_atom; + int actual_format; + int nitems; + int bytes_after; + IntPtr prop = IntPtr.Zero; + + Clipboard.Item = null; + + XGetWindowProperty (DisplayHandle, FosterParent, property, 0, 0x7fffffff, true, Atom.AnyPropertyType, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + + if (nitems > 0) { + if (property == (int)Atom.XA_STRING) { + Clipboard.Item = Marshal.PtrToStringAnsi (prop); + } else if (property == (int)Atom.XA_BITMAP) { + // FIXME - convert bitmap to image + } else if (property == (int)Atom.XA_PIXMAP) { + // FIXME - convert pixmap to image + } else if (property == NetAtoms [(int)NA.OEMTEXT]) { + Clipboard.Item = Marshal.PtrToStringAnsi (prop); + } else if (property == NetAtoms [(int)NA.UNICODETEXT]) { + Clipboard.Item = Marshal.PtrToStringAnsi (prop); + } + + XFree (prop); + } + } + + private void AddExpose (XEvent xevent) + { + Hwnd hwnd; + + hwnd = Hwnd.GetObjectFromWindow (xevent.AnyEvent.window); + + // Don't waste time + if (hwnd == null) { + return; + } + + if (xevent.AnyEvent.window == hwnd.client_window) { + hwnd.AddInvalidArea (xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height); + if (!hwnd.expose_pending) { + MessageQueue.Enqueue (xevent); + hwnd.expose_pending = true; + } + } else { + if (!hwnd.nc_expose_pending) { + MessageQueue.Enqueue (xevent); + hwnd.nc_expose_pending = true; + } + } + } + + private void InvalidateWholeWindow (IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + InvalidateWholeWindow (handle, new Rectangle (0, 0, hwnd.Width, hwnd.Height)); + } + + private void InvalidateWholeWindow (IntPtr handle, Rectangle rectangle) + { + Hwnd hwnd; + XEvent xevent; + + hwnd = Hwnd.ObjectFromHandle (handle); + + + xevent = new XEvent (); + xevent.type = XEventName.Expose; + xevent.ExposeEvent.display = DisplayHandle; + xevent.ExposeEvent.window = hwnd.whole_window; + + xevent.ExposeEvent.x = rectangle.X; + xevent.ExposeEvent.y = rectangle.Y; + xevent.ExposeEvent.width = rectangle.Width; + xevent.ExposeEvent.height = rectangle.Height; + + AddExpose (xevent); + } + + private void WholeToScreen (IntPtr handle, ref int x, ref int y) + { + int dest_x_return; + int dest_y_return; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + lock (XlibLock) { + gdk_window_get_origin (gdk_window_lookup (hwnd.whole_window), out dest_x_return, out dest_y_return); + } + + x = dest_x_return; + y = dest_y_return; + } + + private void AddConfigureNotify (XEvent xevent) + { + Hwnd hwnd; + + hwnd = Hwnd.GetObjectFromWindow (xevent.ConfigureEvent.window); + + // Don't waste time + if (hwnd == null) { + return; + } + + if (xevent.ConfigureEvent.window == hwnd.whole_window) { + if (!hwnd.reparented) { + hwnd.x = xevent.ConfigureEvent.x; + hwnd.y = xevent.ConfigureEvent.y; + } else { + int dummy_int; + + gdk_window_get_geometry (gdk_window_lookup (hwnd.whole_window), out hwnd.x, out hwnd.y, out dummy_int, out dummy_int, out dummy_int); + } + + hwnd.width = xevent.ConfigureEvent.width; + hwnd.height = xevent.ConfigureEvent.height; + + if (!hwnd.configure_pending) { + MessageQueue.Enqueue (xevent); + hwnd.configure_pending = true; + } + } + // We drop configure events for Client windows + } + + private void ShowCaret () + { + if ((Caret.gc == IntPtr.Zero) || Caret.On) { + return; + } + Caret.On = true; + + // gdk_gc_set_foreground + // gdk_draw_line + lock (XlibLock) { + XDrawLine (DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height); + } + } + + private void HideCaret () + { + if ((Caret.gc == IntPtr.Zero) || !Caret.On) { + return; + } + Caret.On = false; + + // gdk_gc_set_foreground + // gdk_draw_text_wc + lock (XlibLock) { + XDrawLine (DisplayHandle, Caret.Window, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height); + } + } + + private int NextTimeout (DateTime now) + { + int timeout = Int32.MaxValue; + lock (TimerList) { + foreach (Timer timer in TimerList) { + int next = (int) (timer.Expires - now).TotalMilliseconds; + if (next < 0) { + return 0; // Have a timer that has already expired + } + + if (next < timeout) { + timeout = next; + } + } + } + if (timeout < Timer.Minimum) { + timeout = Timer.Minimum; + } + + return timeout; + } + + private void CheckTimers (DateTime now) + { + lock (TimerList) { + int count; + + count = TimerList.Count; + + if (count == 0) { + return; + } + + for (int i = 0; i < TimerList.Count; i++) { + Timer timer; + + timer = (Timer) TimerList [i]; + + if (timer.Enabled && timer.Expires <= now) { + timer.Update (now); + timer.FireTick (); + } + } + } + } + + private void UpdateMessageQueue () + { + DateTime now; + int pending; + + now = DateTime.Now; + + lock (XlibLock) { + pending = XPending (DisplayHandle); + } + + if (pending == 0) { + if (Idle != null) { + Idle (this, EventArgs.Empty); + } + + lock (XlibLock) { + pending = XPending (DisplayHandle); + } + } + + if (pending == 0) { + int timeout; + + timeout = NextTimeout (now); + if (timeout > 0) { + #if __MonoCS__ + Syscall.poll (pollfds, (uint) pollfds.Length, timeout); + // Clean out buffer, so we're not busy-looping on the same data + if (pollfds[1].revents != 0) { + wake_receive.Receive(network_buffer, 0, 1, SocketFlags.None); + } + #endif + lock (XlibLock) { + pending = XPending (DisplayHandle); + } + } + } + + CheckTimers (now); + + if (pending == 0) { + lock (XlibLock) { + pending = XPending (DisplayHandle); + } + } + + while (pending > 0) { + XEvent xevent = new XEvent (); + + lock (XlibLock) { + XNextEvent (DisplayHandle, ref xevent); + } +//Console.WriteLine("Got x event {0}", xevent); + switch (xevent.type) { + case XEventName.Expose: + AddExpose (xevent); + break; + + case XEventName.SelectionClear: { + // Should we do something? + break; + } + + case XEventName.SelectionRequest: { + if (Dnd.HandleSelectionRequestEvent (ref xevent)) + break; + XEvent sel_event; + + sel_event = new XEvent (); + sel_event.SelectionEvent.type = XEventName.SelectionNotify; + sel_event.SelectionEvent.send_event = true; + sel_event.SelectionEvent.display = DisplayHandle; + sel_event.SelectionEvent.selection = xevent.SelectionRequestEvent.selection; + sel_event.SelectionEvent.target = xevent.SelectionRequestEvent.target; + sel_event.SelectionEvent.requestor = xevent.SelectionRequestEvent.requestor; + sel_event.SelectionEvent.time = xevent.SelectionRequestEvent.time; + sel_event.SelectionEvent.property = 0; + + // Seems that some apps support asking for supported types + if (xevent.SelectionEvent.target == NetAtoms [(int)NA.TARGETS]) { + uint[] atoms; + int atom_count; + + atoms = new uint [5]; + atom_count = 0; + + if (Clipboard.Item is String) { + atoms [atom_count++] = (uint)Atom.XA_STRING; + atoms [atom_count++] = (uint)NetAtoms [(int)NA.OEMTEXT]; + atoms [atom_count++] = (uint)NetAtoms [(int)NA.UNICODETEXT]; + } else if (Clipboard.Item is Image) { + atoms [atom_count++] = (uint)Atom.XA_PIXMAP; + atoms [atom_count++] = (uint)Atom.XA_BITMAP; + } else { + // FIXME - handle other types + } + + XChangeProperty (DisplayHandle, xevent.SelectionEvent.requestor, xevent.SelectionRequestEvent.property, xevent.SelectionRequestEvent.target, 32, PropertyMode.Replace, atoms, atom_count); + } else if (Clipboard.Item is string) { + IntPtr buffer; + int buflen; + + buflen = 0; + + if (xevent.SelectionRequestEvent.target == (int)Atom.XA_STRING) { + Byte[] bytes; + + bytes = new ASCIIEncoding ().GetBytes ((string)Clipboard.Item); + buffer = Marshal.AllocHGlobal (bytes.Length); + buflen = bytes.Length; + + for (int i = 0; i < buflen; i++) { + Marshal.WriteByte (buffer, i, bytes [i]); + } + } else if (xevent.SelectionRequestEvent.target == NetAtoms [(int)NA.OEMTEXT]) { + // FIXME - this should encode into ISO2022 + buffer = Marshal.StringToHGlobalAnsi ((string)Clipboard.Item); + while (Marshal.ReadByte (buffer, buflen) != 0) { + buflen++; + } + } else if (xevent.SelectionRequestEvent.target == NetAtoms [(int)NA.UNICODETEXT]) { + buffer = Marshal.StringToHGlobalAnsi ((string)Clipboard.Item); + while (Marshal.ReadByte (buffer, buflen) != 0) { + buflen++; + } + } else { + buffer = IntPtr.Zero; + } + + if (buffer != IntPtr.Zero) { + XChangeProperty (DisplayHandle, xevent.SelectionRequestEvent.requestor, xevent.SelectionRequestEvent.property, xevent.SelectionRequestEvent.target, 8, PropertyMode.Replace, buffer, buflen); + sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property; + Marshal.FreeHGlobal (buffer); + } + } else if (Clipboard.Item is Image) { + if (xevent.SelectionEvent.target == (int)Atom.XA_PIXMAP) { + // FIXME - convert image and store as property + } else if (xevent.SelectionEvent.target == (int)Atom.XA_PIXMAP) { + // FIXME - convert image and store as property + } + } + + XSendEvent (DisplayHandle, xevent.SelectionRequestEvent.requestor, false, EventMask.NoEventMask, ref sel_event); + break; + } + + case XEventName.SelectionNotify: { + if (Clipboard.Enumerating) { + Clipboard.Enumerating = false; + if (xevent.SelectionEvent.property != 0) { + XDeleteProperty (DisplayHandle, FosterParent, xevent.SelectionEvent.property); + if (!Clipboard.Formats.Contains (xevent.SelectionEvent.property)) { + Clipboard.Formats.Add (xevent.SelectionEvent.property); + #if DriverDebugExtra + Console.WriteLine("Got supported clipboard atom format: {0}", xevent.SelectionEvent.property); + #endif + } + } + } else if (Clipboard.Retrieving) { + Clipboard.Retrieving = false; + if (xevent.SelectionEvent.property != 0) { + TranslatePropertyToClipboard (xevent.SelectionEvent.property); + } else { + Clipboard.Item = null; + } + } else { + Dnd.HandleSelectionNotifyEvent (ref xevent); + } + break; + } + + case XEventName.KeyPress: + case XEventName.KeyRelease: + case XEventName.ButtonPress: + case XEventName.ButtonRelease: + case XEventName.MotionNotify: + case XEventName.EnterNotify: + case XEventName.LeaveNotify: + case XEventName.CreateNotify: + case XEventName.DestroyNotify: + case XEventName.FocusIn: + case XEventName.FocusOut: + case XEventName.ClientMessage: + case XEventName.ReparentNotify: + MessageQueue.Enqueue (xevent); + break; + + case XEventName.ConfigureNotify: + AddConfigureNotify (xevent); + break; + + case XEventName.PropertyNotify: + if (xevent.PropertyEvent.atom == NetAtoms [(int)NA._NET_ACTIVE_WINDOW]) { + Atom actual_atom; + int actual_format; + int nitems; + int bytes_after; + IntPtr prop = IntPtr.Zero; + IntPtr prev_active;; + + prev_active = ActiveWindow; + XGetWindowProperty (DisplayHandle, RootWindow, NetAtoms [(int)NA._NET_ACTIVE_WINDOW], 0, 1, false, Atom.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + if ((nitems > 0) && (prop != IntPtr.Zero)) { + ActiveWindow = Hwnd.GetHandleFromWindow ((IntPtr)Marshal.ReadInt32 (prop)); + XFree (prop); + + if (prev_active != ActiveWindow) { + if (prev_active != IntPtr.Zero) { + PostMessage (prev_active, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero); + } + if (ActiveWindow != IntPtr.Zero) { + PostMessage (ActiveWindow, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_ACTIVE, IntPtr.Zero); + } + } + if (ModalWindows.Count == 0) { + break; + } else { + // Modality handling, if we are modal and the new active window is one + // of ours but not the modal one, switch back to the modal window + + if (NativeWindow.FromHandle (ActiveWindow) != null) { + if (ActiveWindow != (IntPtr)ModalWindows.Peek ()) { + Activate ((IntPtr)ModalWindows.Peek ()); + } + } + break; + } + } + } + break; + + } + + lock (XlibLock) { + pending = XPending (DisplayHandle); + } + } + } + + private IntPtr GetMousewParam (int Delta) + { + int result = 0; + + if ((MouseState & MouseButtons.Left) != 0) { + result |= (int)MsgButtons.MK_LBUTTON; + } + + if ((MouseState & MouseButtons.Middle) != 0) { + result |= (int)MsgButtons.MK_MBUTTON; + } + + if ((MouseState & MouseButtons.Right) != 0) { + result |= (int)MsgButtons.MK_RBUTTON; + } + + Keys mods = ModifierKeys; + if ((mods & Keys.Control) != 0) { + result |= (int)MsgButtons.MK_CONTROL; + } + + if ((mods & Keys.Shift) != 0) { + result |= (int)MsgButtons.MK_SHIFT; + } + + result |= Delta << 16; + + return (IntPtr)result; + } + private IntPtr XGetParent (IntPtr handle) + { + return gdk_x11_drawable_get_xid (gdk_window_get_parent (gdk_window_lookup (handle))); + } + + private int HandleError (IntPtr display, ref XErrorEvent error_event) + { + if (ErrorExceptions) { + throw new XException (error_event.display, error_event.resourceid, error_event.serial, error_event.error_code, error_event.request_code, error_event.minor_code); + } else { + Console.WriteLine ("X11 Error encountered: {0}{1}\n", XException.GetMessage (error_event.display, error_event.resourceid, error_event.serial, error_event.error_code, error_event.request_code, error_event.minor_code), Environment.StackTrace); + } + return 0; + } + + private void DestroyChildWindow (ShiftUI.Widget c) + { + Hwnd hwnd; + int i; + ShiftUI.Widget[] Widgets; + + if (c != null) { + Widgets = c.Widgets.GetAllWidgets (); + + for (i = 0; i < Widgets.Length; i++) { + if (Widgets [i].IsHandleCreated) { + hwnd = Hwnd.ObjectFromHandle (Widgets [i].Handle); + SendMessage (Widgets [i].Handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero); + hwnd.Dispose (); + } + DestroyChildWindow (Widgets [i]); + } + } + } + + #endregion // Private Methods + + #region Callbacks + private void MouseHover (object sender, EventArgs e) + { + if ((HoverState.X == MousePosition.X) && (HoverState.Y == MousePosition.Y)) { + XEvent xevent; + + HoverState.Timer.Enabled = false; + + if (HoverState.Window != IntPtr.Zero) { + xevent = new XEvent (); + + xevent.type = XEventName.ClientMessage; + xevent.ClientMessageEvent.display = DisplayHandle; + xevent.ClientMessageEvent.window = (IntPtr)HoverState.Window; + xevent.ClientMessageEvent.message_type = (IntPtr)HoverState.Atom; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = (IntPtr) (HoverState.Y << 16 | HoverState.X); + + MessageQueue.EnqueueLocked (xevent); + + WakeupMain (); + } + } + } + + private void CaretCallback (object sender, EventArgs e) + { + if (Caret.Paused) { + return; + } + Caret.On = !Caret.On; + + XDrawLine (DisplayHandle, Caret.Hwnd, Caret.gc, Caret.X, Caret.Y, Caret.X, Caret.Y + Caret.Height); + } + #endregion // Callbacks + + #region Public Properties + + internal int Caption { + get { + return 25; + } + } + + internal override Size CursorSize { + get { + uint x; + uint y; + gdk_display_get_maximal_cursor_size (GdkDisplayHandle, out x, out y); + + return new Size ((int)x, (int)y); + } + } + + internal override bool DragFullWindows { + get { + return true; + } + } + + internal override Size DragSize { + get { + return new Size (4, 4); + } + } + + internal override Size FrameBorderSize { + get { + throw new NotImplementedException (); + } + } + + internal override Size IconSize { + get { + IntPtr list; + XIconSize size; + int count; + + if (XGetIconSizes (DisplayHandle, RootWindow, out list, out count) != 0) { + long current; + int largest; + + current = (long)list; + largest = 0; + + size = new XIconSize (); + + for (int i = 0; i < count; i++) { + size = (XIconSize)Marshal.PtrToStructure ((IntPtr)current, size.GetType ()); + current += Marshal.SizeOf (size); + + // Look for our preferred size + if (size.min_width == 32) { + XFree (list); + return new Size (32, 32); + } + + if (size.max_width == 32) { + XFree (list); + return new Size (32, 32); + } + + if (size.min_width < 32 && size.max_width > 32) { + int x; + + // check if we can fit one + x = size.min_width; + while (x < size.max_width) { + x += size.width_inc; + if (x == 32) { + XFree (list); + return new Size (32, 32); + } + } + } + + if (largest < size.max_width) { + largest = size.max_width; + } + } + + // We didn't find a match or we wouldn't be here + return new Size (largest, largest); + + } else { + return new Size (32, 32); + } + } + } + + internal override int KeyboardSpeed { + get { + // + // A lot harder: need to do: + // XkbQueryExtension(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 1 + // XkbAllocKeyboard(0x08051008, 0xbfffdf4c, 0xbfffdf50, 0xbfffdf54, 0xbfffdf58) = 0x080517a8 + // XkbGetWidgets(0x08051008, 1, 0x080517a8, 0xbfffdf54, 0xbfffdf58) = 0 + // + // And from that we can tell the repetition rate + // + // Notice, the values must map to: + // [0, 31] which maps to 2.5 to 30 repetitions per second. + // + return 0; + } + } + + internal override int KeyboardDelay { + get { + // + // Return values must range from 0 to 4, 0 meaning 250ms, + // and 4 meaning 1000 ms. + // + return 1; // ie, 500 ms + } + } + + internal override Size MaxWindowTrackSize { + get { + return new Size (WorkingArea.Width, WorkingArea.Height); + } + } + + internal override Size MinimizedWindowSize { + get { + return new Size (1, 1); + } + } + + internal override Size MinimizedWindowSpacingSize { + get { + return new Size (1, 1); + } + } + + internal override Size MinimumWindowSize { + get { + return new Size (1, 1); + } + } + + internal override Size MinWindowTrackSize { + get { + return new Size (1, 1); + } + } + + internal override Keys ModifierKeys { + get { + return Keyboard.ModifierKeys; + } + } + + internal override Size SmallIconSize { + get { + IntPtr list; + XIconSize size; + int count; + + if (XGetIconSizes (DisplayHandle, RootWindow, out list, out count) != 0) { + long current; + int smallest; + + current = (long)list; + smallest = 0; + + size = new XIconSize (); + + for (int i = 0; i < count; i++) { + size = (XIconSize)Marshal.PtrToStructure ((IntPtr)current, size.GetType ()); + current += Marshal.SizeOf (size); + + // Look for our preferred size + if (size.min_width == 16) { + XFree (list); + return new Size (16, 16); + } + + if (size.max_width == 16) { + XFree (list); + return new Size (16, 16); + } + + if (size.min_width < 16 && size.max_width > 16) { + int x; + + // check if we can fit one + x = size.min_width; + while (x < size.max_width) { + x += size.width_inc; + if (x == 16) { + XFree (list); + return new Size (16, 16); + } + } + } + + if (smallest == 0 || smallest > size.min_width) { + smallest = size.min_width; + } + } + + // We didn't find a match or we wouldn't be here + return new Size (smallest, smallest); + + } else { + return new Size (16, 16); + } + } + } + + internal override int MouseButtonCount { + get { + return 3; + } + } + + internal override bool MouseButtonsSwapped { + get { + return false; // FIXME - how to detect? + } + } + + internal override bool MouseWheelPresent { + get { + return true; // FIXME - how to detect? + } + } + + internal override Rectangle VirtualScreen { + get { + return WorkingArea; + } + } + + internal override Rectangle WorkingArea { + get { + Atom actual_atom; + int actual_format; + int nitems; + int bytes_after; + IntPtr prop = IntPtr.Zero; + int width; + int height; + + XGetWindowProperty (DisplayHandle, RootWindow, NetAtoms [(int)NA._NET_DESKTOP_GEOMETRY], 0, 256, false, Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + if ((nitems == 2) && (prop != IntPtr.Zero)) { + width = Marshal.ReadInt32 (prop, 0); + height = Marshal.ReadInt32 (prop, 4); + + XFree (prop); + return new Rectangle (0, 0, width, height); + } else { + XWindowAttributes attributes=new XWindowAttributes (); + + lock (XlibLock) { + XGetWindowAttributes (DisplayHandle, XRootWindow (DisplayHandle, ScreenNo), ref attributes); + } + + return new Rectangle (0, 0, attributes.width, attributes.height); + } + } + } + #endregion // Public properties + + #region Public Static Methods + internal override IntPtr InitializeDriver () + { + lock (this) { + if (GdkDisplayHandle == IntPtr.Zero) { + SetDisplay (gdk_x11_display_get_xdisplay (gdk_display_get_default ())); + } + } + return IntPtr.Zero; + } + + internal override void ShutdownDriver (IntPtr token) + { + lock (this) { + if (GdkDisplayHandle != IntPtr.Zero) { + gdk_display_close (GdkDisplayHandle); + DisplayHandle = IntPtr.Zero; + GdkDisplayHandle = IntPtr.Zero; + } + } + } + + internal override void EnableThemes () + { + ThemesEnabled = true; + } + + + internal override void Activate (IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd != null) lock (XlibLock) { + SendNetWMMessage (hwnd.whole_window, (IntPtr)NetAtoms [(int)NA._NET_ACTIVE_WINDOW], IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + //XRaiseWindow(DisplayHandle, handle); + } + return; + } + + internal override void AudibleAlert (AlertType atype) + { + gdk_display_beep (gdk_x11_lookup_xdisplay (DisplayHandle)); + return; + } + + + internal override void CaretVisible (IntPtr handle, bool visible) + { + // Visible is cumulative; two hides require two shows before the caret is visible again + if (Caret.Hwnd == handle) { + if (visible) { + if (Caret.Visible < 1) { + Caret.Visible++; + Caret.On = false; + if (Caret.Visible == 1) { + ShowCaret (); + Caret.Timer.Start (); + } + } + } else { + Caret.Visible--; + if (Caret.Visible == 0) { + Caret.Timer.Stop (); + HideCaret (); + } + } + } + } + + internal bool CalculateWindowRect (IntPtr handle, ref Rectangle ClientRect, int Style, int ExStyle, Menu menu, out Rectangle WindowRect) + { + FormBorderStyle border_style; + TitleStyle title_style; + int caption_height; + int tool_caption_height; + + DeriveStyles (handle, Style, ExStyle, out border_style, out title_style, + out caption_height, out tool_caption_height); + + WindowRect = Hwnd.GetWindowRectangle (border_style, menu, title_style, + caption_height, tool_caption_height, + ClientRect); + + return true; + } + + internal override void ClientToScreen (IntPtr handle, ref int x, ref int y) + { + int dest_x_return; + int dest_y_return; + IntPtr child; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + lock (XlibLock) { + XTranslateCoordinates (DisplayHandle, hwnd.client_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child); + } + + x = dest_x_return; + y = dest_y_return; + } + + + internal override void CreateCaret (IntPtr handle, int width, int height) + { + XGCValues gc_values; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + if (Caret.Hwnd != IntPtr.Zero) { + DestroyCaret (Caret.Hwnd); + } + + Caret.Hwnd = handle; + Caret.Window = hwnd.client_window; + Caret.Width = width; + Caret.Height = height; + Caret.Visible = 0; + Caret.On = false; + + gc_values = new XGCValues (); + gc_values.line_width = width; + + Caret.gc = XCreateGC (DisplayHandle, Caret.Window, GCFunction.GCLineWidth, ref gc_values); + if (Caret.gc == IntPtr.Zero) { + Caret.Hwnd = IntPtr.Zero; + return; + } + + XSetFunction (DisplayHandle, Caret.gc, GXFunction.GXinvert); + } + + internal override IntPtr CreateWindow (CreateParams cp) + { + GdkWindowAttr gdk_window_attributes; + GdkWindowAttributesType attributes_mask = 0; + Hwnd hwnd; + int X; + int Y; + int Width; + int Height; + IntPtr GdkParentHandle; + IntPtr GdkWholeWindow; + IntPtr GdkClientWindow; + Rectangle ClientRect; + GdkWindowType gdk_window_type; + + + hwnd = new Hwnd (); + + gdk_window_attributes = new GdkWindowAttr (); + + X = cp.X; + Y = cp.Y; + Width = cp.Width; + Height = cp.Height; + + if (Width < 1) Width = 1; + if (Height < 1) Height = 1; + + gdk_window_type = GdkWindowType.GDK_WINDOW_CHILD; + + if (cp.Parent != IntPtr.Zero) { + GdkParentHandle = gdk_window_lookup (Hwnd.ObjectFromHandle (cp.Parent).client_window); + } else { + if ((cp.Style & (int)WindowStyles.WS_CHILD) != 0) { + // We need to use our foster parent window until this poor child gets it's parent assigned + GdkParentHandle = GdkFosterParent; + } else if ((cp.Style & (int)WindowStyles.WS_POPUP) != 0) { + GdkParentHandle = GdkRootWindow; + } else { + // Default position on screen, if window manager doesn't place us somewhere else + if (X < 1) X = 50; + if (Y < 1) Y = 50; + GdkParentHandle = GdkRootWindow; + } + } + +// ValueMask = SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity; + +// Attributes.bit_gravity = Gravity.NorthWestGravity; +// Attributes.win_gravity = Gravity.NorthWestGravity; + + // FIXME: does gdk need that ? + // Save what's under the toolwindow + if ((cp.ExStyle & (int)WindowStyles.WS_EX_TOOLWINDOW) != 0) { +// Attributes.save_under = true; +// ValueMask |= SetWindowValuemask.SaveUnder; + } + + // If we're a popup without caption we override the WM + if ((cp.Style & ((int)WindowStyles.WS_POPUP)) != 0) { + if ((cp.Style & (int)WindowStyles.WS_CAPTION) == 0) { + gdk_window_attributes.override_redirect = true; + attributes_mask |= GdkWindowAttributesType.GDK_WA_NOREDIR; + } + } + + hwnd.x = X; + hwnd.y = Y; + hwnd.width = Width; + hwnd.height = Height; + hwnd.parent = Hwnd.ObjectFromHandle (cp.Parent); + + if ((cp.Style & ((int)WindowStyles.WS_DISABLED)) != 0) { + hwnd.enabled = false; + } + + ClientRect = hwnd.ClientRect; + GdkClientWindow = IntPtr.Zero; + + gdk_window_attributes.x = X; + gdk_window_attributes.y = Y; + gdk_window_attributes.width = Width; + gdk_window_attributes.height = Height; + gdk_window_attributes.window_type = gdk_window_type; + + attributes_mask |= GdkWindowAttributesType.GDK_WA_X | GdkWindowAttributesType.GDK_WA_Y; + + gdk_window_attributes.wclass = GdkWindowClass.GDK_INPUT_OUTPUT; + + lock (XlibLock) { + GdkWholeWindow = gdk_window_new (GdkParentHandle, ref gdk_window_attributes, (int)attributes_mask); + + if (GdkWholeWindow != IntPtr.Zero) { + attributes_mask &= ~GdkWindowAttributesType.GDK_WA_NOREDIR; + + if (GdkCustomVisual != IntPtr.Zero && GdkCustomColormap != IntPtr.Zero) { + attributes_mask |= GdkWindowAttributesType.GDK_WA_COLORMAP | GdkWindowAttributesType.GDK_WA_VISUAL; + gdk_window_attributes.colormap = GdkCustomColormap; + gdk_window_attributes.visual = GdkCustomVisual; + } + + gdk_window_attributes.x = ClientRect.X; + gdk_window_attributes.y = ClientRect.Y; + gdk_window_attributes.width = ClientRect.Width; + gdk_window_attributes.height = ClientRect.Height; + + GdkClientWindow = gdk_window_new (GdkWholeWindow, ref gdk_window_attributes, (int)attributes_mask); + } + } + + if ((GdkWholeWindow == IntPtr.Zero) || (GdkClientWindow == IntPtr.Zero)) { + throw new Exception ("Could not create X11 Gdk windows"); + } + + hwnd.WholeWindow = gdk_x11_drawable_get_xid (GdkWholeWindow); + hwnd.ClientWindow = gdk_x11_drawable_get_xid (GdkClientWindow); + + #if DriverDebug + Console.WriteLine("Created window {0:X} / {1:X} parent {2:X}", ClientWindow.ToInt32(), WholeWindow.ToInt32(), hwnd.parent != null ? hwnd.parent.Handle.ToInt32() : 0); + #endif + + lock (XlibLock) { + gdk_window_set_events (GdkWholeWindow, (int)GdkSelectInputMask); + gdk_window_set_events (GdkClientWindow, (int)GdkSelectInputMask); + + if ((cp.Style & (int)WindowStyles.WS_VISIBLE) != 0) { + gdk_window_show (GdkWholeWindow); + gdk_window_show (GdkClientWindow); + hwnd.visible = true; + } + } + + SetWMStyles (hwnd, cp); + + if ((cp.Style & (int)WindowStyles.WS_MINIMIZE) != 0) { + SetWindowState (hwnd.Handle, FormWindowState.Minimized); + } else if ((cp.Style & (int)WindowStyles.WS_MAXIMIZE) != 0) { + SetWindowState (hwnd.Handle, FormWindowState.Maximized); + } + + // for now make all windows dnd enabled + Dnd.SetAllowDrop (hwnd, true); + + // Set caption/window title + Text (hwnd.Handle, cp.Caption); + + return hwnd.Handle; + } + + internal override IntPtr CreateWindow (IntPtr Parent, int X, int Y, int Width, int Height) + { + CreateParams create_params = new CreateParams (); + + create_params.Caption = ""; + create_params.X = X; + create_params.Y = Y; + create_params.Width = Width; + create_params.Height = Height; + + create_params.ClassName = XplatUI.DefaultClassName; + create_params.ClassStyle = 0; + create_params.ExStyle = 0; + create_params.Parent = IntPtr.Zero; + create_params.Param = 0; + + return CreateWindow (create_params); + } + + internal override IntPtr DefineCursor (Bitmap bitmap, Bitmap mask, Color cursor_pixel, Color mask_pixel, int xHotSpot, int yHotSpot) + { + IntPtr cursor; + Bitmap cursor_bitmap; + Bitmap cursor_mask; + Byte[] cursor_bits; + Byte[] mask_bits; + Color c_pixel; + Color m_pixel; + int width; + int height; + IntPtr cursor_pixmap; + IntPtr mask_pixmap; + XColor fg; + XColor bg; + bool and; + bool xor; + + Size cursor_size = CursorSize; + width = cursor_size.Width; + height = cursor_size.Height; + + // Win32 only allows creation cursors of a certain size + if ((bitmap.Width != width) || (bitmap.Width != height)) { + cursor_bitmap = new Bitmap (bitmap, new Size (width, height)); + cursor_mask = new Bitmap (mask, new Size (width, height)); + } else { + cursor_bitmap = bitmap; + cursor_mask = mask; + } + + width = cursor_bitmap.Width; + height = cursor_bitmap.Height; + + cursor_bits = new Byte [(width / 8) * height]; + mask_bits = new Byte [(width / 8) * height]; + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + c_pixel = cursor_bitmap.GetPixel (x, y); + m_pixel = cursor_mask.GetPixel (x, y); + + and = c_pixel == cursor_pixel; + xor = m_pixel == mask_pixel; + + if (!and && !xor) { + // Black + // cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8))); // The bit already is 0 + mask_bits [y * width / 8 + x / 8] |= (byte)(1 << (x % 8)); + } else if (and && !xor) { + // White + cursor_bits [y * width / 8 + x / 8] |= (byte)(1 << (x % 8)); + mask_bits [y * width / 8 + x / 8] |= (byte)(1 << (x % 8)); + #if notneeded + } else if (and && !xor) { + // Screen + } else if (and && xor) { + // Inverse Screen + + // X11 doesn't know the 'reverse screen' concept, so we'll treat them the same + // we want both to be 0 so nothing to be done + //cursor_bits[y * width / 8 + x / 8] &= (byte)~((1 << (x % 8))); + //mask_bits[y * width / 8 + x / 8] |= (byte)(01 << (x % 8)); + #endif + } + } + } + + cursor_pixmap = XCreatePixmapFromBitmapData (DisplayHandle, RootWindow, cursor_bits, width, height, (IntPtr)1, (IntPtr)0, 1); + mask_pixmap = XCreatePixmapFromBitmapData (DisplayHandle, RootWindow, mask_bits, width, height, (IntPtr)1, (IntPtr)0, 1); + fg = new XColor (); + bg = new XColor (); + + fg.pixel = XWhitePixel (DisplayHandle, ScreenNo); + fg.red = (ushort)65535; + fg.green = (ushort)65535; + fg.blue = (ushort)65535; + + bg.pixel = XBlackPixel (DisplayHandle, ScreenNo); + + cursor = XCreatePixmapCursor (DisplayHandle, cursor_pixmap, mask_pixmap, ref fg, ref bg, xHotSpot, yHotSpot); + + XFreePixmap (DisplayHandle, cursor_pixmap); + XFreePixmap (DisplayHandle, mask_pixmap); + + return cursor; + } + + internal override IntPtr DefineStdCursor (StdCursor id) + { + CursorFontShape shape; + IntPtr cursor; + + // FIXME - define missing shapes + + switch (id) { + case StdCursor.AppStarting: { + shape = CursorFontShape.XC_watch; + break; + } + + case StdCursor.Arrow: { + return IntPtr.Zero; + } + + case StdCursor.Cross: { + shape = CursorFontShape.XC_crosshair; + break; + } + + case StdCursor.Default: { + return IntPtr.Zero; + } + + case StdCursor.Hand: { + shape = CursorFontShape.XC_hand1; + break; + } + + case StdCursor.Help: { + shape = CursorFontShape.XC_question_arrow; + break; + } + + case StdCursor.HSplit: { + shape = CursorFontShape.XC_sb_v_double_arrow; + break; + } + + case StdCursor.IBeam: { + shape = CursorFontShape.XC_xterm; + break; + } + + case StdCursor.No: { + shape = CursorFontShape.XC_circle; + break; + } + + case StdCursor.NoMove2D: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.NoMoveHoriz: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.NoMoveVert: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.PanEast: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.PanNE: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.PanNorth: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.PanNW: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.PanSE: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.PanSouth: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.PanSW: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.PanWest: { + shape = CursorFontShape.XC_sizing; + break; + } + + case StdCursor.SizeAll: { + shape = CursorFontShape.XC_fleur; + break; + } + + case StdCursor.SizeNESW: { + shape = CursorFontShape.XC_top_right_corner; + break; + } + + case StdCursor.SizeNS: { + shape = CursorFontShape.XC_sb_v_double_arrow; + break; + } + + case StdCursor.SizeNWSE: { + shape = CursorFontShape.XC_top_left_corner; + break; + } + + case StdCursor.SizeWE: { + shape = CursorFontShape.XC_sb_h_double_arrow; + break; + } + + case StdCursor.UpArrow: { + shape = CursorFontShape.XC_center_ptr; + break; + } + + case StdCursor.VSplit: { + shape = CursorFontShape.XC_sb_h_double_arrow; + break; + } + + case StdCursor.WaitCursor: { + shape = CursorFontShape.XC_watch; + break; + } + + default: { + return IntPtr.Zero; + } + } + + lock (XlibLock) { + cursor = XCreateFontCursor (DisplayHandle, shape); + } + return cursor; + } + + internal override IntPtr DefWndProc (ref Message msg) + { + return IntPtr.Zero; + } + + internal override void DestroyCaret (IntPtr handle) + { + if (Caret.Hwnd == handle) { + if (Caret.Visible == 1) { + Caret.Timer.Stop (); + HideCaret (); + } + if (Caret.gc != IntPtr.Zero) { + XFreeGC (DisplayHandle, Caret.gc); + Caret.gc = IntPtr.Zero; + } + Caret.Hwnd = IntPtr.Zero; + Caret.Visible = 0; + Caret.On = false; + } + } + + internal override void DestroyCursor (IntPtr cursor) + { + lock (XlibLock) { + XFreeCursor (DisplayHandle, cursor); + } + } + + internal override void DestroyWindow (IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd == null) { + #if DriverDebug + Console.WriteLine("window {0:X} already destroyed", handle.ToInt32()); + #endif + return; + } + + #if DriverDebug + Console.WriteLine("Destroying window {0:X}", handle.ToInt32()); + #endif + + // Make sure if the caret is in the window, that we destroy the caret, too + if (Caret.Hwnd == hwnd.client_window) { + DestroyCaret (handle); + } + + // Mark our children as gone as well + DestroyChildWindow (ShiftUI.Widget.ShiftUI.WidgetNativeWindow.ShiftUI.WidgetFromHandle (handle)); + + // Send destroy message + SendMessage (handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero); + + lock (XlibLock) { + if (hwnd.client_window != IntPtr.Zero) { + gdk_window_destroy (gdk_window_lookup (hwnd.client_window)); + } + + if ((hwnd.whole_window != IntPtr.Zero) && (hwnd.whole_window != hwnd.client_window)) { + gdk_window_destroy (gdk_window_lookup (hwnd.whole_window)); + } + } + hwnd.Dispose (); + } + + internal override IntPtr DispatchMessage (ref MSG msg) + { + return NativeWindow.WndProc (msg.hwnd, msg.message, msg.wParam, msg.lParam); + } + + internal override void DrawReversibleRectangle (IntPtr handle, Rectangle rect, int line_width) + { + Hwnd hwnd; + XGCValues gc_values; + IntPtr gc; + + hwnd = Hwnd.ObjectFromHandle (handle); + + gc_values = new XGCValues (); + + gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors; + gc_values.line_width = line_width; + gc_values.foreground = XBlackPixel (DisplayHandle, ScreenNo); + + // This logic will give us true rubber bands: (libsx, SANE_XOR) + //mask = foreground ^ background; + //XSetForeground(DisplayHandle, gc, 0xffffffff); + //XSetBackground(DisplayHandle, gc, background); + //XSetFunction(DisplayHandle, gc, GXxor); + //XSetPlaneMask(DisplayHandle, gc, mask); + + + gc = XCreateGC (DisplayHandle, hwnd.client_window, GCFunction.GCSubwindowMode | GCFunction.GCLineWidth | GCFunction.GCForeground, ref gc_values); + uint foreground; + uint background; + + ShiftUI.Widget Widget; + Widget = ShiftUI.Widget.FromHandle (handle); + + XColor xcolor = new XColor (); + + xcolor.red = (ushort)(ShiftUI.Widget.ForeColor.R * 257); + xcolor.green = (ushort)(ShiftUI.Widget.ForeColor.G * 257); + xcolor.blue = (ushort)(ShiftUI.Widget.ForeColor.B * 257); + XAllocColor (DisplayHandle, DefaultColormap, ref xcolor); + foreground = (uint)xcolor.pixel.ToInt32 (); + + xcolor.red = (ushort)(ShiftUI.Widget.BackColor.R * 257); + xcolor.green = (ushort)(ShiftUI.Widget.BackColor.G * 257); + xcolor.blue = (ushort)(ShiftUI.Widget.BackColor.B * 257); + XAllocColor (DisplayHandle, DefaultColormap, ref xcolor); + background = (uint)xcolor.pixel.ToInt32 (); + + uint mask = foreground ^ background; + + XSetForeground (DisplayHandle, gc, 0xffffffff); + XSetBackground (DisplayHandle, gc, background); + XSetFunction (DisplayHandle, gc, GXFunction.GXxor); + XSetPlaneMask (DisplayHandle, gc, mask); + + if ((rect.Width > 0) && (rect.Height > 0)) { + XDrawRectangle (DisplayHandle, hwnd.client_window, gc, rect.Left, rect.Top, rect.Width, rect.Height); + } else { + if (rect.Width > 0) { + XDrawLine (DisplayHandle, hwnd.client_window, gc, rect.X, rect.Y, rect.Right, rect.Y); + } else { + XDrawLine (DisplayHandle, hwnd.client_window, gc, rect.X, rect.Y, rect.X, rect.Bottom); + } + } + XFreeGC (DisplayHandle, gc); + } + + internal override void DoEvents () + { + MSG msg = new MSG (); + + if (OverrideCursorHandle != IntPtr.Zero) { + OverrideCursorHandle = IntPtr.Zero; + } + + while (PeekMessage (ref msg, IntPtr.Zero, 0, 0, (uint)PeekMessageFlags.PM_REMOVE)) { + TranslateMessage (ref msg); + DispatchMessage (ref msg); + } + } + + internal override void EnableWindow (IntPtr handle, bool Enable) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + if (hwnd != null) { + hwnd.Enabled = Enable; + } + } + + internal override void EndLoop (Thread thread) + { + // This is where we one day will shut down the loop for the thread + } + + + internal override IntPtr GetActive () + { + Atom actual_atom; + int actual_format; + int nitems; + int bytes_after; + IntPtr prop = IntPtr.Zero; + IntPtr active = IntPtr.Zero; + + XGetWindowProperty (DisplayHandle, RootWindow, NetAtoms [(int)NA._NET_ACTIVE_WINDOW], 0, 1, false, Atom.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + if ((nitems > 0) && (prop != IntPtr.Zero)) { + active = (IntPtr)Marshal.ReadInt32 (prop); + XFree (prop); + } + + if (active != IntPtr.Zero) { + Hwnd hwnd; + + hwnd = Hwnd.GetObjectFromWindow (active); + if (hwnd != null) { + active = hwnd.Handle; + } else { + active = IntPtr.Zero; + } + } + return active; + } + + internal override void GetCursorInfo (IntPtr cursor, out int width, out int height, out int hotspot_x, out int hotspot_y) + { + throw new NotImplementedException (); + } + + internal override void GetDisplaySize (out Size size) + { + XWindowAttributes attributes=new XWindowAttributes (); + + lock (XlibLock) { + // FIXME - use _NET_WM messages instead? + XGetWindowAttributes (DisplayHandle, XRootWindow (DisplayHandle, ScreenNo), ref attributes); + } + + size = new Size (attributes.width, attributes.height); + } + + internal override SizeF GetAutoScaleSize (Font font) + { + Graphics g; + float width; + string magic_string = "The quick brown fox jumped over the lazy dog."; + double magic_number = 44.549996948242189; + + g = Graphics.FromHwnd (FosterParent); + + width = (float) (g.MeasureString (magic_string, font).Width / magic_number); + return new SizeF (width, font.Height); + } + + internal override IntPtr GetParent (IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + if (hwnd != null && hwnd.parent != null) { + return hwnd.parent.Handle; + } + return IntPtr.Zero; + } + + internal override void GetCursorPos (IntPtr handle, out int x, out int y) + { + IntPtr use_handle; + IntPtr root; + IntPtr child; + int root_x; + int root_y; + int win_x; + int win_y; + int keys_buttons; + + if (handle != IntPtr.Zero) { + use_handle = Hwnd.ObjectFromHandle (handle).client_window; + } else { + use_handle = RootWindow; + } + + lock (XlibLock) { + XQueryPointer (DisplayHandle, use_handle, out root, out child, out root_x, out root_y, out win_x, out win_y, out keys_buttons); + } + + if (handle != IntPtr.Zero) { + x = win_x; + y = win_y; + } else { + x = root_x; + y = root_y; + } + } + + internal override bool GetFontMetrics (Graphics g, Font font, out int ascent, out int descent) + { + return GetFontMetrics (g.GetHdc (), font.ToHfont (), out ascent, out descent); + } + + internal override Point GetMenuOrigin (IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd != null) { + return hwnd.MenuOrigin; + } + return Point.Empty; + } + + internal bool GetMessage (ref MSG msg, IntPtr handle, int wFilterMin, int wFilterMax) + { + XEvent xevent; + bool client; + Hwnd hwnd; + + ProcessNextMessage: + + if (MessageQueue.Count > 0) { + xevent = (XEvent) MessageQueue.Dequeue (); + } else { + UpdateMessageQueue (); + + if (MessageQueue.Count > 0) { + xevent = (XEvent) MessageQueue.Dequeue (); + } else { + if (!PostQuitState) { + msg.hwnd = IntPtr.Zero; + msg.message = Msg.WM_ENTERIDLE; + return true; + } + + // We reset ourselves so GetMessage can be called again + PostQuitState = false; + + return false; + } + } + + // FIXME - handle filtering + + hwnd = Hwnd.GetObjectFromWindow (xevent.AnyEvent.window); + + // Handle messages for windows that are already or are about to be destroyed + if (hwnd == null) { + #if DriverDebug + Console.WriteLine("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}", xevent.type, xevent.AnyEvent.window.ToInt32()); + #endif + goto ProcessNextMessage; + } + + if (hwnd.client_window == xevent.AnyEvent.window) { + client = true; + //Console.WriteLine("Client message, sending to window {0:X}", msg.hwnd.ToInt32()); + } else { + client = false; + //Console.WriteLine("Non-Client message, sending to window {0:X}", msg.hwnd.ToInt32()); + } + + msg.hwnd = hwnd.Handle; + + // + // If you add a new event to this switch make sure to add it in + // UpdateMessage also unless it is not coming through the X event system. + // + switch (xevent.type) { + case XEventName.KeyPress: { + Keyboard.KeyEvent (FocusWindow, xevent, ref msg); + break; + } + + case XEventName.KeyRelease: { + Keyboard.KeyEvent (FocusWindow, xevent, ref msg); + break; + } + + case XEventName.ButtonPress: { + switch (xevent.ButtonEvent.button) { + case 1: { + MouseState |= MouseButtons.Left; + if (client) { + msg.message = Msg.WM_LBUTTONDOWN; + } else { + msg.message = Msg.WM_NCLBUTTONDOWN; + WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + // TODO: For WM_NCLBUTTONDOWN wParam specifies a hit-test value not the virtual keys down + msg.wParam = GetMousewParam (0); + break; + } + + case 2: { + MouseState |= MouseButtons.Middle; + if (client) { + msg.message = Msg.WM_MBUTTONDOWN; + } else { + msg.message = Msg.WM_NCMBUTTONDOWN; + WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + msg.wParam = GetMousewParam (0); + break; + } + + case 3: { + MouseState |= MouseButtons.Right; + if (client) { + msg.message = Msg.WM_RBUTTONDOWN; + } else { + msg.message = Msg.WM_NCRBUTTONDOWN; + WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + msg.wParam = GetMousewParam (0); + break; + } + + case 4: { + msg.message = Msg.WM_MOUSEWHEEL; + msg.wParam = GetMousewParam (120); + break; + } + + case 5: { + msg.message = Msg.WM_MOUSEWHEEL; + msg.wParam = GetMousewParam (-120); + break; + } + + } + + msg.lParam = (IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x); + MousePosition.X = xevent.ButtonEvent.x; + MousePosition.Y = xevent.ButtonEvent.y; + + if (!hwnd.Enabled) { + IntPtr dummy; + + msg.hwnd = hwnd.EnabledHwnd; + XTranslateCoordinates (DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle (msg.hwnd).ClientWindow, xevent.ButtonEvent.x, xevent.ButtonEvent.y, out xevent.ButtonEvent.x, out xevent.ButtonEvent.y, out dummy); + msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X); + } + + if (Grab.Hwnd != IntPtr.Zero) { + msg.hwnd = Grab.Hwnd; + } + + if (!ClickPending.Pending) { + ClickPending.Pending = true; + ClickPending.Hwnd = msg.hwnd; + ClickPending.Message = msg.message; + ClickPending.wParam = msg.wParam; + ClickPending.lParam = msg.lParam; + ClickPending.Time = (long)xevent.ButtonEvent.time; + } else { + if ((((long)xevent.ButtonEvent.time - ClickPending.Time) < DoubleClickInterval) && (msg.wParam == ClickPending.wParam) && (msg.lParam == ClickPending.lParam) && (msg.message == ClickPending.Message)) { + // Looks like a genuine double click, clicked twice on the same spot with the same keys + switch (xevent.ButtonEvent.button) { + case 1: { + msg.message = client ? Msg.WM_LBUTTONDBLCLK : Msg.WM_NCLBUTTONDBLCLK; + break; + } + + case 2: { + msg.message = client ? Msg.WM_MBUTTONDBLCLK : Msg.WM_NCMBUTTONDBLCLK; + break; + } + + case 3: { + msg.message = client ? Msg.WM_RBUTTONDBLCLK : Msg.WM_NCRBUTTONDBLCLK; + break; + } + } + } + ClickPending.Pending = false; + } + + break; + } + + case XEventName.ButtonRelease: { + Dnd.HandleButtonRelease (ref xevent); + switch (xevent.ButtonEvent.button) { + case 1: { + if (client) { + msg.message = Msg.WM_LBUTTONUP; + } else { + msg.message = Msg.WM_NCLBUTTONUP; + WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + msg.wParam = GetMousewParam (0); + MouseState &= ~MouseButtons.Left; + break; + } + + case 2: { + if (client) { + msg.message = Msg.WM_MBUTTONUP; + } else { + msg.message = Msg.WM_NCMBUTTONUP; + WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + msg.wParam = GetMousewParam (0); + MouseState &= ~MouseButtons.Middle; + break; + } + + case 3: { + if (client) { + msg.message = Msg.WM_RBUTTONUP; + } else { + msg.message = Msg.WM_NCRBUTTONUP; + WholeToScreen (msg.hwnd, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); + } + msg.wParam = GetMousewParam (0); + MouseState &= ~MouseButtons.Right; + break; + } + + case 4: { + goto ProcessNextMessage; + } + + case 5: { + goto ProcessNextMessage; + } + } + + if (!hwnd.Enabled) { + IntPtr dummy; + + msg.hwnd = hwnd.EnabledHwnd; + XTranslateCoordinates (DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle (msg.hwnd).ClientWindow, xevent.ButtonEvent.x, xevent.ButtonEvent.y, out xevent.ButtonEvent.x, out xevent.ButtonEvent.y, out dummy); + msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X); + } + + if (Grab.Hwnd != IntPtr.Zero) { + msg.hwnd = Grab.Hwnd; + } + + msg.lParam = (IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x); + MousePosition.X = xevent.ButtonEvent.x; + MousePosition.Y = xevent.ButtonEvent.y; + break; + } + + case XEventName.MotionNotify: { + if (client) { + #if DriverDebugExtra + Console.WriteLine("GetMessage(): Window {0:X} MotionNotify x={1} y={2}", client ? hwnd.client_window.ToInt32() : hwnd.whole_window.ToInt32(), xevent.MotionEvent.x, xevent.MotionEvent.y); + #endif + + if (Dnd.HandleMotionNotify (ref xevent)) + goto ProcessNextMessage; + if (Grab.Hwnd != IntPtr.Zero) { + msg.hwnd = Grab.Hwnd; + } else { + NativeWindow.WndProc (msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT); + } + + msg.message = Msg.WM_MOUSEMOVE; + msg.wParam = GetMousewParam (0); + msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF); + + if (!hwnd.Enabled) { + IntPtr dummy; + + msg.hwnd = hwnd.EnabledHwnd; + XTranslateCoordinates (DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle (msg.hwnd).ClientWindow, xevent.MotionEvent.x, xevent.MotionEvent.y, out xevent.MotionEvent.x, out xevent.MotionEvent.y, out dummy); + msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X); + } + + HoverState.X = MousePosition.X = xevent.MotionEvent.x; + HoverState.Y = MousePosition.Y = xevent.MotionEvent.y; + + break; + } else { + #if DriverDebugExtra + Console.WriteLine("GetMessage(): non-client area {0:X} MotionNotify x={1} y={2}", client ? hwnd.client_window.ToInt32() : hwnd.whole_window.ToInt32(), xevent.MotionEvent.x, xevent.MotionEvent.y); + #endif + msg.message = Msg.WM_NCMOUSEMOVE; + msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF); + + if (!hwnd.Enabled) { + IntPtr dummy; + + msg.hwnd = hwnd.EnabledHwnd; + XTranslateCoordinates (DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle (msg.hwnd).ClientWindow, xevent.MotionEvent.x, xevent.MotionEvent.y, out xevent.MotionEvent.x, out xevent.MotionEvent.y, out dummy); + msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X); + } + + #if notyet + // Not sure we need this... + HitTest ht; + ht = NativeWindow.WndProc(hwnd.client_window, Msg.WM_NCHITTEST, IntPtr.Zero, msg.lParam); + #endif + + MousePosition.X = xevent.MotionEvent.x; + MousePosition.Y = xevent.MotionEvent.y; + } + + break; + } + + case XEventName.EnterNotify: { + if (!hwnd.Enabled) { + goto ProcessNextMessage; + } + if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) { + goto ProcessNextMessage; + } + msg.message = Msg.WM_MOUSE_ENTER; + HoverState.Timer.Enabled = true; + HoverState.Window = xevent.CrossingEvent.window; + break; + } + + case XEventName.LeaveNotify: { + if (!hwnd.Enabled) { + goto ProcessNextMessage; + } + if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) { + goto ProcessNextMessage; + } + msg.message = Msg.WM_MOUSELEAVE; + HoverState.Timer.Enabled = false; + HoverState.Window = IntPtr.Zero; + break; + } + + #if later + case XEventName.CreateNotify: { + if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { + msg.message = WM_CREATE; + // Set up CreateStruct + } else { + goto ProcessNextMessage; + } + break; + } + #endif + + + case XEventName.ReparentNotify: { + if (hwnd.parent == null) { // Toplevel + if (xevent.ReparentEvent.parent != IntPtr.Zero) { + // We need to adjust x/y + int dummy_int; + + hwnd.Reparented = true; + + gdk_window_get_geometry (gdk_window_lookup (hwnd.whole_window), out hwnd.x, out hwnd.y, out dummy_int, out dummy_int, out dummy_int); + msg.message = Msg.WM_WINDOWPOSCHANGED; + if (hwnd.opacity != 0xffffffff) { + uint opacity; + + opacity = hwnd.opacity; + XChangeProperty (DisplayHandle, XGetParent (hwnd.whole_window), NetAtoms [(int)NA._NET_WM_WINDOW_OPACITY], Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1); + } + } else { + hwnd.Reparented = false; + goto ProcessNextMessage; + } + } + break; + } + + case XEventName.ConfigureNotify: { + if (!client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas + XplatUIWin32.NCCALCSIZE_PARAMS ncp; + IntPtr ptr; + Rectangle rect; + + #if DriverDebugExtra + Console.WriteLine("GetMessage(): Window {0:X} ConfigureNotify x={1} y={2} width={3} height={4}", hwnd.client_window.ToInt32(), xevent.ConfigureEvent.x, xevent.ConfigureEvent.y, xevent.ConfigureEvent.width, xevent.ConfigureEvent.height); + #endif + msg.message = Msg.WM_WINDOWPOSCHANGED; + hwnd.configure_pending = false; + + // We need to adjust our client window to track the resize of whole_window + rect = hwnd.DefaultClientRect; + + ncp = new XplatUIWin32.NCCALCSIZE_PARAMS (); + ptr = Marshal.AllocHGlobal (Marshal.SizeOf (ncp)); + + ncp.rgrc1.left = rect.Left; + ncp.rgrc1.top = rect.Top; + ncp.rgrc1.right = rect.Right; + ncp.rgrc1.bottom = rect.Bottom; + + Marshal.StructureToPtr (ncp, ptr, true); + NativeWindow.WndProc (hwnd.client_window, Msg.WM_NCCALCSIZE, (IntPtr)1, ptr); + ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure (ptr, typeof(XplatUIWin32.NCCALCSIZE_PARAMS)); + Marshal.FreeHGlobal (ptr); + + // FIXME - debug this with Menus, need to set hwnd.ClientRect + + rect = new Rectangle (ncp.rgrc1.left, ncp.rgrc1.top, ncp.rgrc1.right - ncp.rgrc1.left, ncp.rgrc1.bottom - ncp.rgrc1.top); + //Console.WriteLine("CreateOffscreenbuffer..."); +// CreateOffscreenBuffer (ref hwnd.client_offscreen, rect.Width, rect.Height); + + XMoveResizeWindow (DisplayHandle, hwnd.client_window, rect.X, rect.Y, rect.Width, rect.Height); + } else { + goto ProcessNextMessage; + } + + msg.lParam = IntPtr.Zero; // FIXME - Generate LPWINDOWPOS structure and pass on + break; + } + + case XEventName.FocusIn: { + if (!hwnd.Enabled) { + goto ProcessNextMessage; + } + msg.message = Msg.WM_SETFOCUS; + msg.wParam = IntPtr.Zero; + break; + } + + case XEventName.FocusOut: { + if (!hwnd.Enabled) { + goto ProcessNextMessage; + } + msg.message = Msg.WM_KILLFOCUS; + msg.wParam = IntPtr.Zero; + break; + } + + case XEventName.Expose: { + if (PostQuitState) { + goto ProcessNextMessage; + } + + + if (client) { + if (!hwnd.expose_pending) { + goto ProcessNextMessage; + } + } else { + if (!hwnd.nc_expose_pending) { + goto ProcessNextMessage; + } + + switch (hwnd.border_style) { + case FormBorderStyle.Fixed3D: { + Graphics g; + + g = Graphics.FromHwnd (hwnd.whole_window); + ShiftUI.WidgetPaint.DrawBorder3D (g, new Rectangle (0, 0, hwnd.Width, hwnd.Height)); + g.Dispose (); + break; + } + + case FormBorderStyle.FixedSingle: { + Graphics g; + + g = Graphics.FromHwnd (hwnd.whole_window); + ShiftUI.WidgetPaint.DrawBorder (g, new Rectangle (0, 0, hwnd.Width, hwnd.Height), Color.Black, ButtonBorderStyle.Solid); + g.Dispose (); + break; + } + } + #if DriverDebugExtra + Console.WriteLine("GetMessage(): Window {0:X} Exposed non-client area {1},{2} {3}x{4}", hwnd.client_window.ToInt32(), xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height); + #endif + + Rectangle rect = new Rectangle (xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height); + Region region = new Region (rect); + IntPtr hrgn = region.GetHrgn (null); // Graphics object isn't needed + msg.message = Msg.WM_NCPAINT; + msg.wParam = hrgn; + hwnd.nc_expose_pending = false; + break; + } + #if DriverDebugExtra + Console.WriteLine("GetMessage(): Window {0:X} Exposed area {1},{2} {3}x{4}", hwnd.client_window.ToInt32(), xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height); + #endif + if (Caret.Visible == 1) { + Caret.Paused = true; + HideCaret (); + } + + if (Caret.Visible == 1) { + ShowCaret (); + Caret.Paused = false; + } + msg.message = Msg.WM_PAINT; + break; + } + + case XEventName.DestroyNotify: { + + // This is a bit tricky, we don't receive our own DestroyNotify, we only get those for our children + hwnd = Hwnd.ObjectFromHandle (xevent.DestroyWindowEvent.window); + + // We may get multiple for the same window, act only one the first (when Hwnd still knows about it) + if (hwnd.client_window == xevent.DestroyWindowEvent.window) { + msg.hwnd = hwnd.client_window; + msg.message = Msg.WM_DESTROY; + hwnd.Dispose (); + + #if DriverDebug + Console.WriteLine("Got DestroyNotify on Window {0:X}", msg.hwnd.ToInt32()); + #endif + } else { + goto ProcessNextMessage; + } + + break; + } + + case XEventName.ClientMessage: { + if (Dnd.HandleClientMessage (ref xevent)) { + goto ProcessNextMessage; + } + + if (xevent.ClientMessageEvent.message_type == (IntPtr)AsyncAtom) { + XplatUIDriverSupport.ExecuteClientMessage ((GCHandle)xevent.ClientMessageEvent.ptr1); + break; + } + + if (xevent.ClientMessageEvent.message_type == (IntPtr)HoverState.Atom) { + msg.message = Msg.WM_MOUSEHOVER; + msg.wParam = GetMousewParam (0); + msg.lParam = (IntPtr) (xevent.ClientMessageEvent.ptr1); + break; + } + + if (xevent.ClientMessageEvent.message_type == (IntPtr)PostAtom) { + msg.hwnd = xevent.ClientMessageEvent.ptr1; + msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 (); + msg.wParam = xevent.ClientMessageEvent.ptr3; + msg.lParam = xevent.ClientMessageEvent.ptr4; + break; + } + + #if dontcare + if (xevent.ClientMessageEvent.message_type == (IntPtr)NetAtoms[(int)NA._XEMBED]) { + Console.WriteLine("GOT EMBED MESSAGE {0:X}", xevent.ClientMessageEvent.ptr2.ToInt32()); + break; + } + #endif + + if (xevent.ClientMessageEvent.message_type == (IntPtr)NetAtoms [(int)NA.WM_PROTOCOLS]) { + if (xevent.ClientMessageEvent.ptr1 == (IntPtr)NetAtoms [(int)NA.WM_DELETE_WINDOW]) { + msg.message = Msg.WM_CLOSE; + Graphics.FromHdcInternal (IntPtr.Zero); + break; + } + + // We should not get this, but I'll leave the code in case we need it in the future + if (xevent.ClientMessageEvent.ptr1 == (IntPtr)NetAtoms [(int)NA.WM_TAKE_FOCUS]) { + goto ProcessNextMessage; + } + } + break; + } + + case XEventName.TimerNotify: { + xevent.TimerNotifyEvent.handler (this, EventArgs.Empty); + break; + } + + default: { + goto ProcessNextMessage; + } + } + + return true; + } + + internal override bool GetText (IntPtr handle, out string text) + { + IntPtr textptr; + + textptr = IntPtr.Zero; + + lock (XlibLock) { + // FIXME - use _NET properties + XFetchName (DisplayHandle, Hwnd.ObjectFromHandle (handle).whole_window, ref textptr); + } + if (textptr != IntPtr.Zero) { + text = Marshal.PtrToStringAnsi (textptr); + XFree (textptr); + return true; + } else { + text = ""; + return false; + } + } + + internal override void GetWindowPos (IntPtr handle, bool is_toplevel, out int x, out int y, out int width, out int height, out int client_width, out int client_height) + { + Hwnd hwnd; + Rectangle rect; + + hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd != null) { + x = hwnd.x; + y = hwnd.y; + width = hwnd.width; + height = hwnd.height; + + rect = Hwnd.GetClientRectangle (hwnd.border_style, hwnd.menu, hwnd.title_style, hwnd.caption_height, hwnd.tool_caption_height, width, height); + + client_width = rect.Width; + client_height = rect.Height; + + return; + } + + // Should we throw an exception or fail silently? + // throw new ArgumentException("Called with an invalid window handle", "handle"); + + x = 0; + y = 0; + width = 0; + height = 0; + client_width = 0; + client_height = 0; + } + + internal override FormWindowState GetWindowState (IntPtr handle) + { + Atom actual_atom; + int actual_format; + int nitems; + int bytes_after; + IntPtr prop = IntPtr.Zero; + IntPtr atom; + int maximized; + bool minimized; + XWindowAttributes attributes; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + maximized = 0; + minimized = false; + XGetWindowProperty (DisplayHandle, hwnd.whole_window, NetAtoms [(int)NA._NET_WM_STATE], 0, 256, false, Atom.XA_ATOM, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + if ((nitems > 0) && (prop != IntPtr.Zero)) { + for (int i = 0; i < nitems; i++) { + atom = (IntPtr)Marshal.ReadInt32 (prop, i * 4); + if ((atom == (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_HORZ]) || (atom == (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_VERT])) { + maximized++; + } else if (atom == (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_HIDDEN]) { + minimized = true; + } + } + XFree (prop); + } + + if (minimized) { + return FormWindowState.Minimized; + } else if (maximized == 2) { + return FormWindowState.Maximized; + } + + attributes = new XWindowAttributes (); + XGetWindowAttributes (DisplayHandle, handle, ref attributes); + if (attributes.map_state == MapState.IsUnmapped) { + throw new NotSupportedException ("Cannot retrieve the state of an unmapped window"); + } + + + return FormWindowState.Normal; + } + + internal override void GrabInfo (out IntPtr handle, out bool GrabConfined, out Rectangle GrabArea) + { + handle = Grab.Hwnd; + GrabConfined = Grab.Confined; + GrabArea = Grab.Area; + } + + internal override void GrabWindow (IntPtr handle, IntPtr confine_to_handle) + { + Hwnd hwnd; + IntPtr confine_to_window; + + confine_to_window = IntPtr.Zero; + + if (confine_to_handle != IntPtr.Zero) { + XWindowAttributes attributes = new XWindowAttributes (); + + hwnd = Hwnd.ObjectFromHandle (confine_to_handle); + + lock (XlibLock) { + XGetWindowAttributes (DisplayHandle, hwnd.client_window, ref attributes); + } + Grab.Area.X = attributes.x; + Grab.Area.Y = attributes.y; + Grab.Area.Width = attributes.width; + Grab.Area.Height = attributes.height; + Grab.Confined = true; + confine_to_window = hwnd.client_window; + } + + Grab.Hwnd = handle; + + hwnd = Hwnd.ObjectFromHandle (handle); + + lock (XlibLock) { + XGrabPointer (DisplayHandle, hwnd.client_window, false, + EventMask.ButtonPressMask | EventMask.ButtonMotionMask | + EventMask.ButtonReleaseMask | EventMask.PointerMotionMask, + GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, 0, 0); + } + } + + internal override void UngrabWindow (IntPtr hwnd) + { + lock (XlibLock) { + XUngrabPointer (DisplayHandle, 0); + XFlush (DisplayHandle); + } + Grab.Hwnd = IntPtr.Zero; + Grab.Confined = false; + } + + internal override void HandleException (Exception e) + { + StackTrace st = new StackTrace (e, true); + Console.WriteLine ("Exception '{0}'", e.Message + st.ToString ()); + Console.WriteLine ("{0}{1}", e.Message, st.ToString ()); + } + + internal override void Invalidate (IntPtr handle, Rectangle rc, bool clear) + { + Hwnd hwnd; + XEvent xevent; + + hwnd = Hwnd.ObjectFromHandle (handle); + + + xevent = new XEvent (); + xevent.type = XEventName.Expose; + xevent.ExposeEvent.display = DisplayHandle; + xevent.ExposeEvent.window = hwnd.client_window; + + if (clear) { + xevent.ExposeEvent.x = hwnd.X; + xevent.ExposeEvent.y = hwnd.Y; + xevent.ExposeEvent.width = hwnd.Width; + xevent.ExposeEvent.height = hwnd.Height; + } else { + xevent.ExposeEvent.x = rc.X; + xevent.ExposeEvent.y = rc.Y; + xevent.ExposeEvent.width = rc.Width; + xevent.ExposeEvent.height = rc.Height; + } + + AddExpose (xevent); + } + + internal override bool IsEnabled (IntPtr handle) + { + return Hwnd.ObjectFromHandle (handle).Enabled; + } + + internal override bool IsVisible (IntPtr handle) + { + return Hwnd.ObjectFromHandle (handle).visible; + } + + internal override void KillTimer (Timer timer) + { + lock (TimerList) { + TimerList.Remove (timer); + } + } + + internal override void MenuToScreen (IntPtr handle, ref int x, ref int y) + { + int dest_x_return; + int dest_y_return; + IntPtr child; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + lock (XlibLock) { + XTranslateCoordinates (DisplayHandle, hwnd.whole_window, RootWindow, x, y, out dest_x_return, out dest_y_return, out child); + } + + x = dest_x_return; + y = dest_y_return; + } + + internal override void OverrideCursor (IntPtr cursor) + { + OverrideCursorHandle = cursor; + } + + internal PaintEventArgs PaintEventStart (IntPtr handle, bool client) + { + PaintEventArgs paint_event; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + if (Caret.Visible == 1) { + Caret.Paused = true; + HideCaret (); + } + + if (client) { + // handle backing store + IntPtr gdk_window = gdk_window_lookup (hwnd.client_window); + IntPtr gdk_pixmap = NewPixmap (gdk_window, hwnd.ClientRect.Width, hwnd.ClientRect.Height); + + backing_store [gdk_window] = gdk_pixmap; + + hwnd.client_dc = Graphics.FromHwnd (gdk_x11_drawable_get_xid (gdk_pixmap)); + hwnd.client_dc.SetClip (hwnd.invalid); + paint_event = new PaintEventArgs (hwnd.client_dc, hwnd.invalid); + hwnd.expose_pending = false; + + return paint_event; + } else { + hwnd.client_dc = Graphics.FromHwnd (hwnd.whole_window); + paint_event = new PaintEventArgs (hwnd.client_dc, new Rectangle (0, 0, hwnd.width, hwnd.height)); + hwnd.nc_expose_pending = false; + + return paint_event; + } + } + + internal void PaintEventEnd (IntPtr handle, bool client) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + hwnd.client_dc.Flush (); + + if (client) { + // clients are already drawn to a backing store pixmap + IntPtr gdk_window = gdk_window_lookup (hwnd.client_window); + IntPtr gdk_pixmap = (IntPtr)backing_store [gdk_window]; + + BlitOffscreenPixmap (gdk_pixmap, gdk_window, hwnd.Invalid); + + g_object_unref (gdk_pixmap); + backing_store.Remove (gdk_pixmap); + + hwnd.ClearInvalidArea (); + } + + hwnd.client_dc.Dispose (); + hwnd.client_dc = null; + + if (Caret.Visible == 1) { + ShowCaret (); + Caret.Paused = false; + } + } + + internal bool PeekMessage (ref MSG msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags) + { + bool pending; + + // FIXME - imlement filtering + + if ((flags & (uint)PeekMessageFlags.PM_REMOVE) == 0) { + throw new NotImplementedException ("PeekMessage PM_NOREMOVE is not implemented yet"); // FIXME - Implement PM_NOREMOVE flag + } + + pending = false; + if (MessageQueue.Count > 0) { + pending = true; + } else { + // Only call UpdateMessageQueue if real events are pending + // otherwise we go to sleep on the socket + if (XPending (DisplayHandle) != 0) { + UpdateMessageQueue (); + pending = true; + } + } + + CheckTimers (DateTime.Now); + + if (!pending) { + return false; + } + return GetMessage (ref msg, hWnd, wFilterMin, wFilterMax); + } + + // FIXME - I think this should just enqueue directly + internal override bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam) + { + XEvent xevent = new XEvent (); + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + xevent.type = XEventName.ClientMessage; + xevent.ClientMessageEvent.display = DisplayHandle; + + if (hwnd != null) { + xevent.ClientMessageEvent.window = hwnd.whole_window; + } else { + xevent.ClientMessageEvent.window = IntPtr.Zero; + } + + xevent.ClientMessageEvent.message_type = (IntPtr) PostAtom; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = handle; + xevent.ClientMessageEvent.ptr2 = (IntPtr) message; + xevent.ClientMessageEvent.ptr3 = wparam; + xevent.ClientMessageEvent.ptr4 = lparam; + + MessageQueue.Enqueue (xevent); + + return true; + } + + internal override void PostQuitMessage (int exitCode) + { + XFlush (DisplayHandle); + PostQuitState = true; + + // Remove our display handle from S.D + Graphics.FromHdcInternal (IntPtr.Zero); + } + + internal override void ScreenToClient (IntPtr handle, ref int x, ref int y) + { + int dest_x_return; + int dest_y_return; + IntPtr child; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + lock (XlibLock) { + XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.client_window, x, y, out dest_x_return, out dest_y_return, out child); + } + + x = dest_x_return; + y = dest_y_return; + } + + internal override void ScreenToMenu (IntPtr handle, ref int x, ref int y) + { + int dest_x_return; + int dest_y_return; + IntPtr child; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + lock (XlibLock) { + XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.whole_window, x, y, out dest_x_return, out dest_y_return, out child); + } + + x = dest_x_return; + y = dest_y_return; + } + + internal override void ScrollWindow (IntPtr handle, Rectangle area, int XAmount, int YAmount, bool with_children) + { + Hwnd hwnd; + IntPtr gc; + XGCValues gc_values; + + hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd.invalid != Rectangle.Empty) { + // BIG FAT WARNING. This only works with how we use this function right now + // where we basically still scroll the whole window, but work around areas + // that are covered by our children + + hwnd.invalid.X += XAmount; + hwnd.invalid.Y += YAmount; + + if (hwnd.invalid.X < 0) { + hwnd.invalid.Width += hwnd.invalid.X; + hwnd.invalid.X = 0; + } + + if (hwnd.invalid.Y < 0) { + hwnd.invalid.Height += hwnd.invalid.Y; + hwnd.invalid.Y = 0; + } + } + + gc_values = new XGCValues (); + + if (with_children) { + gc_values.subwindow_mode = GCSubwindowMode.IncludeInferiors; + } + + gc = XCreateGC (DisplayHandle, hwnd.client_window, 0, ref gc_values); + + XCopyArea (DisplayHandle, hwnd.client_window, hwnd.client_window, gc, area.X - XAmount, area.Y - YAmount, area.Width, area.Height, area.X, area.Y); + + // Generate an expose for the area exposed by the horizontal scroll + if (XAmount > 0) { + hwnd.AddInvalidArea (area.X, area.Y, XAmount, area.Height); + } else if (XAmount < 0) { + hwnd.AddInvalidArea (XAmount + area.X + area.Width, area.Y, -XAmount, area.Height); + } + + // Generate an expose for the area exposed by the vertical scroll + if (YAmount > 0) { + hwnd.AddInvalidArea (area.X, area.Y, area.Width, YAmount); + } else if (YAmount < 0) { + hwnd.AddInvalidArea (area.X, YAmount + area.Y + area.Height, area.Width, -YAmount); + } + XFreeGC (DisplayHandle, gc); + + UpdateWindow (handle); + } + + internal override void ScrollWindow (IntPtr handle, int XAmount, int YAmount, bool with_children) + { + Hwnd hwnd; + + hwnd = Hwnd.GetObjectFromWindow (handle); + + ScrollWindow (handle, hwnd.ClientRect, XAmount, YAmount, with_children); + } + + internal override void SendAsyncMethod (AsyncMethodData method) + { + XEvent xevent = new XEvent (); + + xevent.type = XEventName.ClientMessage; + xevent.ClientMessageEvent.display = DisplayHandle; + xevent.ClientMessageEvent.window = FosterParent; + xevent.ClientMessageEvent.message_type = (IntPtr)AsyncAtom; + xevent.ClientMessageEvent.format = 32; + xevent.ClientMessageEvent.ptr1 = (IntPtr) GCHandle.Alloc (method); + + MessageQueue.EnqueueLocked (xevent); + + WakeupMain (); + } + + internal override IntPtr SendMessage (IntPtr hwnd, Msg message, IntPtr wParam, IntPtr lParam) + { + return NativeWindow.WndProc (hwnd, message, wParam, lParam); + } + + internal override void SetAllowDrop (IntPtr handle, bool value) + { + // We allow drop on all windows + } + + internal override DragDropEffects StartDrag (IntPtr handle, object data, + DragDropEffects allowed_effects) + { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd == null) + throw new ArgumentException ("Attempt to begin drag from invalid window handle (" + handle.ToInt32 () + ")."); + + return Dnd.StartDrag (hwnd.client_window, data, allowed_effects); + } + + internal override void SetBorderStyle (IntPtr handle, FormBorderStyle border_style) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + hwnd.border_style = border_style; + + XMoveResizeWindow (DisplayHandle, hwnd.client_window, hwnd.ClientRect.X, hwnd.ClientRect.Y, hwnd.ClientRect.Width, hwnd.ClientRect.Height); + + InvalidateWholeWindow (handle); + } + + internal override void SetCaretPos (IntPtr handle, int x, int y) + { + if (Caret.Hwnd == handle) { + Caret.Timer.Stop (); + HideCaret (); + + Caret.X = x; + Caret.Y = y; + + if (Caret.Visible == 1) { + ShowCaret (); + Caret.Timer.Start (); + } + } + } + + internal override void SetCursor (IntPtr handle, IntPtr cursor) + { + Hwnd hwnd; + + if (OverrideCursorHandle == IntPtr.Zero) { + if ((LastCursorWindow == handle) && (LastCursorHandle == cursor)) { + return; + } + + LastCursorHandle = cursor; + LastCursorWindow = handle; + + hwnd = Hwnd.ObjectFromHandle (handle); + lock (XlibLock) { + if (cursor != IntPtr.Zero) { + XDefineCursor (DisplayHandle, hwnd.whole_window, cursor); + } else { + XUndefineCursor (DisplayHandle, hwnd.whole_window); + } + } + return; + } + + hwnd = Hwnd.ObjectFromHandle (handle); + lock (XlibLock) { + XDefineCursor (DisplayHandle, hwnd.whole_window, OverrideCursorHandle); + } + } + + internal override void SetCursorPos (IntPtr handle, int x, int y) + { + if (handle == IntPtr.Zero) { + lock (XlibLock) { + XWarpPointer (DisplayHandle, IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, x, y); + } + return; + } else { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + lock (XlibLock) { + XWarpPointer (DisplayHandle, IntPtr.Zero, hwnd.client_window, 0, 0, 0, 0, x, y); + } + return; + } + } + + internal override void SetFocus (IntPtr handle) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + if (FocusWindow != IntPtr.Zero) { + PostMessage (FocusWindow, Msg.WM_KILLFOCUS, hwnd.client_window, IntPtr.Zero); + } + PostMessage (hwnd.client_window, Msg.WM_SETFOCUS, FocusWindow, IntPtr.Zero); + FocusWindow = hwnd.client_window; + + //XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).client_window, RevertTo.None, IntPtr.Zero); + } + + internal override void SetIcon (IntPtr handle, Icon icon) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + if (hwnd != null) { + SetIcon (hwnd, icon); + } + } + + internal override void SetMenu (IntPtr handle, Menu menu) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + hwnd.menu = menu; + + // FIXME - do we need to trigger some resize? + } + + internal override void SetModal (IntPtr handle, bool Modal) + { + if (Modal) { + ModalWindows.Push (handle); + } else { + if (ModalWindows.Contains (handle)) { + ModalWindows.Pop (); + } + if (ModalWindows.Count > 0) { + Activate ((IntPtr)ModalWindows.Peek ()); + } + } + } + + internal override IntPtr SetParent (IntPtr handle, IntPtr parent) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + hwnd.parent = Hwnd.ObjectFromHandle (parent); + + lock (XlibLock) { + #if DriverDebug + Console.WriteLine("Parent for window {0:X} / {1:X} = {2:X} (Handle:{3:X})", hwnd.ClientWindow.ToInt32(), hwnd.WholeWindow.ToInt32(), hwnd.parent != null ? hwnd.parent.Handle.ToInt32() : 0, parent.ToInt32()); + #endif + XReparentWindow (DisplayHandle, hwnd.whole_window, hwnd.parent.client_window, hwnd.x, hwnd.y); + } + + return IntPtr.Zero; + } + + internal override void SetTimer (Timer timer) + { + lock (TimerList) { + TimerList.Add (timer); + } + WakeupMain (); + } + + internal bool SetTopmost (IntPtr handle, IntPtr handle_owner, bool enabled) + { + Hwnd hwnd; + Hwnd hwnd_owner; + + hwnd = Hwnd.ObjectFromHandle (handle); + + if (handle_owner != IntPtr.Zero) { + hwnd_owner = Hwnd.ObjectFromHandle (handle_owner); + } else { + hwnd_owner = null; + } + + if (enabled) { + lock (XlibLock) { + if (hwnd_owner != null) { + XSetTransientForHint (DisplayHandle, hwnd.whole_window, hwnd_owner.whole_window); + } else { + XSetTransientForHint (DisplayHandle, hwnd.whole_window, FosterParent); + } + } + } else { + lock (XlibLock) { + XDeleteProperty (DisplayHandle, hwnd.whole_window, (int)Atom.XA_WM_TRANSIENT_FOR); + } + } + return true; + } + + internal bool SetVisible (IntPtr handle, bool visible) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + hwnd.visible = visible; + + lock (XlibLock) { + if (visible) { + if (ShiftUI.Widget.FromHandle (handle) is Form) { + FormWindowState s; + + s = ((Form)ShiftUI.Widget.FromHandle (handle)).WindowState; + + XMapWindow (DisplayHandle, hwnd.whole_window); + XMapWindow (DisplayHandle, hwnd.client_window); + + switch (s) { + case FormWindowState.Minimized: SetWindowState (handle, FormWindowState.Minimized); break; + case FormWindowState.Maximized: SetWindowState (handle, FormWindowState.Maximized); break; + } + } else { + XMapWindow (DisplayHandle, hwnd.whole_window); + XMapWindow (DisplayHandle, hwnd.client_window); + } + } else { + XUnmapWindow (DisplayHandle, hwnd.whole_window); + } + } + return true; + } + + internal override void SetWindowMinMax (IntPtr handle, Rectangle maximized, Size min, Size max) + { + Hwnd hwnd; + XSizeHints hints; + + hwnd = Hwnd.ObjectFromHandle (handle); + if (hwnd == null) { + return; + } + + hints = new XSizeHints (); + + if (min != Size.Empty) { + hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize); + hints.min_width = min.Width; + hints.min_height = min.Height; + } + + if (max != Size.Empty) { + hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize); + hints.max_width = max.Width; + hints.max_height = max.Height; + } + + XSetWMNormalHints (DisplayHandle, hwnd.whole_window, ref hints); + + if (maximized != Rectangle.Empty) { + hints.flags = (IntPtr)XSizeHintsFlags.PPosition; + hints.x = maximized.X; + hints.y = maximized.Y; + hints.width = maximized.Width; + hints.height = maximized.Height; + + // Metacity does not seem to follow this constraint for maximized (zoomed) windows + XSetZoomHints (DisplayHandle, hwnd.whole_window, ref hints); + } + } + + + internal override void SetWindowPos (IntPtr handle, int x, int y, int width, int height) + { + Hwnd hwnd; + Rectangle client_rect; + + hwnd = Hwnd.ObjectFromHandle (handle); + + // X requires a sanity check for width & height; otherwise it dies + if (hwnd.zero_sized && width > 0 && height > 0) { + if (hwnd.visible) { + XMapWindow (DisplayHandle, hwnd.whole_window); + } + hwnd.zero_sized = false; + } + + if (width < 1) { + hwnd.zero_sized = true; + XUnmapWindow (DisplayHandle, hwnd.whole_window); + } + + if (height < 1) { + hwnd.zero_sized = true; + XUnmapWindow (DisplayHandle, hwnd.whole_window); + } + + client_rect = Hwnd.GetClientRectangle (hwnd.border_style, hwnd.menu, hwnd.title_style, hwnd.caption_height, hwnd.tool_caption_height, width, height); + + // Save a server roundtrip (and prevent a feedback loop) + if ((hwnd.x == x) && (hwnd.y == y) && + (hwnd.width == width) && (hwnd.height == height) && + (hwnd.ClientRect == client_rect)) { + return; + } + + if (!hwnd.zero_sized) { + lock (XlibLock) { + XMoveResizeWindow (DisplayHandle, hwnd.whole_window, x, y, width, height); + XMoveResizeWindow (DisplayHandle, hwnd.client_window, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height); + } + } + + // Prevent an old queued ConfigureNotify from setting our width with outdated data, set it now + hwnd.width = width; + hwnd.height = height; + } + + internal override void SetWindowState (IntPtr handle, FormWindowState state) + { + FormWindowState current_state; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + current_state = GetWindowState (handle); + + if (current_state == state) { + return; + } + + switch (state) { + case FormWindowState.Normal: { + lock (XlibLock) { + if (current_state == FormWindowState.Minimized) { + XMapWindow (DisplayHandle, hwnd.whole_window); + XMapWindow (DisplayHandle, hwnd.client_window); + } else if (current_state == FormWindowState.Maximized) { + SendNetWMMessage (hwnd.whole_window, (IntPtr)(uint)NetAtoms [(int)NA._NET_WM_STATE], (IntPtr)2 /* toggle */, (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_HORZ], (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_VERT]); + } + } + Activate (handle); + return; + } + + case FormWindowState.Minimized: { + lock (XlibLock) { + if (current_state == FormWindowState.Maximized) { + SendNetWMMessage (hwnd.whole_window, (IntPtr)NetAtoms [(int)NA._NET_WM_STATE], (IntPtr)2 /* toggle */, (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_HORZ], (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_VERT]); + } + XIconifyWindow (DisplayHandle, hwnd.whole_window, ScreenNo); + } + return; + } + + case FormWindowState.Maximized: { + lock (XlibLock) { + if (current_state == FormWindowState.Minimized) { + XMapWindow (DisplayHandle, hwnd.whole_window); + XMapWindow (DisplayHandle, hwnd.client_window); + } + + SendNetWMMessage (hwnd.whole_window, (IntPtr)NetAtoms [(int)NA._NET_WM_STATE], (IntPtr)1 /* Add */, (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_HORZ], (IntPtr)NetAtoms [(int)NA._NET_WM_STATE_MAXIMIZED_VERT]); + } + Activate (handle); + return; + } + } + } + + internal override void SetWindowStyle (IntPtr handle, CreateParams cp) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + SetHwndStyles (hwnd, cp); + SetWMStyles (hwnd, cp); + } + + internal override void SetWindowTransparency (IntPtr handle, double transparency, Color key) + { + Hwnd hwnd; + uint opacity; + + hwnd = Hwnd.ObjectFromHandle (handle); + + if (hwnd == null) { + return; + } + + hwnd.opacity = (uint)(0xffffffff * transparency); + opacity = hwnd.opacity; + + if (hwnd.reparented) { + XChangeProperty (DisplayHandle, XGetParent (hwnd.whole_window), NetAtoms [(int)NA._NET_WM_WINDOW_OPACITY], Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1); + } + } + + internal override bool SetZOrder (IntPtr handle, IntPtr after_handle, bool top, bool bottom) + { + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + + if (top) { + lock (XlibLock) { + XRaiseWindow (DisplayHandle, hwnd.whole_window); + } + return true; + } else if (!bottom) { + Hwnd after_hwnd = null; + + if (after_handle != IntPtr.Zero) { + after_hwnd = Hwnd.ObjectFromHandle (after_handle); + } + + XWindowChanges values = new XWindowChanges (); + + if (after_hwnd == null) { + throw new ArgumentNullException ("after_handle", "Need sibling to adjust z-order"); + } + values.sibling = after_hwnd.whole_window; + values.stack_mode = StackMode.Below; + + lock (XlibLock) { + XConfigureWindow (DisplayHandle, hwnd.whole_window, ChangeWindowFlags.CWStackMode | ChangeWindowFlags.CWSibling, ref values); + } + } else { + // Bottom + lock (XlibLock) { + XLowerWindow (DisplayHandle, hwnd.whole_window); + } + return true; + } + return false; + } + + internal override void ShowCursor (bool show) + { + ; // FIXME - X11 doesn't 'hide' the cursor. we could create an empty cursor + } + + internal override object StartLoop (Thread thread) + { + // Future place for prepping a new queue for this specific thread + return thread; + } + + internal override TransparencySupport SupportsTransparency () + { + // We need to check if the x compositing manager is running + return TransparencySupport.Get; + } + + internal override bool SystrayAdd (IntPtr handle, string tip, Icon icon, out ToolTip tt) + { + GetSystrayManagerWindow (); + + if (SystrayMgrWindow != IntPtr.Zero) { + uint[] atoms; + XSizeHints size_hints; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + #if DriverDebug + Console.WriteLine("Adding Systray Whole:{0:X}, Client:{1:X}", hwnd.whole_window.ToInt32(), hwnd.client_window.ToInt32()); + #endif + + XUnmapWindow (DisplayHandle, hwnd.whole_window); + XUnmapWindow (DisplayHandle, hwnd.client_window); + + // Oh boy. + gdk_window_destroy (gdk_window_lookup (hwnd.client_window)); + hwnd.client_window = hwnd.whole_window; + + size_hints = new XSizeHints (); + + size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize); + size_hints.min_width = icon.Width; + size_hints.min_height = icon.Height; + + size_hints.max_width = icon.Width; + size_hints.max_height = icon.Height; + + size_hints.base_width = icon.Width; + size_hints.base_height = icon.Height; + XSetWMNormalHints (DisplayHandle, hwnd.whole_window, ref size_hints); + + atoms = new uint [2]; + atoms [0] = 1; // Version 1 + atoms [1] = 0; // We're not mapped + + // This line cost me 3 days... + XChangeProperty (DisplayHandle, hwnd.whole_window, NetAtoms [(int)NA._XEMBED_INFO], NetAtoms [(int)NA._XEMBED_INFO], 32, PropertyMode.Replace, atoms, 2); + + // Need to pick some reasonable defaults + tt = new ToolTip (); + tt.AutomaticDelay = 100; + tt.InitialDelay = 250; + tt.ReshowDelay = 250; + tt.ShowAlways = true; + + if ((tip != null) && (tip != string.Empty)) { + tt.SetToolTip (ShiftUI.Widget.FromHandle (handle), tip); + tt.Active = true; + } else { + tt.Active = false; + } + + // Make sure the window exists + XSync (DisplayHandle, hwnd.whole_window); + + SendNetClientMessage (SystrayMgrWindow, (IntPtr)NetAtoms [(int)NA._NET_SYSTEM_TRAY_OPCODE], IntPtr.Zero, (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK, hwnd.whole_window); + return true; + } + + tt = null; + return false; + } + + internal override bool SystrayChange (IntPtr handle, string tip, Icon icon, ref ToolTip tt) + { + ShiftUI.Widget Widget; + + Widget = ShiftUI.Widget.FromHandle (handle); + if (Widget != null && tt != null) { + tt.SetToolTip (Widget, tip); + tt.Active = true; + return true; + } else { + return false; + } + } + + internal override void SystrayRemove (IntPtr handle, ref ToolTip tt) + { + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + XUnmapWindow (DisplayHandle, hwnd.whole_window); + SetParent (hwnd.whole_window, FosterParent); + + // The caller can now re-dock it later... + if (tt != null) { + tt.Dispose (); + tt = null; + } + } + + internal override bool Text (IntPtr handle, string text) + { + lock (XlibLock) { + gdk_window_set_title (gdk_window_lookup (Hwnd.ObjectFromHandle (handle).whole_window), text); + } + return true; + } + + internal override bool TranslateMessage (ref MSG msg) + { + return Keyboard.TranslateMessage (ref msg); + } + + internal override void UpdateWindow (IntPtr handle) + { + XEvent xevent; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle (handle); + + if (!hwnd.visible || hwnd.expose_pending) { + return; + } + + #if not + SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero); + #else + xevent = new XEvent (); + xevent.type = XEventName.Expose; + xevent.ExposeEvent.display = DisplayHandle; + xevent.ExposeEvent.window = hwnd.client_window; + + MessageQueue.Enqueue (xevent); + hwnd.expose_pending = true; + #endif + } + + internal static IntPtr NewPixmap (IntPtr gdk_window, int width, int height) + { + return gdk_pixmap_new (gdk_window, width, height, 24); // FIXME: instead of 24, get the correct display depth + } + + internal static void BlitOffscreenPixmap (IntPtr gdk_pixmap, IntPtr dest_drawable, Rectangle area) + { + IntPtr gdk_gc = gdk_gc_new (gdk_pixmap); + + gdk_draw_drawable (dest_drawable, gdk_gc, gdk_pixmap, area.X, area.Y, area.X, area.Y, area.Width, area.Height); + + g_object_unref (gdk_gc); + } + #endregion // Public Static Methods + + #region Events + internal override event EventHandler Idle; + #endregion // Events + + #region X11 Imports + [DllImport ("libX11", EntryPoint="XSynchronize")] + internal extern static IntPtr XSynchronize (IntPtr display, bool onoff); + + [DllImport ("libX11", EntryPoint="XCreateWindow")] + internal extern static IntPtr XCreateWindow (IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, int depth, int xclass, IntPtr visual, SetWindowValuemask valuemask, ref XSetWindowAttributes attributes); + [DllImport ("libX11", EntryPoint="XCreateSimpleWindow")] + internal extern static IntPtr XCreateSimpleWindow (IntPtr display, IntPtr parent, int x, int y, int width, int height, int border_width, int border, int background); + [DllImport ("libX11", EntryPoint="XMapWindow")] + internal extern static int XMapWindow (IntPtr display, IntPtr window); + [DllImport ("libX11", EntryPoint="XUnmapWindow")] + internal extern static int XUnmapWindow (IntPtr display, IntPtr window); + [DllImport ("libX11", EntryPoint="XMapSubwindows")] + internal extern static int XMapSubindows (IntPtr display, IntPtr window); + [DllImport ("libX11", EntryPoint="XUnmapSubwindows")] + internal extern static int XUnmapSubwindows (IntPtr display, IntPtr window); + [DllImport ("libX11", EntryPoint="XRootWindow")] + internal extern static IntPtr XRootWindow (IntPtr display, int screen_number); + [DllImport ("libX11", EntryPoint="XNextEvent")] + internal extern static IntPtr XNextEvent (IntPtr display, ref XEvent xevent); + [DllImport ("libX11")] + internal extern static int XConnectionNumber (IntPtr diplay); + [DllImport ("libX11")] + internal extern static int XPending (IntPtr diplay); + [DllImport ("libX11")] + internal extern static bool XCheckWindowEvent (IntPtr display, IntPtr window, EventMask mask, ref XEvent xevent); + [DllImport ("libX11")] + internal extern static bool XCheckMaskEvent (IntPtr display, EventMask mask, ref XEvent xevent); + [DllImport ("libX11", EntryPoint="XSelectInput")] + internal extern static IntPtr XSelectInput (IntPtr display, IntPtr window, EventMask mask); + + [DllImport ("libX11", EntryPoint="XReparentWindow")] + internal extern static int XReparentWindow (IntPtr display, IntPtr window, IntPtr parent, int x, int y); + [DllImport ("libX11", EntryPoint="XMoveResizeWindow")] + internal extern static int XMoveResizeWindow (IntPtr display, IntPtr window, int x, int y, int width, int height); + + [DllImport ("libX11", EntryPoint="XResizeWindow")] + internal extern static int XResizeWindow (IntPtr display, IntPtr window, int width, int height); + + [DllImport ("libX11", EntryPoint="XGetWindowAttributes")] + internal extern static int XGetWindowAttributes (IntPtr display, IntPtr window, ref XWindowAttributes attributes); + + [DllImport ("libX11", EntryPoint="XFlush")] + internal extern static int XFlush (IntPtr display); + + [DllImport ("libX11", EntryPoint="XSetWMName")] + internal extern static int XSetWMName (IntPtr display, IntPtr window, ref XTextProperty text_prop); + + [DllImport ("libX11", EntryPoint="XStoreName")] + internal extern static int XStoreName (IntPtr display, IntPtr window, string window_name); + + [DllImport ("libX11", EntryPoint="XFetchName")] + internal extern static int XFetchName (IntPtr display, IntPtr window, ref IntPtr window_name); + + [DllImport ("libX11", EntryPoint="XSendEvent")] + internal extern static int XSendEvent (IntPtr display, IntPtr window, bool propagate, EventMask event_mask, ref XEvent send_event); + + [DllImport ("libX11", EntryPoint="XQueryTree")] + internal extern static int XQueryTree (IntPtr display, IntPtr window, out IntPtr root_return, out IntPtr parent_return, out IntPtr children_return, out int nchildren_return); + + [DllImport ("libX11", EntryPoint="XFree")] + internal extern static int XFree (IntPtr data); + + [DllImport ("libX11", EntryPoint="XRaiseWindow")] + internal extern static int XRaiseWindow (IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XLowerWindow")] + internal extern static uint XLowerWindow (IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XConfigureWindow")] + internal extern static uint XConfigureWindow (IntPtr display, IntPtr window, ChangeWindowFlags value_mask, ref XWindowChanges values); + + [DllImport ("libX11", EntryPoint="XInternAtom")] + internal extern static int XInternAtom (IntPtr display, string atom_name, bool only_if_exists); + + [DllImport ("libX11", EntryPoint="XSetWMProtocols")] + internal extern static int XSetWMProtocols (IntPtr display, IntPtr window, uint[] protocols, int count); + + [DllImport ("libX11", EntryPoint="XGrabPointer")] + internal extern static int XGrabPointer (IntPtr display, IntPtr window, bool owner_events, EventMask event_mask, GrabMode pointer_mode, GrabMode keyboard_mode, IntPtr confine_to, uint cursor, uint timestamp); + + [DllImport ("libX11", EntryPoint="XUngrabPointer")] + internal extern static int XUngrabPointer (IntPtr display, uint timestamp); + + [DllImport ("libX11", EntryPoint="XQueryPointer")] + internal extern static bool XQueryPointer (IntPtr display, IntPtr window, out IntPtr root, out IntPtr child, out int root_x, out int root_y, out int win_x, out int win_y, out int keys_buttons); + + [DllImport ("libX11", EntryPoint="XTranslateCoordinates")] + internal extern static bool XTranslateCoordinates (IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, out int intdest_x_return, out int dest_y_return, out IntPtr child_return); + + [DllImport ("libX11", EntryPoint="XWarpPointer")] + internal extern static uint XWarpPointer (IntPtr display, IntPtr src_w, IntPtr dest_w, int src_x, int src_y, uint src_width, uint src_height, int dest_x, int dest_y); + + [DllImport ("libX11", EntryPoint="XClearWindow")] + internal extern static int XClearWindow (IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XClearArea")] + internal extern static int XClearArea (IntPtr display, IntPtr window, int x, int y, int width, int height, bool exposures); + + // Colormaps + [DllImport ("libX11", EntryPoint="XDefaultScreenOfDisplay")] + internal extern static IntPtr XDefaultScreenOfDisplay (IntPtr display); + + [DllImport ("libX11", EntryPoint="XScreenNumberOfScreen")] + internal extern static int XScreenNumberOfScreen (IntPtr display, IntPtr Screen); + + [DllImport ("libX11", EntryPoint="XDefaultVisual")] + internal extern static IntPtr XDefaultVisual (IntPtr display, int screen_number); + + [DllImport ("libX11", EntryPoint="XDefaultDepth")] + internal extern static uint XDefaultDepth (IntPtr display, int screen_number); + + [DllImport ("libX11", EntryPoint="XDefaultColormap")] + internal extern static IntPtr XDefaultColormap (IntPtr display, int screen_number); + + [DllImport ("libX11", EntryPoint="XLookupColor")] + internal extern static int XLookupColor (IntPtr display, IntPtr Colormap, string Coloranem, ref XColor exact_def_color, ref XColor screen_def_color); + + [DllImport ("libX11", EntryPoint="XAllocColor")] + internal extern static int XAllocColor (IntPtr display, IntPtr Colormap, ref XColor colorcell_def); + + [DllImport ("libX11", EntryPoint="XSetTransientForHint")] + internal extern static int XSetTransientForHint (IntPtr display, IntPtr window, IntPtr prop_window); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty (IntPtr display, IntPtr window, int property, int type, int format, PropertyMode mode, ref MotifWmHints data, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty (IntPtr display, IntPtr window, int property, Atom format, int type, PropertyMode mode, uint[] atoms, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty (IntPtr display, IntPtr window, int property, Atom format, int type, PropertyMode mode, ref uint value, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty (IntPtr display, IntPtr window, int property, int format, int type, PropertyMode mode, uint[] atoms, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty (IntPtr display, IntPtr window, int property, int format, int type, PropertyMode mode, IntPtr atoms, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty")] + internal extern static int XChangeProperty (IntPtr display, IntPtr window, int property, Atom format, int type, PropertyMode mode, IntPtr atoms, int nelements); + + [DllImport ("libX11", EntryPoint="XChangeProperty", CharSet=CharSet.Ansi)] + internal extern static int XChangeProperty (IntPtr display, IntPtr window, int property, int type, int format, PropertyMode mode, string text, int text_length); + + [DllImport ("libX11", EntryPoint="XDeleteProperty")] + internal extern static int XDeleteProperty (IntPtr display, IntPtr window, int property); + + // Drawing + [DllImport ("libX11", EntryPoint="XCreateGC")] + internal extern static IntPtr XCreateGC (IntPtr display, IntPtr window, GCFunction valuemask, ref XGCValues values); + + [DllImport ("libX11", EntryPoint="XFreeGC")] + internal extern static int XFreeGC (IntPtr display, IntPtr gc); + + [DllImport ("libX11", EntryPoint="XSetFunction")] + internal extern static int XSetFunction (IntPtr display, IntPtr gc, GXFunction function); + + [DllImport ("libX11", EntryPoint="XDrawLine")] + internal extern static int XDrawLine (IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int x2, int y2); + + [DllImport ("libX11", EntryPoint="XDrawRectangle")] + internal extern static int XDrawRectangle (IntPtr display, IntPtr drawable, IntPtr gc, int x1, int y1, int width, int height); + + [DllImport ("libX11", EntryPoint="XSetWindowBackground")] + internal extern static int XSetWindowBackground (IntPtr display, IntPtr window, IntPtr background); + + [DllImport ("libX11", EntryPoint="XCopyArea")] + internal extern static int XCopyArea (IntPtr display, IntPtr src, IntPtr dest, IntPtr gc, int src_x, int src_y, int width, int height, int dest_x, int dest_y); + + [DllImport ("libX11", EntryPoint="XGetAtomName")] + internal extern static string XGetAtomName (IntPtr display, int atom); + + [DllImport ("libX11", EntryPoint="XGetWindowProperty")] + internal extern static int XGetWindowProperty (IntPtr display, IntPtr window, int atom, int long_offset, int long_length, bool delete, Atom req_type, out Atom actual_type, out int actual_format, out int nitems, out int bytes_after, ref IntPtr prop); + + [DllImport ("libX11", EntryPoint="XSetInputFocus")] + internal extern static int XSetInputFocus (IntPtr display, IntPtr window, RevertTo revert_to, IntPtr time); + + [DllImport ("libX11", EntryPoint="XIconifyWindow")] + internal extern static int XIconifyWindow (IntPtr display, IntPtr window, int screen_number); + + [DllImport ("libX11", EntryPoint="XDefineCursor")] + internal extern static int XDefineCursor (IntPtr display, IntPtr window, IntPtr cursor); + + [DllImport ("libX11", EntryPoint="XUndefineCursor")] + internal extern static int XUndefineCursor (IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XFreeCursor")] + internal extern static int XFreeCursor (IntPtr display, IntPtr cursor); + + [DllImport ("libX11", EntryPoint="XCreateFontCursor")] + internal extern static IntPtr XCreateFontCursor (IntPtr display, CursorFontShape shape); + + [DllImport ("libX11", EntryPoint="XCreatePixmapCursor")] + internal extern static IntPtr XCreatePixmapCursor (IntPtr display, IntPtr source, IntPtr mask, ref XColor foreground_color, ref XColor background_color, int x_hot, int y_hot); + + [DllImport ("libX11", EntryPoint="XCreatePixmapFromBitmapData")] + internal extern static IntPtr XCreatePixmapFromBitmapData (IntPtr display, IntPtr drawable, byte[] data, int width, int height, IntPtr fg, IntPtr bg, int depth); + + [DllImport ("libX11", EntryPoint="XFreePixmap")] + internal extern static IntPtr XFreePixmap (IntPtr display, IntPtr pixmap); + + [DllImport ("libX11", EntryPoint="XWhitePixel")] + internal extern static IntPtr XWhitePixel (IntPtr display, int screen_no); + + [DllImport ("libX11", EntryPoint="XBlackPixel")] + internal extern static IntPtr XBlackPixel (IntPtr display, int screen_no); + + [DllImport ("libX11", EntryPoint="XGrabServer")] + internal extern static void XGrabServer (IntPtr display); + + [DllImport ("libX11", EntryPoint="XUngrabServer")] + internal extern static void XUngrabServer (IntPtr display); + + [DllImport ("libX11", EntryPoint="XSetWMNormalHints")] + internal extern static void XSetWMNormalHints (IntPtr display, IntPtr window, ref XSizeHints hints); + + [DllImport ("libX11", EntryPoint="XSetZoomHints")] + internal extern static void XSetZoomHints (IntPtr display, IntPtr window, ref XSizeHints hints); + + [DllImport ("libX11", EntryPoint="XSetWMHints")] + internal extern static void XSetWMHints (IntPtr display, IntPtr window, ref XWMHints wmhints); + + [DllImport ("libX11", EntryPoint="XSync")] + internal extern static void XSync (IntPtr display, IntPtr window); + + [DllImport ("libX11", EntryPoint="XGetIconSizes")] + internal extern static int XGetIconSizes (IntPtr display, IntPtr window, out IntPtr size_list, out int count); + + [DllImport ("libX11", EntryPoint="XSetErrorHandler")] + internal extern static IntPtr XSetErrorHandler (XErrorHandler error_handler); + + [DllImport ("libX11", EntryPoint="XGetErrorText")] + internal extern static IntPtr XGetErrorText (IntPtr display, byte code, StringBuilder buffer, int length); + + [DllImport ("libX11", EntryPoint="XInitThreads")] + internal extern static int XInitThreads (); + + [DllImport ("libX11", EntryPoint="XConvertSelection")] + internal extern static int XConvertSelection (IntPtr display, int selection, int target, int property, IntPtr requestor, IntPtr time); + + [DllImport ("libX11", EntryPoint="XGetSelectionOwner")] + internal extern static IntPtr XGetSelectionOwner (IntPtr display, int selection); + + [DllImport ("libX11", EntryPoint="XSetSelectionOwner")] + internal extern static int XSetSelectionOwner (IntPtr display, int selection, IntPtr owner, IntPtr time); + + [DllImport ("libX11", EntryPoint="XSetPlaneMask")] + internal extern static int XSetPlaneMask (IntPtr display, IntPtr gc, uint mask); + + [DllImport ("libX11", EntryPoint="XSetForeground")] + internal extern static int XSetForeground (IntPtr display, IntPtr gc, uint foreground); + + [DllImport ("libX11", EntryPoint="XSetBackground")] + internal extern static int XSetBackground (IntPtr display, IntPtr gc, uint background); + + #endregion + + #region gdk imports + [DllImport("libgdk-x11-2.0.so")] + static extern bool gdk_init_check (IntPtr argc, IntPtr argv); + + [DllImport("libgdk-x11-2.0.so")] + internal static extern IntPtr gdk_x11_display_get_xdisplay (IntPtr display); + + [DllImport("libgdk-x11-2.0.so")] + internal static extern IntPtr gdk_display_get_default (); + + [DllImport("libgdk-x11-2.0.so")] + static extern IntPtr gdk_pixmap_new (IntPtr drawable, int width, int height, int depth); + + [DllImport("libgdk-x11-2.0.so")] + static extern IntPtr gdk_x11_drawable_get_xid (IntPtr gdkdrawable); + + [DllImport("libgdk-x11-2.0.so")] + static extern void gdk_draw_drawable (IntPtr drawable_dest, IntPtr gdk_gc, IntPtr drawable_src, int xsrc, int ysrc, int xdest, int ydest, int width, int height); + + [DllImport("libgdk-x11-2.0.so")] + static extern IntPtr gdk_gc_new (IntPtr drawable); + + [DllImport("libgdk-x11-2.0.so")] + static extern IntPtr gdk_window_foreign_new (IntPtr anid); + + [DllImport("libgdk-x11-2.0.so")] + static extern IntPtr gdk_x11_lookup_xdisplay (IntPtr xdisplay); + + [DllImport("libgdk-x11-2.0.so")] + static extern void gdk_display_close (IntPtr display); + + [DllImport("libgdk-x11-2.0.so")] + static extern void gdk_display_beep (IntPtr display); + + [DllImport("libgdk-x11-2.0.so")] + static extern void gdk_display_sync (IntPtr display); + + [DllImport("libgdk-x11-2.0.so")] + static extern IntPtr gdk_get_default_root_window (); + + [DllImport("libgdk-x11-2.0.so")] + static extern IntPtr gdk_colormap_get_system (); + + [DllImport("libgdk-x11-2.0.so")] + static extern IntPtr gdk_x11_colormap_get_xcolormap (IntPtr gdk_colormap); + + [DllImport("libgdk-x11-2.0.so")] + static extern void gdk_window_destroy (IntPtr gdk_window); + + [DllImport("libgdk-x11-2.0.so")] + static extern void gdk_x11_grab_server (); + + [DllImport("libgdk-x11-2.0.so")] + static extern void gdk_x11_ungrab_server (); + + [DllImport("libgdk-x11-2.0.so")] + static extern void gdk_display_flush (IntPtr gdk_display); + + [DllImport("libgdk-x11-2.0.so")] + static extern void gdk_window_iconify (IntPtr gdk_window); + + [DllImport("libgdk-x11-2.0.so")] + static extern void gdk_window_deiconify (IntPtr gdk_window); + + [DllImport("libgdk-x11-2.0.so")] + static extern void gdk_window_set_decorations (IntPtr gdk_window, int decorations); + + [DllImport("libgdk-x11-2.0.so")] + static extern IntPtr gdk_screen_get_default (); + + [DllImport("libgdk-x11-2.0.so")] + static extern int gdk_screen_get_number (IntPtr gdk_screen); + + [DllImport("libgdk-x11-2.0.so")] + static extern IntPtr gdk_window_lookup (IntPtr anid); + + [DllImport("libgdk-x11-2.0.so")] + static extern IntPtr gdk_window_new (IntPtr gdk_parent, ref GdkWindowAttr gdk_window_attributes, int attributes_mask); + + [DllImport("libgdk-x11-2.0.so")] + static extern void gdk_window_set_events (IntPtr gdk_window, int event_mask); + + [DllImport("libgdk-x11-2.0.so")] + static extern void gdk_window_show (IntPtr window); + + [DllImport("libgdk-x11-2.0.so")] + static extern void gdk_window_set_title (IntPtr gdk_window, string title); + + [DllImport("libgdk-x11-2.0.so")] + static extern int gdk_window_get_origin (IntPtr gdk_window, out int x, out int y); + + [DllImport("libgdk-x11-2.0.so")] + static extern void gdk_window_get_geometry (IntPtr gdk_window, out int x, out int y, out int width, out int height, out int depth); + + [DllImport("libgdk-x11-2.0.so")] + static extern void gdk_property_change (IntPtr gdk_window, /*GdkAtom*/IntPtr property, /*GdkAtom*/IntPtr type, int format, int gdk_prop_mode, /*const guchar **/ IntPtr data, int nelements); + + [DllImport("libgdk-x11-2.0.so")] + static extern IntPtr gdk_window_get_parent (IntPtr gdk_window); + + [DllImport("libgdk-x11-2.0.so")] + static extern void gdk_display_get_maximal_cursor_size (IntPtr gdk_display, out uint width, out uint height); + + [DllImport("libgdk-x11-2.0.so")] + static extern int gdk_visual_get_best_depth (); + #endregion + + #region gobject imports + [DllImport("libglib-2.0.so")] + static extern void g_free (IntPtr mem); + + [DllImport("libgobject-2.0.so")] + static extern void g_object_unref (IntPtr nativeObject); + #endregion + } +} diff --git a/source/ShiftUI/Keyboard/InputLanguage.cs b/source/ShiftUI/Keyboard/InputLanguage.cs new file mode 100644 index 0000000..e2f7edd --- /dev/null +++ b/source/ShiftUI/Keyboard/InputLanguage.cs @@ -0,0 +1,134 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// NOT COMPLETE + +using System.Globalization; +using System; + +namespace ShiftUI { + public sealed class InputLanguage { + private static InputLanguageCollection all; + private IntPtr handle; + private CultureInfo culture; + private string layout_name; + private static InputLanguage current_input; + private static InputLanguage default_input; + + #region Private Constructor + [MonoInternalNote ("Pull Microsofts InputLanguages and enter them here")] + internal InputLanguage() + { + } + + internal InputLanguage(IntPtr handle, CultureInfo culture, string layout_name) : this() { + this.handle=handle; + this.culture=culture; + this.layout_name=layout_name; + } + #endregion // Private Constructor + + #region Public Static Properties + public static InputLanguage CurrentInputLanguage { + get { + if (current_input == null) + current_input = InputLanguage.FromCulture (CultureInfo.CurrentUICulture); + return current_input; + } + + set { + if (InstalledInputLanguages.Contains (value)) + current_input = value; + } + } + + public static InputLanguage DefaultInputLanguage { + get { + if (default_input == null) + default_input = InputLanguage.FromCulture (CultureInfo.CurrentUICulture); + + return default_input; + } + } + + public static InputLanguageCollection InstalledInputLanguages { + get { + if (all == null) + all = new InputLanguageCollection (new InputLanguage[] { new InputLanguage (IntPtr.Zero, new CultureInfo(string.Empty), "US") }); + + return all; + } + } + #endregion // Public Static Properties + + #region Public Instance Properties + public CultureInfo Culture { + get { + return this.culture; + } + } + + public IntPtr Handle { + get { + return this.handle; + } + } + + public string LayoutName { + get { + return this.layout_name; + } + } + #endregion // Public Instance Properties + + #region Public Static Methods + public static InputLanguage FromCulture(System.Globalization.CultureInfo culture) { + foreach (InputLanguage c in InstalledInputLanguages) { + if (culture.EnglishName==c.culture.EnglishName) { + return new InputLanguage(c.handle, c.culture, c.layout_name); + } + } + + return new InputLanguage (InstalledInputLanguages[0].handle, InstalledInputLanguages[0].culture, InstalledInputLanguages[0].layout_name); + } + #endregion // Public Static Methods + + #region Public Instance Methods + public override bool Equals(object value) { + if (value is InputLanguage) { + if ((((InputLanguage)value).culture==this.culture) && (((InputLanguage)value).handle==this.handle) && (((InputLanguage)value).layout_name==this.layout_name)) { + return true; + } + } + return false; + } + + public override int GetHashCode() { + return base.GetHashCode(); + } + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Keyboard/InputLanguageCollection.cs b/source/ShiftUI/Keyboard/InputLanguageCollection.cs new file mode 100644 index 0000000..e1715db --- /dev/null +++ b/source/ShiftUI/Keyboard/InputLanguageCollection.cs @@ -0,0 +1,77 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +using System.Collections; +using System.Globalization; +using System; + +namespace ShiftUI { + public class InputLanguageCollection : ReadOnlyCollectionBase { + #region Private Constructor + internal InputLanguageCollection (InputLanguage[] data) + { + base.InnerList.AddRange (data); + } + #endregion // Private Constructor + + #region Public Instance Methods + public InputLanguage this [int index] { + get { + if (index >= base.InnerList.Count) { + throw new ArgumentOutOfRangeException("index"); + } + return base.InnerList[index] as InputLanguage; + } + } + + public bool Contains(InputLanguage value) { + for (int i = 0; i < base.InnerList.Count; i++) { + if ((this[i].Culture == value.Culture) && (this[i].LayoutName == value.LayoutName)) { + return true; + } + } + return false; + } + + public void CopyTo(InputLanguage[] array, int index) { + if (base.InnerList.Count > 0) { + base.InnerList.CopyTo (array, index); + } + } + + public int IndexOf(InputLanguage value) { + for (int i = 0; i < base.InnerList.Count; i++) { + if ((this[i].Culture == value.Culture) && (this[i].LayoutName == value.LayoutName)) { + return i; + } + } + return -1; + } + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/Keyboard/KeyEventArgs.cs b/source/ShiftUI/Keyboard/KeyEventArgs.cs new file mode 100644 index 0000000..da53765 --- /dev/null +++ b/source/ShiftUI/Keyboard/KeyEventArgs.cs @@ -0,0 +1,123 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + [ComVisible(true)] + public class KeyEventArgs : EventArgs { + private Keys key_data; + private bool event_handled; + private bool supress_key_press; + + #region Public Constructors + public KeyEventArgs(Keys keyData) { + this.key_data=keyData; + this.event_handled=false; + } + #endregion // Public Constructors + + #region Public Instance Properties + public virtual bool Alt { + get { + if ((this.key_data & Keys.Alt)==0) { + return false; + } else { + return true; + } + } + } + + public bool Widget { + get { + if ((this.key_data & Keys.Widget)==0) { + return false; + } else { + return true; + } + } + } + + public bool Handled { + get { + return this.event_handled; + } + + set { + this.event_handled=value; + } + } + + public Keys KeyCode { + get { + return (this.key_data & Keys.KeyCode); + } + } + + public Keys KeyData { + get { + return this.key_data; + } + } + + public int KeyValue { + get { + return Convert.ToInt32(this.key_data); + } + } + + public Keys Modifiers { + get { + return (this.key_data & Keys.Modifiers); + } + } + + public virtual bool Shift { + get { + if ((this.key_data & Keys.Shift)==0) { + return false; + } else { + return true; + } + } + } + + public bool SuppressKeyPress { + get { + return supress_key_press; + } + set { + supress_key_press = value; + event_handled = value; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Keyboard/KeyEventHandler.cs b/source/ShiftUI/Keyboard/KeyEventHandler.cs new file mode 100644 index 0000000..857eef3 --- /dev/null +++ b/source/ShiftUI/Keyboard/KeyEventHandler.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + + +// COMPLETE + +namespace ShiftUI { + public delegate void KeyEventHandler (object sender, KeyEventArgs e); +} diff --git a/source/ShiftUI/Keyboard/KeyPressEventArgs.cs b/source/ShiftUI/Keyboard/KeyPressEventArgs.cs new file mode 100644 index 0000000..7d912d6 --- /dev/null +++ b/source/ShiftUI/Keyboard/KeyPressEventArgs.cs @@ -0,0 +1,68 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + [ComVisible(true)] + public class KeyPressEventArgs : EventArgs { + private char key_char; + private bool event_handled; + + #region Public Constructors + public KeyPressEventArgs(char keyChar) { + this.key_char=keyChar; + this.event_handled=false; + } + #endregion // Public Constructors + + #region Public Instance Properties + public bool Handled { + get { + return this.event_handled; + } + + set { + this.event_handled=value; + } + } + + public char KeyChar { + get { + return this.key_char; + } + + set { + key_char = value; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Keyboard/KeyPressEventHandler.cs b/source/ShiftUI/Keyboard/KeyPressEventHandler.cs new file mode 100644 index 0000000..bfb6a25 --- /dev/null +++ b/source/ShiftUI/Keyboard/KeyPressEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +namespace ShiftUI { + public delegate void KeyPressEventHandler (object sender, KeyPressEventArgs e); +} diff --git a/source/ShiftUI/Keyboard/KeyboardLayouts.cs b/source/ShiftUI/Keyboard/KeyboardLayouts.cs new file mode 100644 index 0000000..7d56678 --- /dev/null +++ b/source/ShiftUI/Keyboard/KeyboardLayouts.cs @@ -0,0 +1,149 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// +// +using System; +using System.Resources; +using System.Text; +using System.IO; +using System.Runtime.Serialization.Formatters.Binary; +using System.Reflection; + +namespace ShiftUI { + + internal class KeyboardLayouts { + private KeyboardLayout [] keyboard_layouts; + public int [][] vkey_table; + public short [][] scan_table; + + public static object ObjFromByte(string resource) { + var asm = Assembly.GetExecutingAssembly (); + var resources = asm.GetManifestResourceNames (); + byte[] binary = null; + foreach (var r in resources) { + if(r.Contains(resource)) { + var res = asm.GetManifestResourceStream(r); + binary = new byte[res.Length]; + res.Read(binary, 0, (int)res.Length); + string base64s = Encoding.UTF8.GetString (binary); + binary = Convert.FromBase64String (base64s); + res.Close(); + } + } + if (binary != null) { + MemoryStream memStream = new MemoryStream(); + BinaryFormatter binForm = new BinaryFormatter(); + memStream.Write(binary, 0, binary.Length); + memStream.Seek(0, SeekOrigin.Begin); + Object obj = (Object) binForm.Deserialize(memStream); + return obj; + } else { + throw new ArgumentException ("The resource could not be found."); + } + } + + public void LoadLayouts () + { + keyboard_layouts = (KeyboardLayout []) ObjFromByte("keyboard_table"); + + vkey_table = (int [][]) ObjFromByte ("vkey_table"); + scan_table = (short [][]) ObjFromByte ("scan_table"); + } + + public KeyboardLayout [] Layouts { + get { + if (keyboard_layouts == null) + LoadLayouts (); + return keyboard_layouts; + } + } + } + + + + [Serializable] +#if GENERATING_RESOURCES + [CLSCompliant(false)] + public +#else + internal +#endif + class KeyboardLayout { + + public int Lcid; + public string Name; + public ScanTableIndex ScanIndex; + public VKeyTableIndex VKeyIndex; + public uint [][] Keys; + + public KeyboardLayout (int lcid, string name, ScanTableIndex scan_index, + VKeyTableIndex vkey_index, uint [][] keys) + { + Lcid = lcid; + Name = name; + ScanIndex = scan_index; + VKeyIndex = vkey_index; + Keys = keys; + } + + public KeyboardLayout (int lcid, string name, int scan_index, + int vkey_index, uint [][] keys) : this (lcid, name, (ScanTableIndex) scan_index, + (VKeyTableIndex) vkey_index, keys) + { + } + + } + +#if GENERATING_RESOURCES + public +#else + internal +#endif + enum VKeyTableIndex { + Qwerty, + Qwertz, + Dvorak, + Qwertz105, + Azerty, + QwertyV2, + AbntQwerty, + QwertyJp106, + Vnc + } + +#if GENERATING_RESOURCES + public +#else + internal +#endif + enum ScanTableIndex { + Qwerty, + Dvorak, + AbntQwerty, + QwertyJp106, + Vnc + } + +} + diff --git a/source/ShiftUI/Keyboard/ResXResourceWriter.cs b/source/ShiftUI/Keyboard/ResXResourceWriter.cs new file mode 100644 index 0000000..42b3961 --- /dev/null +++ b/source/ShiftUI/Keyboard/ResXResourceWriter.cs @@ -0,0 +1,667 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Duncan Mak duncan@ximian.com +// Gonzalo Paniagua Javier gonzalo@ximian.com +// Peter Bartok pbartok@novell.com +// Gary Barnett gary.barnett.mono@gmail.com +// includes code by Mike Krüger and Lluis Sanchez + +using System.ComponentModel; +using System.IO; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; +using System.Xml; +using System.Reflection; + +namespace System.Resources +{ +#if INSIDE_SYSTEM_WEB + internal +#else + public +#endif + class ResXResourceWriter : IResourceWriter, IDisposable + { + #region Local Variables + private string filename; + private Stream stream; + private TextWriter textwriter; + private XmlTextWriter writer; + private bool written; + private string base_path; + #endregion // Local Variables + + #region Static Fields + public static readonly string BinSerializedObjectMimeType = "application/x-microsoft.net.object.binary.base64"; + public static readonly string ByteArraySerializedObjectMimeType = "application/x-microsoft.net.object.bytearray.base64"; + public static readonly string DefaultSerializedObjectMimeType = BinSerializedObjectMimeType; + public static readonly string ResMimeType = "text/microsoft-resx"; + public static readonly string ResourceSchema = schema; + public static readonly string SoapSerializedObjectMimeType = "application/x-microsoft.net.object.soap.base64"; + public static readonly string Version = "2.0"; + #endregion // Static Fields + + #region Constructors & Destructor + public ResXResourceWriter (Stream stream) + { + if (stream == null) + throw new ArgumentNullException ("stream"); + + if (!stream.CanWrite) + throw new ArgumentException ("stream is not writable.", "stream"); + + this.stream = stream; + } + + public ResXResourceWriter (TextWriter textWriter) + { + if (textWriter == null) + throw new ArgumentNullException ("textWriter"); + + this.textwriter = textWriter; + } + + public ResXResourceWriter (string fileName) + { + if (fileName == null) + throw new ArgumentNullException ("fileName"); + + this.filename = fileName; + } + + ~ResXResourceWriter() { + Dispose(false); + } + #endregion // Constructors & Destructor + + void InitWriter () + { + if (filename != null) + stream = File.Open (filename, FileMode.Create); + if (textwriter == null) + textwriter = new StreamWriter (stream, Encoding.UTF8); + + writer = new XmlTextWriter (textwriter); + writer.Formatting = Formatting.Indented; + writer.WriteStartDocument (); + writer.WriteStartElement ("root"); + writer.WriteRaw (schema); + WriteHeader ("resmimetype", "text/microsoft-resx"); + WriteHeader ("version", "1.3"); + WriteHeader ("reader", typeof (ResXResourceReader).AssemblyQualifiedName); + WriteHeader ("writer", typeof (ResXResourceWriter).AssemblyQualifiedName); + } + + void WriteHeader (string name, string value) + { + writer.WriteStartElement ("resheader"); + writer.WriteAttributeString ("name", name); + writer.WriteStartElement ("value"); + writer.WriteString (value); + writer.WriteEndElement (); + writer.WriteEndElement (); + } + + void WriteNiceBase64(byte[] value, int offset, int length) { + string b64; + StringBuilder sb; + int pos; + int inc; + string ins; + + b64 = Convert.ToBase64String(value, offset, length); + + // Wild guess; two extra newlines, and one newline/tab pair for every 80 chars + sb = new StringBuilder(b64, b64.Length + ((b64.Length + 160) / 80) * 3); + pos = 0; + inc = 80 + Environment.NewLine.Length + 1; + ins = Environment.NewLine + "\t"; + while (pos < sb.Length) { + sb.Insert(pos, ins); + pos += inc; + } + sb.Insert(sb.Length, Environment.NewLine); + writer.WriteString(sb.ToString()); + } + void WriteBytes (string name, Type type, byte[] value, int offset, int length) + { + WriteBytes (name, type, value, offset, length, String.Empty); + } + + void WriteBytes (string name, Type type, byte[] value, int offset, int length, string comment) + { + writer.WriteStartElement ("data"); + writer.WriteAttributeString ("name", name); + + if (type != null) { + writer.WriteAttributeString ("type", type.AssemblyQualifiedName); + // byte[] should never get a mimetype, otherwise MS.NET won't be able + // to parse the data. + if (type != typeof (byte[])) + writer.WriteAttributeString ("mimetype", ByteArraySerializedObjectMimeType); + writer.WriteStartElement ("value"); + WriteNiceBase64 (value, offset, length); + } else { + writer.WriteAttributeString ("mimetype", BinSerializedObjectMimeType); + writer.WriteStartElement ("value"); + writer.WriteBase64 (value, offset, length); + } + + writer.WriteEndElement (); + + if (!(comment == null || comment.Equals (String.Empty))) { + writer.WriteStartElement ("comment"); + writer.WriteString (comment); + writer.WriteEndElement (); + } + + writer.WriteEndElement (); + } + + void WriteBytes (string name, Type type, byte [] value, string comment) + { + WriteBytes (name, type, value, 0, value.Length, comment); + } + + void WriteString (string name, string value) + { + WriteString (name, value, null); + } + void WriteString (string name, string value, Type type) + { + WriteString (name, value, type, String.Empty); + } + void WriteString (string name, string value, Type type, string comment) + { + writer.WriteStartElement ("data"); + writer.WriteAttributeString ("name", name); + if (type != null) + writer.WriteAttributeString ("type", type.AssemblyQualifiedName); + writer.WriteStartElement ("value"); + writer.WriteString (value); + writer.WriteEndElement (); + if (!(comment == null || comment.Equals (String.Empty))) { + writer.WriteStartElement ("comment"); + writer.WriteString (comment); + writer.WriteEndElement (); + } + writer.WriteEndElement (); + writer.WriteWhitespace ("\n "); + } + + public void AddResource (string name, byte [] value) + { + if (name == null) + throw new ArgumentNullException ("name"); + + if (value == null) + throw new ArgumentNullException ("value"); + + if (written) + throw new InvalidOperationException ("The resource is already generated."); + + if (writer == null) + InitWriter (); + + WriteBytes (name, value.GetType (), value, null); + } + + public void AddResource (string name, object value) + { + AddResource (name, value, String.Empty); + } + + private void AddResource (string name, object value, string comment) + { + if (value is string) { + AddResource (name, (string) value, comment); + return; + } + + if (name == null) + throw new ArgumentNullException ("name"); + + if (value != null && !value.GetType ().IsSerializable) + throw new InvalidOperationException (String.Format ("The element '{0}' of type '{1}' is not serializable.", name, value.GetType ().Name)); + + if (written) + throw new InvalidOperationException ("The resource is already generated."); + + if (writer == null) + InitWriter (); + + if (value is byte[]) { + WriteBytes (name, value.GetType (), (byte []) value, comment); + return; + } + + if (value == null) { + // nulls written as ResXNullRef + WriteString (name, "", typeof (ResXNullRef), comment); + return; + } + + TypeConverter converter = TypeDescriptor.GetConverter (value); + if (value is ResXFileRef) { + ResXFileRef fileRef = ProcessFileRefBasePath ((ResXFileRef) value); + string str = (string) converter.ConvertToInvariantString (fileRef); + WriteString (name, str, value.GetType (), comment); + return; + } + + if (converter != null && converter.CanConvertTo (typeof (string)) && converter.CanConvertFrom (typeof (string))) { + string str = (string) converter.ConvertToInvariantString (value); + WriteString (name, str, value.GetType (), comment); + return; + } + + if (converter != null && converter.CanConvertTo (typeof (byte[])) && converter.CanConvertFrom (typeof (byte[]))) { + byte[] b = (byte[]) converter.ConvertTo (value, typeof (byte[])); + WriteBytes (name, value.GetType (), b, comment); + return; + } + + MemoryStream ms = new MemoryStream (); + BinaryFormatter fmt = new BinaryFormatter (); + try { + fmt.Serialize (ms, value); + } catch (Exception e) { + throw new InvalidOperationException ("Cannot add a " + value.GetType () + + "because it cannot be serialized: " + + e.Message); + } + + WriteBytes (name, null, ms.GetBuffer (), 0, (int) ms.Length, comment); + ms.Close (); + } + + public void AddResource (string name, string value) + { + AddResource (name, value, string.Empty); + } + + private void AddResource (string name, string value, string comment) + { + if (name == null) + throw new ArgumentNullException ("name"); + + if (value == null) + throw new ArgumentNullException ("value"); + + if (written) + throw new InvalidOperationException ("The resource is already generated."); + + if (writer == null) + InitWriter (); + + WriteString (name, value, null, comment); + } + + [MonoTODO ("Stub, not implemented")] + public virtual void AddAlias (string aliasName, AssemblyName assemblyName) + { + } + + public void AddResource (ResXDataNode node) + { + if (node == null) + throw new ArgumentNullException ("node"); + + if (writer == null) + InitWriter (); + + if (node.IsWritable) + WriteWritableNode (node); + else if (node.FileRef != null) + AddResource (node.Name, node.FileRef, node.Comment); + else + AddResource (node.Name, node.GetValue ((AssemblyName []) null), node.Comment); + } + + ResXFileRef ProcessFileRefBasePath (ResXFileRef fileRef) + { + if (String.IsNullOrEmpty (BasePath)) + return fileRef; + + string newPath = AbsoluteToRelativePath (BasePath, fileRef.FileName); + return new ResXFileRef (newPath, fileRef.TypeName, fileRef.TextFileEncoding); + } + + static bool IsSeparator (char ch) + { + return ch == Path.DirectorySeparatorChar || ch == Path.AltDirectorySeparatorChar || ch == Path.VolumeSeparatorChar; + } + //adapted from MonoDevelop.Core + unsafe static string AbsoluteToRelativePath (string baseDirectoryPath, string absPath) + { + if (string.IsNullOrEmpty (baseDirectoryPath)) + return absPath; + + baseDirectoryPath = baseDirectoryPath.TrimEnd (Path.DirectorySeparatorChar); + + fixed (char* bPtr = baseDirectoryPath, aPtr = absPath) { + var bEnd = bPtr + baseDirectoryPath.Length; + var aEnd = aPtr + absPath.Length; + char* lastStartA = aEnd; + char* lastStartB = bEnd; + + int indx = 0; + // search common base path + var a = aPtr; + var b = bPtr; + while (a < aEnd) { + if (*a != *b) + break; + if (IsSeparator (*a)) { + indx++; + lastStartA = a + 1; + lastStartB = b; + } + a++; + b++; + if (b >= bEnd) { + if (a >= aEnd || IsSeparator (*a)) { + indx++; + lastStartA = a + 1; + lastStartB = b; + } + break; + } + } + if (indx == 0) + return absPath; + + if (lastStartA >= aEnd) + return "."; + + // handle case a: some/path b: some/path/deeper... + if (a >= aEnd) { + if (IsSeparator (*b)) { + lastStartA = a + 1; + lastStartB = b; + } + } + + // look how many levels to go up into the base path + int goUpCount = 0; + while (lastStartB < bEnd) { + if (IsSeparator (*lastStartB)) + goUpCount++; + lastStartB++; + } + var size = goUpCount * 2 + goUpCount + aEnd - lastStartA; + var result = new char [size]; + fixed (char* rPtr = result) { + // go paths up + var r = rPtr; + for (int i = 0; i < goUpCount; i++) { + *(r++) = '.'; + *(r++) = '.'; + *(r++) = Path.DirectorySeparatorChar; + } + // copy the remaining absulute path + while (lastStartA < aEnd) + *(r++) = *(lastStartA++); + } + return new string (result); + } + } + + // avoids instantiating objects + void WriteWritableNode (ResXDataNode node) + { + writer.WriteStartElement ("data"); + writer.WriteAttributeString ("name", node.Name); + if (!(node.Type == null || node.Type.Equals (String.Empty))) + writer.WriteAttributeString ("type", node.Type); + if (!(node.MimeType == null || node.MimeType.Equals (String.Empty))) + writer.WriteAttributeString ("mimetype", node.MimeType); + writer.WriteStartElement ("value"); + writer.WriteString (node.DataString); + writer.WriteEndElement (); + if (!(node.Comment == null || node.Comment.Equals (String.Empty))) { + writer.WriteStartElement ("comment"); + writer.WriteString (node.Comment); + writer.WriteEndElement (); + } + writer.WriteEndElement (); + writer.WriteWhitespace ("\n "); + } + + public void AddMetadata (string name, string value) + { + if (name == null) + throw new ArgumentNullException ("name"); + + if (value == null) + throw new ArgumentNullException ("value"); + + if (written) + throw new InvalidOperationException ("The resource is already generated."); + + if (writer == null) + InitWriter (); + + writer.WriteStartElement ("metadata"); + writer.WriteAttributeString ("name", name); + writer.WriteAttributeString ("xml:space", "preserve"); + + writer.WriteElementString ("value", value); + + writer.WriteEndElement (); + } + + public void AddMetadata (string name, byte[] value) + { + if (name == null) + throw new ArgumentNullException ("name"); + + if (value == null) + throw new ArgumentNullException ("value"); + + if (written) + throw new InvalidOperationException ("The resource is already generated."); + + if (writer == null) + InitWriter (); + + writer.WriteStartElement ("metadata"); + writer.WriteAttributeString ("name", name); + + writer.WriteAttributeString ("type", value.GetType ().AssemblyQualifiedName); + + writer.WriteStartElement ("value"); + WriteNiceBase64 (value, 0, value.Length); + writer.WriteEndElement (); + + writer.WriteEndElement (); + } + + public void AddMetadata (string name, object value) + { + if (value is string) { + AddMetadata (name, (string)value); + return; + } + + if (value is byte[]) { + AddMetadata (name, (byte[])value); + return; + } + + if (name == null) + throw new ArgumentNullException ("name"); + + if (value == null) + throw new ArgumentNullException ("value"); + + if (!value.GetType ().IsSerializable) + throw new InvalidOperationException (String.Format ("The element '{0}' of type '{1}' is not serializable.", name, value.GetType ().Name)); + + if (written) + throw new InvalidOperationException ("The resource is already generated."); + + if (writer == null) + InitWriter (); + + Type type = value.GetType (); + + TypeConverter converter = TypeDescriptor.GetConverter (value); + if (converter != null && converter.CanConvertTo (typeof (string)) && converter.CanConvertFrom (typeof (string))) { + string str = (string)converter.ConvertToInvariantString (value); + writer.WriteStartElement ("metadata"); + writer.WriteAttributeString ("name", name); + if (type != null) + writer.WriteAttributeString ("type", type.AssemblyQualifiedName); + writer.WriteStartElement ("value"); + writer.WriteString (str); + writer.WriteEndElement (); + writer.WriteEndElement (); + writer.WriteWhitespace ("\n "); + return; + } + + if (converter != null && converter.CanConvertTo (typeof (byte[])) && converter.CanConvertFrom (typeof (byte[]))) { + byte[] b = (byte[])converter.ConvertTo (value, typeof (byte[])); + writer.WriteStartElement ("metadata"); + writer.WriteAttributeString ("name", name); + + if (type != null) { + writer.WriteAttributeString ("type", type.AssemblyQualifiedName); + writer.WriteAttributeString ("mimetype", ByteArraySerializedObjectMimeType); + writer.WriteStartElement ("value"); + WriteNiceBase64 (b, 0, b.Length); + } else { + writer.WriteAttributeString ("mimetype", BinSerializedObjectMimeType); + writer.WriteStartElement ("value"); + writer.WriteBase64 (b, 0, b.Length); + } + + writer.WriteEndElement (); + writer.WriteEndElement (); + return; + } + + MemoryStream ms = new MemoryStream (); + BinaryFormatter fmt = new BinaryFormatter (); + try { + fmt.Serialize (ms, value); + } catch (Exception e) { + throw new InvalidOperationException ("Cannot add a " + value.GetType () + + "because it cannot be serialized: " + + e.Message); + } + + writer.WriteStartElement ("metadata"); + writer.WriteAttributeString ("name", name); + + if (type != null) { + writer.WriteAttributeString ("type", type.AssemblyQualifiedName); + writer.WriteAttributeString ("mimetype", ByteArraySerializedObjectMimeType); + writer.WriteStartElement ("value"); + WriteNiceBase64 (ms.GetBuffer (), 0, ms.GetBuffer ().Length); + } else { + writer.WriteAttributeString ("mimetype", BinSerializedObjectMimeType); + writer.WriteStartElement ("value"); + writer.WriteBase64 (ms.GetBuffer (), 0, ms.GetBuffer ().Length); + } + + writer.WriteEndElement (); + writer.WriteEndElement (); + ms.Close (); + } + + public void Close () + { + if (!written) { + Generate (); + } + + if (writer != null) { + writer.Close (); + stream = null; + filename = null; + textwriter = null; + } + } + + public virtual void Dispose () + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public void Generate () + { + if (written) + throw new InvalidOperationException ("The resource is already generated."); + + written = true; + writer.WriteEndElement (); + writer.Flush (); + } + + protected virtual void Dispose (bool disposing) + { + if (disposing) + Close(); + } + + static string schema = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + +".Replace ("'", "\""); + + #region Public Properties + public string BasePath { + get { return base_path; } + set { base_path = value; } + } + #endregion + } +} diff --git a/source/ShiftUI/Keyboard/create-keyboards.cs b/source/ShiftUI/Keyboard/create-keyboards.cs new file mode 100644 index 0000000..67ac3ad --- /dev/null +++ b/source/ShiftUI/Keyboard/create-keyboards.cs @@ -0,0 +1,2079 @@ + +using System; +using System.Resources; +using System.Windows.Forms; +using ShiftUI; + + + +public class CreateKeyboards +{ + public static void Main() + { + ResXResourceWriter rsxw = new ResXResourceWriter ("keyboards.resx"); + KeyboardLayout [] table = new KeyboardLayout [64]; + + table [0] = new KeyboardLayout (1033, "United States keyboard layout", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0x5b, 0x7b, }, + new uint [] {0x5d, 0x7d, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0x3b, 0x3a, }, new uint [] {0x27, 0x22, }, + new uint [] {0x5c, 0x7c, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3c, }, new uint [] {0x2e, 0x3e, }, + new uint [] {0x2f, 0x3f, }, new uint [] {}, + new uint [] {}, }); + table [1] = new KeyboardLayout (1033, "United States keyboard layout (phantom key version)", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0x5b, 0x7b, }, + new uint [] {0x5d, 0x7d, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0x3b, 0x3a, }, new uint [] {0x27, 0x22, }, + new uint [] {0x5c, 0x7c, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3c, }, new uint [] {0x2e, 0x3e, }, + new uint [] {0x2f, 0x3f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [2] = new KeyboardLayout (1033, "United States keyboard layout (dvorak)", 1, 2, new uint [][] { + new uint [] {0x60, 0x7e, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x5b, 0x7b, }, + new uint [] {0x5d, 0x7d, }, new uint [] {0x27, 0x22, }, + new uint [] {0x2c, 0x3c, }, new uint [] {0x2e, 0x3e, }, + new uint [] {0x70, 0x50, }, new uint [] {0x79, 0x59, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x63, 0x43, }, new uint [] {0x72, 0x52, }, + new uint [] {0x6c, 0x4c, }, new uint [] {0x2f, 0x3f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x61, 0x41, }, + new uint [] {0x6f, 0x4f, }, new uint [] {0x65, 0x45, }, + new uint [] {0x75, 0x55, }, new uint [] {0x69, 0x49, }, + new uint [] {0x64, 0x44, }, new uint [] {0x68, 0x48, }, + new uint [] {0x74, 0x54, }, new uint [] {0x6e, 0x4e, }, + new uint [] {0x73, 0x53, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x5c, 0x7c, }, new uint [] {0x3b, 0x3a, }, + new uint [] {0x71, 0x51, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x78, 0x58, }, + new uint [] {0x62, 0x42, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x77, 0x57, }, new uint [] {0x76, 0x56, }, + new uint [] {0x7a, 0x5a, }, new uint [] {}, + new uint [] {}, }); + table [3] = new KeyboardLayout (1033, "United States International keyboard layout", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x5c, 0x7c, }, + new uint [] {0x71, 0x51, }, new uint [] {0x77, 0x57, }, + new uint [] {0x65, 0x45, }, new uint [] {0x72, 0x52, }, + new uint [] {0x74, 0x54, }, new uint [] {0x79, 0x59, }, + new uint [] {0x75, 0x55, }, new uint [] {0x69, 0x49, }, + new uint [] {0x6f, 0x4f, }, new uint [] {0x70, 0x50, }, + new uint [] {0x5b, 0x7b, }, new uint [] {0x5d, 0x7d, }, + new uint [] {0x61, 0x41, }, new uint [] {0x73, 0x53, }, + new uint [] {0x64, 0x44, }, new uint [] {0x66, 0x46, }, + new uint [] {0x67, 0x47, }, new uint [] {0x68, 0x48, }, + new uint [] {0x6a, 0x4a, }, new uint [] {0x6b, 0x4b, }, + new uint [] {0x6c, 0x4c, }, new uint [] {0x3b, 0x3a, }, + new uint [] {0x27, 0x22, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3c, }, new uint [] {0x2e, 0x3e, }, + new uint [] {0x2f, 0x3f, }, new uint [] {}, + new uint [] {}, }); + table [4] = new KeyboardLayout (2057, "British keyboard layout", 0, 0, new uint [][] { + new uint [] {0x60, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0xffffffa3, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0x5b, 0x7b, }, + new uint [] {0x5d, 0x7d, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0x3b, 0x3a, }, new uint [] {0x27, 0x40, }, + new uint [] {0x23, 0x7e, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3c, }, new uint [] {0x2e, 0x3e, }, + new uint [] {0x2f, 0x3f, }, new uint [] {0x5c, 0x7c, }, + new uint [] {}, }); + table [5] = new KeyboardLayout (1031, "German keyboard layout", 0, 1, new uint [][] { + new uint [] {0x5e, 0xffffffb0, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0xffffffa7, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x3d, }, new uint [] {0xffffffdf, 0x3f, }, + new uint [] {0xffffffb4, 0x60, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x7a, 0x5a, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xfffffffc, 0xffffffdc, }, + new uint [] {0x2b, 0x2a, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xfffffff6, 0xffffffd6, }, new uint [] {0xffffffe4, 0xffffffc4, }, + new uint [] {0x23, 0x27, }, new uint [] {0x79, 0x59, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x3c, 0x3e, 0x7c, }, + new uint [] {}, }); + table [6] = new KeyboardLayout (1031, "German keyboard layout without dead keys", 0, 1, new uint [][] { + new uint [] {0x5e, 0xffffffb0, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0xffffffa7, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, 0x7b, }, + new uint [] {0x38, 0x28, 0x5b, }, new uint [] {0x39, 0x29, 0x5d, }, + new uint [] {0x30, 0x3d, 0x7d, }, new uint [] {0xffffffdf, 0x3f, 0x5c, }, + new uint [] {0xffffffb4, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x7a, 0x5a, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xfffffffc, 0xffffffdc, }, + new uint [] {0x2b, 0x2a, 0x7e, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xfffffff6, 0xffffffd6, }, new uint [] {0xffffffe4, 0xffffffc4, }, + new uint [] {0x23, 0x27, }, new uint [] {0x79, 0x59, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [7] = new KeyboardLayout (1031, "German keyboard layout for logitech desktop pro", 0, 1, new uint [][] { + new uint [] {0x5e, 0xffffffb0, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0xffffffa7, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, 0x7b, }, + new uint [] {0x38, 0x28, 0x5b, }, new uint [] {0x39, 0x29, 0x5d, }, + new uint [] {0x30, 0x3d, 0x7d, }, new uint [] {0xffffffdf, 0x3f, 0x5c, }, + new uint [] {0x27, 0x60, }, new uint [] {0x71, 0x51, 0x40, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x7a, 0x5a, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xfffffffc, 0xffffffdc, }, + new uint [] {0x2b, 0x2a, 0x7e, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xfffffff6, 0xffffffd6, }, new uint [] {0xffffffe4, 0xffffffc4, }, + new uint [] {0x23, 0x27, }, new uint [] {0x79, 0x59, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x3c, 0x3e, 0x7c, }, + new uint [] {}, }); + table [8] = new KeyboardLayout (1031, "German keyboard layout without dead keys 105", 0, 3, new uint [][] { + new uint [] {0x5e, 0xffffffb0, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, 0xffffffb2, }, new uint [] {0x33, 0xffffffa7, 0xffffffb3, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, 0x7b, }, + new uint [] {0x38, 0x28, 0x5b, }, new uint [] {0x39, 0x29, 0x5d, }, + new uint [] {0x30, 0x3d, 0x7d, }, new uint [] {0xffffffdf, 0x3f, 0x5c, }, + new uint [] {0x27, 0x60, }, new uint [] {0x71, 0x51, 0x40, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x7a, 0x5a, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xfffffffc, 0xffffffdc, }, + new uint [] {0x2b, 0x2a, 0x7e, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xfffffff6, 0xffffffd6, }, new uint [] {0xffffffe4, 0xffffffc4, }, + new uint [] {0x23, 0x27, }, new uint [] {0x3c, 0x3e, 0x7c, }, + new uint [] {0x79, 0x59, }, new uint [] {0x78, 0x58, }, + new uint [] {0x63, 0x43, }, new uint [] {0x76, 0x56, }, + new uint [] {0x62, 0x42, }, new uint [] {0x6e, 0x4e, }, + new uint [] {0x6d, 0x4d, }, new uint [] {0x2c, 0x3b, }, + new uint [] {0x2e, 0x3a, }, new uint [] {0x2d, 0x5f, }, + new uint [] {}, }); + table [9] = new KeyboardLayout (2055, "Swiss German keyboard layout", 0, 1, new uint [][] { + new uint [] {0xffffffa7, 0xffffffb0, }, new uint [] {0x31, 0x2b, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x2a, }, + new uint [] {0x34, 0xffffffe7, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x3d, }, new uint [] {0x27, 0x3f, }, + new uint [] {0x5e, 0x60, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x7a, 0x5a, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xfffffffc, 0xffffffe8, }, + new uint [] {0xffffffa8, 0x21, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xfffffff6, 0xffffffe9, }, new uint [] {0xffffffe4, 0xffffffe0, }, + new uint [] {0x24, 0xffffffa3, }, new uint [] {0x79, 0x59, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [10] = new KeyboardLayout (4108, "Swiss French keyboard layout", 0, 1, new uint [][] { + new uint [] {0xffffffa7, 0xffffffb0, }, new uint [] {0x31, 0x2b, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x2a, }, + new uint [] {0x34, 0xffffffe7, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x3d, }, new uint [] {0x27, 0x3f, }, + new uint [] {0x5e, 0x60, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x7a, 0x5a, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xffffffe8, 0xfffffffc, }, + new uint [] {0xffffffa8, 0x21, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xffffffe9, 0xfffffff6, }, new uint [] {0xffffffe0, 0xffffffe4, }, + new uint [] {0x24, 0xffffffa3, }, new uint [] {0x79, 0x59, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [11] = new KeyboardLayout (1053, "Swedish keyboard layout", 0, 5, new uint [][] { + new uint [] {0xffffffa7, 0xffffffbd, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0xffffffa4, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x3d, }, new uint [] {0x2b, 0x3f, }, + new uint [] {0xffffffb4, 0x60, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xffffffe5, 0xffffffc5, }, + new uint [] {0xffffffa8, 0x5e, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xfffffff6, 0xffffffd6, }, new uint [] {0xffffffe4, 0xffffffc4, }, + new uint [] {0x27, 0x2a, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [12] = new KeyboardLayout (1061, "Estonian keyboard layout", 0, 0, new uint [][] { + new uint [] {0xffffffb7, 0x7e, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0xffffffa4, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x3d, }, new uint [] {0x2b, 0x3f, }, + new uint [] {0xffffffb4, 0x60, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xfffffffc, 0xffffffdc, }, + new uint [] {0xfffffff5, 0xffffffd5, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xfffffff6, 0xffffffd6, }, new uint [] {0xffffffe4, 0xffffffc4, }, + new uint [] {0x27, 0x2a, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [13] = new KeyboardLayout (1044, "Norwegian keyboard layout", 0, 0, new uint [][] { + new uint [] {0x7c, 0xffffffa7, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, 0x40, }, new uint [] {0x33, 0x23, 0xffffffa3, }, + new uint [] {0x34, 0xffffffa4, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, 0x7b, }, + new uint [] {0x38, 0x28, 0x5b, }, new uint [] {0x39, 0x29, 0x5d, }, + new uint [] {0x30, 0x3d, 0x7d, }, new uint [] {0x2b, 0x3f, }, + new uint [] {0x5c, 0x60, 0xffffffb4, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xffffffe5, 0xffffffc5, }, + new uint [] {0xffffffa8, 0x5e, 0x7e, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xfffffff8, 0xffffffd8, }, new uint [] {0xffffffe6, 0xffffffc6, }, + new uint [] {0x27, 0x2a, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [14] = new KeyboardLayout (1030, "Danish keyboard layout", 0, 0, new uint [][] { + new uint [] {0xffffffbd, 0xffffffa7, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0xffffffa4, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x3d, }, new uint [] {0x2b, 0x3f, }, + new uint [] {0xffffffb4, 0x60, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xffffffe5, 0xffffffc5, }, + new uint [] {0xffffffa8, 0x5e, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xffffffe6, 0xffffffc6, }, new uint [] {0xfffffff8, 0xffffffd8, }, + new uint [] {0x27, 0x2a, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [15] = new KeyboardLayout (1036, "French keyboard layout", 0, 4, new uint [][] { + new uint [] {0xffffffb2, }, new uint [] {0x26, 0x31, }, + new uint [] {0xffffffe9, 0x32, 0x7e, }, new uint [] {0x22, 0x33, 0x23, }, + new uint [] {0x27, 0x34, 0x7b, }, new uint [] {0x28, 0x35, 0x5b, }, + new uint [] {0x2d, 0x36, 0x7c, }, new uint [] {0xffffffe8, 0x37, 0x60, }, + new uint [] {0x5f, 0x38, 0x5c, }, new uint [] {0xffffffe7, 0x39, 0x5e, 0xffffffb1, }, + new uint [] {0xffffffe0, 0x30, 0x40, }, new uint [] {0x29, 0xffffffb0, 0x5d, }, + new uint [] {0x3d, 0x2b, 0x7d, }, new uint [] {0x61, 0x41, }, + new uint [] {0x7a, 0x5a, }, new uint [] {0x65, 0x45, 0xffffffbf, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0x5e, 0xffffffa8, }, + new uint [] {0x24, 0xffffffa3, 0xffffffa4, }, new uint [] {0x71, 0x51, }, + new uint [] {0x73, 0x53, 0xffffffdf, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0x6d, 0x4d, }, new uint [] {0xfffffff9, 0x25, }, + new uint [] {0x2a, 0xffffffb5, }, new uint [] {0x77, 0x57, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x2c, 0x3f, }, + new uint [] {0x3b, 0x2e, }, new uint [] {0x3a, 0x2f, }, + new uint [] {0x21, 0xffffffa7, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [16] = new KeyboardLayout (3084, "Canadian French keyboard layout", 0, 0, new uint [][] { + new uint [] {0x23, 0x7c, 0x5c, }, new uint [] {0x31, 0x21, 0xffffffb1, }, + new uint [] {0x32, 0x22, 0x40, }, new uint [] {0x33, 0x2f, 0xffffffa3, }, + new uint [] {0x34, 0x24, 0xffffffa2, }, new uint [] {0x35, 0x25, 0xffffffa4, }, + new uint [] {0x36, 0x3f, 0xffffffac, }, new uint [] {0x37, 0x26, 0xffffffa6, }, + new uint [] {0x38, 0x2a, 0xffffffb2, }, new uint [] {0x39, 0x28, 0xffffffb3, }, + new uint [] {0x30, 0x29, 0xffffffbc, }, new uint [] {0x2d, 0x5f, 0xffffffbd, }, + new uint [] {0x3d, 0x2b, 0xffffffbe, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, 0xffffffa7, }, + new uint [] {0x70, 0x50, 0xffffffb6, }, new uint [] {0x5e, 0x5e, 0x5b, }, + new uint [] {0xffffffb8, 0xffffffa8, 0x5d, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0x3b, 0x3a, 0x7e, }, new uint [] {0x60, 0x60, 0x7b, }, + new uint [] {0x3c, 0x3e, 0x7d, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x27, 0x2d, }, new uint [] {0x2e, }, + new uint [] {0xffffffe9, 0xffffffc9, }, new uint [] {0xffffffab, 0xffffffbb, 0xffffffb0, }, + new uint [] {}, }); + table [17] = new KeyboardLayout (3084, "Canadian French keyboard layout (CA_fr)", 0, 0, new uint [][] { + new uint [] {0x23, 0x7c, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x2f, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x3f, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0x5e, 0x5e, }, + new uint [] {0xffffffb8, 0xffffffa8, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0x3b, 0x3a, }, new uint [] {0x60, 0x60, }, + new uint [] {0x3c, 0x3e, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x27, }, new uint [] {0x2e, }, + new uint [] {0xffffffe9, 0xffffffc9, }, new uint [] {0xffffffab, 0xffffffbb, }, + new uint [] {}, }); + table [18] = new KeyboardLayout (3084, "Canadian keyboard layout", 0, 0, new uint [][] { + new uint [] {0x2f, 0x5c, }, new uint [] {0x31, 0x21, 0xffffffb9, 0xffffffa1, }, + new uint [] {0x32, 0x40, 0xffffffb2, }, new uint [] {0x33, 0x23, 0xffffffb3, 0xffffffa3, }, + new uint [] {0x34, 0x24, 0xffffffbc, 0xffffffa4, }, new uint [] {0x35, 0x25, 0xffffffbd, }, + new uint [] {0x36, 0x3f, 0xffffffbe, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, 0xfffffff8, 0xffffffd8, }, + new uint [] {0x70, 0x50, 0xfffffffe, 0xffffffde, }, new uint [] {0x5e, 0xffffffa8, 0xffffffa8, }, + new uint [] {0xffffffe7, 0xffffffc7, 0x7e, }, new uint [] {0x61, 0x41, 0xffffffe6, 0xffffffc6, }, + new uint [] {0x73, 0x53, 0xffffffdf, 0xffffffa7, }, new uint [] {0x64, 0x44, 0xfffffff0, 0xffffffd0, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0x3b, 0x3a, 0xffffffb4, }, new uint [] {0xffffffe8, 0xffffffc8, }, + new uint [] {0xffffffe0, 0xffffffc0, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, 0xffffffa2, 0xffffffa9, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, 0xffffffb5, 0xffffffba, }, + new uint [] {0x2c, 0x27, }, new uint [] {0x2e, 0x22, 0xffffffb7, 0xfffffff7, }, + new uint [] {0xffffffe9, 0xffffffc9, }, new uint [] {0xfffffff9, 0xffffffd9, }, + new uint [] {}, }); + table [19] = new KeyboardLayout (2060, "Belgian keyboard layout", 0, 4, new uint [][] { + new uint [] {}, new uint [] {0x26, 0x31, 0x7c, }, + new uint [] {0xffffffe9, 0x32, 0x40, }, new uint [] {0x22, 0x33, 0x23, }, + new uint [] {0x27, 0x34, }, new uint [] {0x28, 0x35, }, + new uint [] {0xffffffa7, 0x36, 0x5e, }, new uint [] {0xffffffe8, 0x37, }, + new uint [] {0x21, 0x38, }, new uint [] {0xffffffe7, 0x39, 0x7b, }, + new uint [] {0xffffffe0, 0x30, 0x7d, }, new uint [] {0x29, 0xffffffb0, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x61, 0x41, }, + new uint [] {0x7a, 0x5a, }, new uint [] {0x65, 0x45, 0xffffffa4, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0x5e, 0xffffffa8, 0x5b, }, + new uint [] {0x24, 0x2a, 0x5d, }, new uint [] {0x71, 0x51, }, + new uint [] {0x73, 0x53, 0xffffffdf, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0x6d, 0x4d, }, new uint [] {0xfffffff9, 0x25, 0xffffffb4, }, + new uint [] {0xffffffb5, 0xffffffa3, 0x60, }, new uint [] {0x77, 0x57, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x2c, 0x3f, }, + new uint [] {0x3b, 0x2e, }, new uint [] {0x3a, 0x2f, }, + new uint [] {0x3d, 0x2b, 0x7e, }, new uint [] {0x3c, 0x3e, 0x5c, }, + new uint [] {}, }); + table [20] = new KeyboardLayout (2070, "Portuguese keyboard layout", 0, 0, new uint [][] { + new uint [] {0x5c, 0x7c, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x3d, }, new uint [] {0x27, 0x3f, }, + new uint [] {0xffffffab, 0xffffffbb, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0x2b, 0x2a, }, + new uint [] {0xffffffb4, 0x60, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xffffffe7, 0xffffffc7, }, new uint [] {0xffffffba, 0xffffffaa, }, + new uint [] {0x7e, 0x5e, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [21] = new KeyboardLayout (1046, "Brazilian ABNT-2 keyboard layout", 2, 6, new uint [][] { + new uint [] {0x27, 0x22, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0xffffffa8, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xffffffb4, 0x60, }, + new uint [] {0x5b, 0x7b, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xffffffe7, 0xffffffc7, }, new uint [] {0x7e, 0x5e, }, + new uint [] {0x5d, 0x7d, }, new uint [] {0x5c, 0x7c, }, + new uint [] {0x7a, 0x5a, }, new uint [] {0x78, 0x58, }, + new uint [] {0x63, 0x43, }, new uint [] {0x76, 0x56, }, + new uint [] {0x62, 0x42, }, new uint [] {0x6e, 0x4e, }, + new uint [] {0x6d, 0x4d, }, new uint [] {0x2c, 0x3c, }, + new uint [] {0x2e, 0x3e, }, new uint [] {0x3b, 0x3a, }, + new uint [] {0x2f, 0x3f, }, }); + table [22] = new KeyboardLayout (1046, "Brazilian ABNT-2 keyboard layout ALT GR", 2, 6, new uint [][] { + new uint [] {0x27, 0x22, }, new uint [] {0x31, 0x21, 0x39, }, + new uint [] {0x32, 0x40, 0x32, }, new uint [] {0x33, 0x23, 0x33, }, + new uint [] {0x34, 0x24, 0x23, }, new uint [] {0x35, 0x25, 0x22, }, + new uint [] {0x36, 0x28, 0x2c, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, 0x27, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0x34, 0x60, }, + new uint [] {0x5b, 0x7b, 0x2a, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0x67, 0x47, }, new uint [] {0x7e, 0x5e, }, + new uint [] {0x5d, 0x7d, 0x3a, }, new uint [] {0x5c, 0x7c, }, + new uint [] {0x7a, 0x5a, }, new uint [] {0x78, 0x58, }, + new uint [] {0x63, 0x43, }, new uint [] {0x76, 0x56, }, + new uint [] {0x62, 0x42, }, new uint [] {0x6e, 0x4e, }, + new uint [] {0x6d, 0x4d, }, new uint [] {0x2c, 0x3c, }, + new uint [] {0x2e, 0x3e, }, new uint [] {0x3b, 0x3a, }, + new uint [] {0x2f, 0x3f, 0x30, }, }); + table [23] = new KeyboardLayout (1035, "Finnish keyboard layout", 0, 0, new uint [][] { + new uint [] {0xffffffa7, 0xffffffbd, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0xffffffa4, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x3d, }, new uint [] {0x2b, 0x3f, }, + new uint [] {0xffffffb4, 0x60, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xffffffe5, 0xffffffc5, }, + new uint [] {0xffffffa8, 0x5e, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xfffffff6, 0xffffffd6, }, new uint [] {0xffffffe4, 0xffffffc4, }, + new uint [] {0x27, 0x2a, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [24] = new KeyboardLayout (1026, "Bulgarian bds keyboard layout", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, 0x28, 0x29, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, 0x32, 0x3f, }, new uint [] {0x33, 0x23, 0x33, 0x2b, }, + new uint [] {0x34, 0x24, 0x34, 0x22, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, 0x36, 0x3d, }, new uint [] {0x37, 0x26, 0x37, 0x3a, }, + new uint [] {0x38, 0x2a, 0x38, 0x2f, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, 0x2d, 0x49, }, + new uint [] {0x3d, 0x2b, 0x2e, 0x56, }, new uint [] {0x71, 0x51, 0x2c, 0xfffffffb, }, + new uint [] {0x77, 0x57, 0xfffffff3, 0xffffffd3, }, new uint [] {0x65, 0x45, 0xffffffe5, 0xffffffc5, }, + new uint [] {0x72, 0x52, 0xffffffe8, 0xffffffc8, }, new uint [] {0x74, 0x54, 0xfffffff8, 0xffffffd8, }, + new uint [] {0x79, 0x59, 0xfffffff9, 0xffffffd9, }, new uint [] {0x75, 0x55, 0xffffffea, 0xffffffca, }, + new uint [] {0x69, 0x49, 0xfffffff1, 0xffffffd1, }, new uint [] {0x6f, 0x4f, 0xffffffe4, 0xffffffc4, }, + new uint [] {0x70, 0x50, 0xffffffe7, 0xffffffc7, }, new uint [] {0x5b, 0x7b, 0xfffffff6, 0xffffffd6, }, + new uint [] {0x5d, 0x7d, 0x3b, }, new uint [] {0x61, 0x41, 0xfffffffc, 0xffffffdc, }, + new uint [] {0x73, 0x53, 0xffffffff, 0xffffffdf, }, new uint [] {0x64, 0x44, 0xffffffe0, 0xffffffc0, }, + new uint [] {0x66, 0x46, 0xffffffee, 0xffffffce, }, new uint [] {0x67, 0x47, 0xffffffe6, 0xffffffc6, }, + new uint [] {0x68, 0x48, 0xffffffe3, 0xffffffc3, }, new uint [] {0x6a, 0x4a, 0xfffffff2, 0xffffffd2, }, + new uint [] {0x6b, 0x4b, 0xffffffed, 0xffffffcd, }, new uint [] {0x6c, 0x4c, 0xffffffe2, 0xffffffc2, }, + new uint [] {0x3b, 0x3a, 0xffffffec, 0xffffffcc, }, new uint [] {0x27, 0x22, 0xfffffff7, 0xffffffd7, }, + new uint [] {0x5c, 0x7c, 0x27, 0xffffffdb, }, new uint [] {0x7a, 0x5a, 0xfffffffe, 0xffffffde, }, + new uint [] {0x78, 0x58, 0xffffffe9, 0xffffffc9, }, new uint [] {0x63, 0x43, 0xfffffffa, 0xffffffda, }, + new uint [] {0x76, 0x56, 0xfffffffd, 0xffffffdd, }, new uint [] {0x62, 0x42, 0xfffffff4, 0xffffffd4, }, + new uint [] {0x6e, 0x4e, 0xfffffff5, 0xffffffd5, }, new uint [] {0x6d, 0x4d, 0xffffffef, 0xffffffcf, }, + new uint [] {0x2c, 0x3c, 0xfffffff0, 0xffffffd0, }, new uint [] {0x2e, 0x3e, 0xffffffeb, 0xffffffcb, }, + new uint [] {0x2f, 0x3f, 0xffffffe1, 0xffffffc1, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [25] = new KeyboardLayout (1026, "Bulgarian phonetic keyboard layout", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, 0xfffffff7, 0xffffffd7, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, 0xffffffff, 0xffffffdf, }, + new uint [] {0x77, 0x57, 0xffffffe2, 0xffffffc2, }, new uint [] {0x65, 0x45, 0xffffffe5, 0xffffffc5, }, + new uint [] {0x72, 0x52, 0xfffffff0, 0xffffffd0, }, new uint [] {0x74, 0x54, 0xfffffff2, 0xffffffd2, }, + new uint [] {0x79, 0x59, 0xfffffffa, 0xffffffda, }, new uint [] {0x75, 0x55, 0xfffffff3, 0xffffffd3, }, + new uint [] {0x69, 0x49, 0xffffffe8, 0xffffffc8, }, new uint [] {0x6f, 0x4f, 0xffffffee, 0xffffffce, }, + new uint [] {0x70, 0x50, 0xffffffef, 0xffffffcf, }, new uint [] {0x5b, 0x7b, 0xfffffff8, 0xffffffd8, }, + new uint [] {0x5d, 0x7d, 0xfffffff9, 0xffffffd9, }, new uint [] {0x61, 0x41, 0xffffffe0, 0xffffffc0, }, + new uint [] {0x73, 0x53, 0xfffffff1, 0xffffffd1, }, new uint [] {0x64, 0x44, 0xffffffe4, 0xffffffc4, }, + new uint [] {0x66, 0x46, 0xfffffff4, 0xffffffd4, }, new uint [] {0x67, 0x47, 0xffffffe3, 0xffffffc3, }, + new uint [] {0x68, 0x48, 0xfffffff5, 0xffffffd5, }, new uint [] {0x6a, 0x4a, 0xffffffe9, 0xffffffc9, }, + new uint [] {0x6b, 0x4b, 0xffffffea, 0xffffffca, }, new uint [] {0x6c, 0x4c, 0xffffffeb, 0xffffffcb, }, + new uint [] {0x3b, 0x3a, }, new uint [] {0x27, 0x22, }, + new uint [] {0x5c, 0x7c, 0xfffffffe, 0xffffffde, }, new uint [] {0x7a, 0x5a, 0xffffffe7, 0xffffffc7, }, + new uint [] {0x78, 0x58, 0xfffffffc, 0xffffffdc, }, new uint [] {0x63, 0x43, 0xfffffff6, 0xffffffd6, }, + new uint [] {0x76, 0x56, 0xffffffe6, 0xffffffc6, }, new uint [] {0x62, 0x42, 0xffffffe1, 0xffffffc1, }, + new uint [] {0x6e, 0x4e, 0xffffffed, 0xffffffcd, }, new uint [] {0x6d, 0x4d, 0xffffffec, 0xffffffcc, }, + new uint [] {0x2c, 0x3c, }, new uint [] {0x2e, 0x3e, }, + new uint [] {0x2f, 0x3f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [26] = new KeyboardLayout (1059, "Belarusian keyboard layout", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, 0xffffffa3, 0xffffffb3, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, 0xffffffca, 0xffffffea, }, + new uint [] {0x77, 0x57, 0xffffffc3, 0xffffffe3, }, new uint [] {0x65, 0x45, 0xffffffd5, 0xfffffff5, }, + new uint [] {0x72, 0x52, 0xffffffcb, 0xffffffeb, }, new uint [] {0x74, 0x54, 0xffffffc5, 0xffffffe5, }, + new uint [] {0x79, 0x59, 0xffffffce, 0xffffffee, }, new uint [] {0x75, 0x55, 0xffffffc7, 0xffffffe7, }, + new uint [] {0x69, 0x49, 0xffffffdb, 0xfffffffb, }, new uint [] {0x6f, 0x4f, 0xffffffae, 0xffffffbe, }, + new uint [] {0x70, 0x50, 0xffffffda, 0xfffffffa, }, new uint [] {0x5b, 0x7b, 0xffffffc8, 0xffffffe8, }, + new uint [] {0x5d, 0x7d, 0x27, 0x27, }, new uint [] {0x61, 0x41, 0xffffffc6, 0xffffffe6, }, + new uint [] {0x73, 0x53, 0xffffffd9, 0xfffffff9, }, new uint [] {0x64, 0x44, 0xffffffd7, 0xfffffff7, }, + new uint [] {0x66, 0x46, 0xffffffc1, 0xffffffe1, }, new uint [] {0x67, 0x47, 0xffffffd0, 0xfffffff0, }, + new uint [] {0x68, 0x48, 0xffffffd2, 0xfffffff2, }, new uint [] {0x6a, 0x4a, 0xffffffcf, 0xffffffef, }, + new uint [] {0x6b, 0x4b, 0xffffffcc, 0xffffffec, }, new uint [] {0x6c, 0x4c, 0xffffffc4, 0xffffffe4, }, + new uint [] {0x3b, 0x3a, 0xffffffd6, 0xfffffff6, }, new uint [] {0x27, 0x22, 0xffffffdc, 0xfffffffc, }, + new uint [] {0x5c, 0x7c, 0x2f, 0x7c, }, new uint [] {0x7a, 0x5a, 0xffffffd1, 0xfffffff1, }, + new uint [] {0x78, 0x58, 0xffffffde, 0xfffffffe, }, new uint [] {0x63, 0x43, 0xffffffd3, 0xfffffff3, }, + new uint [] {0x76, 0x56, 0xffffffcd, 0xffffffed, }, new uint [] {0x62, 0x42, 0xffffffa6, 0xffffffb6, }, + new uint [] {0x6e, 0x4e, 0xffffffd4, 0xfffffff4, }, new uint [] {0x6d, 0x4d, 0xffffffd8, 0xfffffff8, }, + new uint [] {0x2c, 0x3c, 0xffffffc2, 0xffffffe2, }, new uint [] {0x2e, 0x3e, 0xffffffc0, 0xffffffe0, }, + new uint [] {0x2f, 0x3f, 0x2e, 0x2c, }, new uint [] {0x3c, 0x3e, 0x7c, 0xffffffa6, }, + new uint [] {}, }); + table [27] = new KeyboardLayout (1049, "Russian keyboard layout", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, 0xffffffca, 0xffffffea, }, + new uint [] {0x77, 0x57, 0xffffffc3, 0xffffffe3, }, new uint [] {0x65, 0x45, 0xffffffd5, 0xfffffff5, }, + new uint [] {0x72, 0x52, 0xffffffcb, 0xffffffeb, }, new uint [] {0x74, 0x54, 0xffffffc5, 0xffffffe5, }, + new uint [] {0x79, 0x59, 0xffffffce, 0xffffffee, }, new uint [] {0x75, 0x55, 0xffffffc7, 0xffffffe7, }, + new uint [] {0x69, 0x49, 0xffffffdb, 0xfffffffb, }, new uint [] {0x6f, 0x4f, 0xffffffdd, 0xfffffffd, }, + new uint [] {0x70, 0x50, 0xffffffda, 0xfffffffa, }, new uint [] {0x5b, 0x7b, 0xffffffc8, 0xffffffe8, }, + new uint [] {0x5d, 0x7d, 0xffffffdf, 0xffffffff, }, new uint [] {0x61, 0x41, 0xffffffc6, 0xffffffe6, }, + new uint [] {0x73, 0x53, 0xffffffd9, 0xfffffff9, }, new uint [] {0x64, 0x44, 0xffffffd7, 0xfffffff7, }, + new uint [] {0x66, 0x46, 0xffffffc1, 0xffffffe1, }, new uint [] {0x67, 0x47, 0xffffffd0, 0xfffffff0, }, + new uint [] {0x68, 0x48, 0xffffffd2, 0xfffffff2, }, new uint [] {0x6a, 0x4a, 0xffffffcf, 0xffffffef, }, + new uint [] {0x6b, 0x4b, 0xffffffcc, 0xffffffec, }, new uint [] {0x6c, 0x4c, 0xffffffc4, 0xffffffe4, }, + new uint [] {0x3b, 0x3a, 0xffffffd6, 0xfffffff6, }, new uint [] {0x27, 0x22, 0xffffffdc, 0xfffffffc, }, + new uint [] {0x5c, 0x7c, }, new uint [] {0x7a, 0x5a, 0xffffffd1, 0xfffffff1, }, + new uint [] {0x78, 0x58, 0xffffffde, 0xfffffffe, }, new uint [] {0x63, 0x43, 0xffffffd3, 0xfffffff3, }, + new uint [] {0x76, 0x56, 0xffffffcd, 0xffffffed, }, new uint [] {0x62, 0x42, 0xffffffc9, 0xffffffe9, }, + new uint [] {0x6e, 0x4e, 0xffffffd4, 0xfffffff4, }, new uint [] {0x6d, 0x4d, 0xffffffd8, 0xfffffff8, }, + new uint [] {0x2c, 0x3c, 0xffffffc2, 0xffffffe2, }, new uint [] {0x2e, 0x3e, 0xffffffc0, 0xffffffe0, }, + new uint [] {0x2f, 0x3f, }, new uint [] {}, + new uint [] {}, }); + table [28] = new KeyboardLayout (1049, "Russian keyboard layout (phantom key version)", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, 0xffffffca, 0xffffffea, }, + new uint [] {0x77, 0x57, 0xffffffc3, 0xffffffe3, }, new uint [] {0x65, 0x45, 0xffffffd5, 0xfffffff5, }, + new uint [] {0x72, 0x52, 0xffffffcb, 0xffffffeb, }, new uint [] {0x74, 0x54, 0xffffffc5, 0xffffffe5, }, + new uint [] {0x79, 0x59, 0xffffffce, 0xffffffee, }, new uint [] {0x75, 0x55, 0xffffffc7, 0xffffffe7, }, + new uint [] {0x69, 0x49, 0xffffffdb, 0xfffffffb, }, new uint [] {0x6f, 0x4f, 0xffffffdd, 0xfffffffd, }, + new uint [] {0x70, 0x50, 0xffffffda, 0xfffffffa, }, new uint [] {0x5b, 0x7b, 0xffffffc8, 0xffffffe8, }, + new uint [] {0x5d, 0x7d, 0xffffffdf, 0xffffffff, }, new uint [] {0x61, 0x41, 0xffffffc6, 0xffffffe6, }, + new uint [] {0x73, 0x53, 0xffffffd9, 0xfffffff9, }, new uint [] {0x64, 0x44, 0xffffffd7, 0xfffffff7, }, + new uint [] {0x66, 0x46, 0xffffffc1, 0xffffffe1, }, new uint [] {0x67, 0x47, 0xffffffd0, 0xfffffff0, }, + new uint [] {0x68, 0x48, 0xffffffd2, 0xfffffff2, }, new uint [] {0x6a, 0x4a, 0xffffffcf, 0xffffffef, }, + new uint [] {0x6b, 0x4b, 0xffffffcc, 0xffffffec, }, new uint [] {0x6c, 0x4c, 0xffffffc4, 0xffffffe4, }, + new uint [] {0x3b, 0x3a, 0xffffffd6, 0xfffffff6, }, new uint [] {0x27, 0x22, 0xffffffdc, 0xfffffffc, }, + new uint [] {0x5c, 0x7c, }, new uint [] {0x7a, 0x5a, 0xffffffd1, 0xfffffff1, }, + new uint [] {0x78, 0x58, 0xffffffde, 0xfffffffe, }, new uint [] {0x63, 0x43, 0xffffffd3, 0xfffffff3, }, + new uint [] {0x76, 0x56, 0xffffffcd, 0xffffffed, }, new uint [] {0x62, 0x42, 0xffffffc9, 0xffffffe9, }, + new uint [] {0x6e, 0x4e, 0xffffffd4, 0xfffffff4, }, new uint [] {0x6d, 0x4d, 0xffffffd8, 0xfffffff8, }, + new uint [] {0x2c, 0x3c, 0xffffffc2, 0xffffffe2, }, new uint [] {0x2e, 0x3e, 0xffffffc0, 0xffffffe0, }, + new uint [] {0x2f, 0x3f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [29] = new KeyboardLayout (1049, "Russian keyboard layout KOI8-R", 0, 0, new uint [][] { + new uint [] {0x28, 0x29, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x2f, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x3a, }, + new uint [] {0x36, 0x2c, }, new uint [] {0x37, 0x2e, }, + new uint [] {0x38, 0x3b, }, new uint [] {0x39, 0x3f, }, + new uint [] {0x30, 0x25, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0xffffffca, 0xffffffea, }, + new uint [] {0xffffffc3, 0xffffffe3, }, new uint [] {0xffffffd5, 0xfffffff5, }, + new uint [] {0xffffffcb, 0xffffffeb, }, new uint [] {0xffffffc5, 0xffffffe5, }, + new uint [] {0xffffffce, 0xffffffee, }, new uint [] {0xffffffc7, 0xffffffe7, }, + new uint [] {0xffffffdb, 0xfffffffb, }, new uint [] {0xffffffdd, 0xfffffffd, }, + new uint [] {0xffffffda, 0xfffffffa, }, new uint [] {0xffffffc8, 0xffffffe8, }, + new uint [] {0xffffffdf, 0xffffffff, }, new uint [] {0xffffffc6, 0xffffffe6, }, + new uint [] {0xffffffd9, 0xfffffff9, }, new uint [] {0xffffffd7, 0xfffffff7, }, + new uint [] {0xffffffc1, 0xffffffe1, }, new uint [] {0xffffffd0, 0xfffffff0, }, + new uint [] {0xffffffd2, 0xfffffff2, }, new uint [] {0xffffffcf, 0xffffffef, }, + new uint [] {0xffffffcc, 0xffffffec, }, new uint [] {0xffffffc4, 0xffffffe4, }, + new uint [] {0xffffffd6, 0xfffffff6, }, new uint [] {0xffffffdc, 0xfffffffc, }, + new uint [] {0x5c, 0x7c, }, new uint [] {0xffffffd1, 0xfffffff1, }, + new uint [] {0xffffffde, 0xfffffffe, }, new uint [] {0xffffffd3, 0xfffffff3, }, + new uint [] {0xffffffcd, 0xffffffed, }, new uint [] {0xffffffc9, 0xffffffe9, }, + new uint [] {0xffffffd4, 0xfffffff4, }, new uint [] {0xffffffd8, 0xfffffff8, }, + new uint [] {0xffffffc2, 0xffffffe2, }, new uint [] {0xffffffc0, 0xffffffe0, }, + new uint [] {0x2f, 0x3f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [30] = new KeyboardLayout (1049, "Russian keyboard layout cp1251", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, 0xffffffe9, 0xffffffc9, }, + new uint [] {0x77, 0x57, 0xfffffff6, 0xffffffd6, }, new uint [] {0x65, 0x45, 0xfffffff3, 0xffffffd3, }, + new uint [] {0x72, 0x52, 0xffffffea, 0xffffffca, }, new uint [] {0x74, 0x54, 0xffffffe5, 0xffffffc5, }, + new uint [] {0x79, 0x59, 0xffffffed, 0xffffffcd, }, new uint [] {0x75, 0x55, 0xffffffe3, 0xffffffc3, }, + new uint [] {0x69, 0x49, 0xfffffff8, 0xffffffd8, }, new uint [] {0x6f, 0x4f, 0xfffffff9, 0xffffffd9, }, + new uint [] {0x70, 0x50, 0xffffffe7, 0xffffffc7, }, new uint [] {0x5b, 0x7b, 0xfffffff5, 0xffffffd5, }, + new uint [] {0x5d, 0x7d, 0xfffffffa, 0xffffffda, }, new uint [] {0x61, 0x41, 0xfffffff4, 0xffffffd4, }, + new uint [] {0x73, 0x53, 0xfffffffb, 0xffffffdb, }, new uint [] {0x64, 0x44, 0xffffffe2, 0xffffffc2, }, + new uint [] {0x66, 0x46, 0xffffffe0, 0xffffffc0, }, new uint [] {0x67, 0x47, 0xffffffef, 0xffffffcf, }, + new uint [] {0x68, 0x48, 0xfffffff0, 0xffffffd0, }, new uint [] {0x6a, 0x4a, 0xffffffee, 0xffffffce, }, + new uint [] {0x6b, 0x4b, 0xffffffeb, 0xffffffcb, }, new uint [] {0x6c, 0x4c, 0xffffffe4, 0xffffffc4, }, + new uint [] {0x3b, 0x3a, 0xffffffe6, 0xffffffc6, }, new uint [] {0x27, 0x22, 0xfffffffd, 0xffffffdd, }, + new uint [] {0x5c, 0x7c, }, new uint [] {0x7a, 0x5a, 0xffffffff, 0xffffffdf, }, + new uint [] {0x78, 0x58, 0xfffffff7, 0xffffffd7, }, new uint [] {0x63, 0x43, 0xfffffff1, 0xffffffd1, }, + new uint [] {0x76, 0x56, 0xffffffec, 0xffffffcc, }, new uint [] {0x62, 0x42, 0xffffffe8, 0xffffffc8, }, + new uint [] {0x6e, 0x4e, 0xfffffff2, 0xffffffd2, }, new uint [] {0x6d, 0x4d, 0xfffffffc, 0xffffffdc, }, + new uint [] {0x2c, 0x3c, 0xffffffe1, 0xffffffc1, }, new uint [] {0x2e, 0x3e, 0xfffffffe, 0xffffffde, }, + new uint [] {0x2f, 0x3f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [31] = new KeyboardLayout (1049, "Russian phonetic keyboard layout", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, 0xffffffd1, 0xfffffff1, }, + new uint [] {0x77, 0x57, 0xffffffd7, 0xfffffff7, }, new uint [] {0x65, 0x45, 0xffffffc5, 0xffffffe5, }, + new uint [] {0x72, 0x52, 0xffffffd2, 0xfffffff2, }, new uint [] {0x74, 0x54, 0xffffffd4, 0xfffffff4, }, + new uint [] {0x79, 0x59, 0xffffffd9, 0xfffffff9, }, new uint [] {0x75, 0x55, 0xffffffd5, 0xfffffff5, }, + new uint [] {0x69, 0x49, 0xffffffc9, 0xffffffe9, }, new uint [] {0x6f, 0x4f, 0xffffffcf, 0xffffffef, }, + new uint [] {0x70, 0x50, 0xffffffd0, 0xfffffff0, }, new uint [] {0x5b, 0x7b, 0xffffffdb, 0xfffffffb, }, + new uint [] {0x5d, 0x7d, 0xffffffdd, 0xfffffffd, }, new uint [] {0x61, 0x41, 0xffffffc1, 0xffffffe1, }, + new uint [] {0x73, 0x53, 0xffffffd3, 0xfffffff3, }, new uint [] {0x64, 0x44, 0xffffffc4, 0xffffffe4, }, + new uint [] {0x66, 0x46, 0xffffffc6, 0xffffffe6, }, new uint [] {0x67, 0x47, 0xffffffc7, 0xffffffe7, }, + new uint [] {0x68, 0x48, 0xffffffc8, 0xffffffe8, }, new uint [] {0x6a, 0x4a, 0xffffffca, 0xffffffea, }, + new uint [] {0x6b, 0x4b, 0xffffffcb, 0xffffffeb, }, new uint [] {0x6c, 0x4c, 0xffffffcc, 0xffffffec, }, + new uint [] {0x3b, 0x3a, }, new uint [] {0x27, 0x22, }, + new uint [] {0x5c, 0x7c, }, new uint [] {0x7a, 0x5a, 0xffffffda, 0xfffffffa, }, + new uint [] {0x78, 0x58, 0xffffffd8, 0xfffffff8, }, new uint [] {0x63, 0x43, 0xffffffc3, 0xffffffe3, }, + new uint [] {0x76, 0x56, 0xffffffd6, 0xfffffff6, }, new uint [] {0x62, 0x42, 0xffffffc2, 0xffffffe2, }, + new uint [] {0x6e, 0x4e, 0xffffffce, 0xffffffee, }, new uint [] {0x6d, 0x4d, 0xffffffcd, 0xffffffed, }, + new uint [] {0x2c, 0x3c, }, new uint [] {0x2e, 0x3e, }, + new uint [] {0x2f, 0x3f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [32] = new KeyboardLayout (1058, "Ukrainian keyboard layout KOI8-U", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, 0xffffffad, 0xffffffbd, }, new uint [] {0x31, 0x21, 0x31, 0x21, }, + new uint [] {0x32, 0x40, 0x32, 0x22, }, new uint [] {0x33, 0x23, 0x33, 0x27, }, + new uint [] {0x34, 0x24, 0x34, 0x2a, }, new uint [] {0x35, 0x25, 0x35, 0x3a, }, + new uint [] {0x36, 0x5e, 0x36, 0x2c, }, new uint [] {0x37, 0x26, 0x37, 0x2e, }, + new uint [] {0x38, 0x2a, 0x38, 0x3b, }, new uint [] {0x39, 0x28, 0x39, 0x28, }, + new uint [] {0x30, 0x29, 0x30, 0x29, }, new uint [] {0x2d, 0x5f, 0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, 0x3d, 0x2b, }, new uint [] {0x71, 0x51, 0xffffffca, 0xffffffea, }, + new uint [] {0x77, 0x57, 0xffffffc3, 0xffffffe3, }, new uint [] {0x65, 0x45, 0xffffffd5, 0xfffffff5, }, + new uint [] {0x72, 0x52, 0xffffffcb, 0xffffffeb, }, new uint [] {0x74, 0x54, 0xffffffc5, 0xffffffe5, }, + new uint [] {0x79, 0x59, 0xffffffce, 0xffffffee, }, new uint [] {0x75, 0x55, 0xffffffc7, 0xffffffe7, }, + new uint [] {0x69, 0x49, 0xffffffdb, 0xfffffffb, }, new uint [] {0x6f, 0x4f, 0xffffffdd, 0xfffffffd, }, + new uint [] {0x70, 0x50, 0xffffffda, 0xfffffffa, }, new uint [] {0x5b, 0x7b, 0xffffffc8, 0xffffffe8, }, + new uint [] {0x5d, 0x7d, 0xffffffa7, 0xffffffb7, }, new uint [] {0x61, 0x41, 0xffffffc6, 0xffffffe6, }, + new uint [] {0x73, 0x53, 0xffffffa6, 0xffffffb6, }, new uint [] {0x64, 0x44, 0xffffffd7, 0xfffffff7, }, + new uint [] {0x66, 0x46, 0xffffffc1, 0xffffffe1, }, new uint [] {0x67, 0x47, 0xffffffd0, 0xfffffff0, }, + new uint [] {0x68, 0x48, 0xffffffd2, 0xfffffff2, }, new uint [] {0x6a, 0x4a, 0xffffffcf, 0xffffffef, }, + new uint [] {0x6b, 0x4b, 0xffffffcc, 0xffffffec, }, new uint [] {0x6c, 0x4c, 0xffffffc4, 0xffffffe4, }, + new uint [] {0x3b, 0x3a, 0xffffffd6, 0xfffffff6, }, new uint [] {0x27, 0x22, 0xffffffa4, 0xffffffb4, }, + new uint [] {0x5c, 0x7c, 0x5c, 0x7c, }, new uint [] {0x7a, 0x5a, 0xffffffd1, 0xfffffff1, }, + new uint [] {0x78, 0x58, 0xffffffde, 0xfffffffe, }, new uint [] {0x63, 0x43, 0xffffffd3, 0xfffffff3, }, + new uint [] {0x76, 0x56, 0xffffffcd, 0xffffffed, }, new uint [] {0x62, 0x42, 0xffffffc9, 0xffffffe9, }, + new uint [] {0x6e, 0x4e, 0xffffffd4, 0xfffffff4, }, new uint [] {0x6d, 0x4d, 0xffffffd8, 0xfffffff8, }, + new uint [] {0x2c, 0x3c, 0xffffffc2, 0xffffffe2, }, new uint [] {0x2e, 0x3e, 0xffffffc0, 0xffffffe0, }, + new uint [] {0x2f, 0x3f, 0x2f, 0x3f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [33] = new KeyboardLayout (1058, "Ukrainian keyboard layout (standard)", 0, 0, new uint [][] { + new uint [] {0xffffffad, 0xffffffbd, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x27, }, + new uint [] {0x34, 0x3b, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x3a, }, new uint [] {0x37, 0x3f, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0xffffffca, 0xffffffea, }, + new uint [] {0xffffffc3, 0xffffffe3, }, new uint [] {0xffffffd5, 0xfffffff5, }, + new uint [] {0xffffffcb, 0xffffffeb, }, new uint [] {0xffffffc5, 0xffffffe5, }, + new uint [] {0xffffffce, 0xffffffee, }, new uint [] {0xffffffc7, 0xffffffe7, }, + new uint [] {0xffffffdb, 0xfffffffb, }, new uint [] {0xffffffdd, 0xfffffffd, }, + new uint [] {0xffffffda, 0xfffffffa, }, new uint [] {0xffffffc8, 0xffffffe8, }, + new uint [] {0xffffffa7, 0xffffffb7, }, new uint [] {0xffffffc6, 0xffffffe6, }, + new uint [] {0xffffffa6, 0xffffffb6, }, new uint [] {0xffffffd7, 0xfffffff7, }, + new uint [] {0xffffffc1, 0xffffffe1, }, new uint [] {0xffffffd0, 0xfffffff0, }, + new uint [] {0xffffffd2, 0xfffffff2, }, new uint [] {0xffffffcf, 0xffffffef, }, + new uint [] {0xffffffcc, 0xffffffec, }, new uint [] {0xffffffc4, 0xffffffe4, }, + new uint [] {0xffffffd6, 0xfffffff6, }, new uint [] {0xffffffa4, 0xffffffb4, }, + new uint [] {0x5c, 0x2f, }, new uint [] {0xffffffd1, 0xfffffff1, }, + new uint [] {0xffffffde, 0xfffffffe, }, new uint [] {0xffffffd3, 0xfffffff3, }, + new uint [] {0xffffffcd, 0xffffffed, }, new uint [] {0xffffffc9, 0xffffffe9, }, + new uint [] {0xffffffd4, 0xfffffff4, }, new uint [] {0xffffffd8, 0xfffffff8, }, + new uint [] {0xffffffc2, 0xffffffe2, }, new uint [] {0xffffffc0, 0xffffffe0, }, + new uint [] {0x2e, 0x2c, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [34] = new KeyboardLayout (1049, "Russian keyboard layout (standard)", 0, 0, new uint [][] { + new uint [] {0xffffffa3, 0xffffffb3, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x27, }, + new uint [] {0x34, 0x3b, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x3a, }, new uint [] {0x37, 0x3f, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0xffffffca, 0xffffffea, }, + new uint [] {0xffffffc3, 0xffffffe3, }, new uint [] {0xffffffd5, 0xfffffff5, }, + new uint [] {0xffffffcb, 0xffffffeb, }, new uint [] {0xffffffc5, 0xffffffe5, }, + new uint [] {0xffffffce, 0xffffffee, }, new uint [] {0xffffffc7, 0xffffffe7, }, + new uint [] {0xffffffdb, 0xfffffffb, }, new uint [] {0xffffffdd, 0xfffffffd, }, + new uint [] {0xffffffda, 0xfffffffa, }, new uint [] {0xffffffc8, 0xffffffe8, }, + new uint [] {0xffffffdf, 0xffffffff, }, new uint [] {0xffffffc6, 0xffffffe6, }, + new uint [] {0xffffffd9, 0xfffffff9, }, new uint [] {0xffffffd7, 0xfffffff7, }, + new uint [] {0xffffffc1, 0xffffffe1, }, new uint [] {0xffffffd0, 0xfffffff0, }, + new uint [] {0xffffffd2, 0xfffffff2, }, new uint [] {0xffffffcf, 0xffffffef, }, + new uint [] {0xffffffcc, 0xffffffec, }, new uint [] {0xffffffc4, 0xffffffe4, }, + new uint [] {0xffffffd6, 0xfffffff6, }, new uint [] {0xffffffdc, 0xfffffffc, }, + new uint [] {0x5c, 0x2f, }, new uint [] {0xffffffd1, 0xfffffff1, }, + new uint [] {0xffffffde, 0xfffffffe, }, new uint [] {0xffffffd3, 0xfffffff3, }, + new uint [] {0xffffffcd, 0xffffffed, }, new uint [] {0xffffffc9, 0xffffffe9, }, + new uint [] {0xffffffd4, 0xfffffff4, }, new uint [] {0xffffffd8, 0xfffffff8, }, + new uint [] {0xffffffc2, 0xffffffe2, }, new uint [] {0xffffffc0, 0xffffffe0, }, + new uint [] {0x2e, 0x2c, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [35] = new KeyboardLayout (1034, "Spanish keyboard layout", 0, 0, new uint [][] { + new uint [] {0xffffffba, 0xffffffaa, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0xffffffb7, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x3d, }, new uint [] {0x27, 0x3f, }, + new uint [] {0xffffffa1, 0xffffffbf, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0x60, 0x5e, }, + new uint [] {0x2b, 0x2a, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xfffffff1, 0xffffffd1, }, new uint [] {0xffffffb4, 0xffffffa8, }, + new uint [] {0xffffffe7, 0xffffffc7, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [36] = new KeyboardLayout (1040, "Italian keyboard layout", 0, 0, new uint [][] { + new uint [] {0x5c, 0x7c, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0xffffffa3, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x3d, }, new uint [] {0x27, 0x3f, }, + new uint [] {0xffffffec, 0x5e, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xffffffe8, 0xffffffe9, }, + new uint [] {0x2b, 0x2a, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xfffffff2, 0xffffffe7, }, new uint [] {0xffffffe0, 0xffffffb0, }, + new uint [] {0xfffffff9, 0xffffffa7, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [37] = new KeyboardLayout (1039, "Icelandic keyboard layout", 0, 0, new uint [][] { + new uint [] {0xffffffb0, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x3d, }, new uint [] {0xfffffff6, 0xffffffd6, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xfffffff0, 0xffffffd0, }, + new uint [] {0x27, 0x3f, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xffffffe6, 0xffffffc6, }, new uint [] {0xffffffb4, 0xffffffc4, }, + new uint [] {0x2b, 0x2a, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0xfffffffe, 0xffffffde, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [38] = new KeyboardLayout (1038, "Hungarian keyboard layout", 0, 1, new uint [][] { + new uint [] {0x30, 0xffffffa7, }, new uint [] {0x31, 0x27, 0x7e, }, + new uint [] {0x32, 0x22, 0xffffffb7, }, new uint [] {0x33, 0x2b, 0x5e, }, + new uint [] {0x34, 0x21, 0xffffffa2, }, new uint [] {0x35, 0x25, 0x30, 0xffffffb0, }, + new uint [] {0x36, 0x2f, 0xffffffb2, }, new uint [] {0x37, 0x3d, 0x60, }, + new uint [] {0x38, 0x28, 0xffffffff, }, new uint [] {0x39, 0x29, 0xffffffb4, }, + new uint [] {0xfffffff6, 0xffffffd6, 0xffffffbd, }, new uint [] {0xfffffffc, 0xffffffdc, 0xffffffa8, }, + new uint [] {0xfffffff3, 0xffffffd3, 0xffffffb8, }, new uint [] {0x71, 0x51, 0x5c, }, + new uint [] {0x77, 0x57, 0x7c, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x7a, 0x5a, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, 0xffffffcd, }, new uint [] {0x6f, 0x4f, 0xfffffff8, }, + new uint [] {0x70, 0x50, }, new uint [] {0xfffffff5, 0xffffffd5, 0xfffffff7, }, + new uint [] {0xfffffffa, 0xffffffda, 0xffffffd7, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, 0xfffffff0, }, new uint [] {0x64, 0x44, 0xffffffd0, }, + new uint [] {0x66, 0x46, 0x5b, }, new uint [] {0x67, 0x47, 0x5d, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, 0xffffffed, }, + new uint [] {0x6b, 0x4b, 0xffffffb3, }, new uint [] {0x6c, 0x4c, 0xffffffa3, }, + new uint [] {0xffffffe9, 0xffffffc9, 0x24, }, new uint [] {0xffffffe1, 0xffffffc1, 0xffffffdf, }, + new uint [] {0xfffffffb, 0xffffffdb, 0xffffffa4, }, new uint [] {0x79, 0x59, 0x3e, }, + new uint [] {0x78, 0x58, 0x23, }, new uint [] {0x63, 0x43, 0x26, }, + new uint [] {0x76, 0x56, 0x40, }, new uint [] {0x62, 0x42, 0x7b, }, + new uint [] {0x6e, 0x4e, 0x7d, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3f, 0x3b, }, new uint [] {0x2e, 0x3a, 0x3e, }, + new uint [] {0x2d, 0x5f, 0x2a, }, new uint [] {0xffffffed, 0xffffffcd, 0x3c, }, + new uint [] {}, }); + table [39] = new KeyboardLayout (1045, "Polish (programmer's) keyboard layout", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, 0xffffffa7, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, 0xffffffea, 0xffffffca, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, 0xfffffff3, 0xffffffd3, }, + new uint [] {0x70, 0x50, }, new uint [] {0x5b, 0x7b, }, + new uint [] {0x5d, 0x7d, }, new uint [] {0x61, 0x41, 0xffffffb1, 0xffffffa1, }, + new uint [] {0x73, 0x53, 0xffffffb6, 0xffffffa6, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, 0xffffffb3, 0xffffffa3, }, + new uint [] {0x3b, 0x3a, }, new uint [] {0x27, 0x22, }, + new uint [] {0x5c, 0x7c, }, new uint [] {0x7a, 0x5a, 0xffffffbf, 0xffffffaf, }, + new uint [] {0x78, 0x58, 0xffffffbc, 0xffffffac, }, new uint [] {0x63, 0x43, 0xffffffe6, 0xffffffc6, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, 0xfffffff1, 0xffffffd1, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3c, }, new uint [] {0x2e, 0x3e, }, + new uint [] {0x2f, 0x3f, }, new uint [] {0x3c, 0x3e, 0x7c, }, + new uint [] {}, }); + table [40] = new KeyboardLayout (1060, "Slovenian keyboard layout", 0, 1, new uint [][] { + new uint [] {0xffffffb8, 0xffffffa8, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x3d, }, new uint [] {0x27, 0x3f, }, + new uint [] {0x2b, 0x2a, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x7a, 0x5a, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xffffffb9, 0xffffffa9, }, + new uint [] {0xfffffff0, 0xffffffd0, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xffffffe8, 0xffffffc8, }, new uint [] {0xffffffe6, 0xffffffc6, }, + new uint [] {0xffffffbe, 0xffffffae, }, new uint [] {0x79, 0x59, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [41] = new KeyboardLayout (3098, "Serbian keyboard layout sr", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x3d, }, new uint [] {0x27, 0x3f, }, + new uint [] {0x2b, 0x2a, }, new uint [] {0xffffffa9, 0xffffffb9, }, + new uint [] {0xffffffaa, 0xffffffba, }, new uint [] {0xffffffc5, 0xffffffe5, }, + new uint [] {0xffffffd2, 0xfffffff2, }, new uint [] {0xffffffd4, 0xfffffff4, }, + new uint [] {0xffffffda, 0xfffffffa, }, new uint [] {0xffffffd5, 0xfffffff5, }, + new uint [] {0xffffffc9, 0xffffffe9, }, new uint [] {0xffffffcf, 0xffffffef, }, + new uint [] {0xffffffd0, 0xfffffff0, }, new uint [] {0xffffffdb, 0xfffffffb, }, + new uint [] {0x5b, 0x5d, }, new uint [] {0xffffffc1, 0xffffffe1, }, + new uint [] {0xffffffd3, 0xfffffff3, }, new uint [] {0xffffffc4, 0xffffffe4, }, + new uint [] {0xffffffc6, 0xffffffe6, }, new uint [] {0xffffffc7, 0xffffffe7, }, + new uint [] {0xffffffc8, 0xffffffe8, }, new uint [] {0xffffffa8, 0xffffffb8, }, + new uint [] {0xffffffcb, 0xffffffeb, }, new uint [] {0xffffffcc, 0xffffffec, }, + new uint [] {0xffffffde, 0xfffffffe, }, new uint [] {0xffffffab, 0xffffffbb, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0xffffffa1, 0xffffffb1, }, + new uint [] {0xffffffaf, 0xffffffbf, }, new uint [] {0xffffffc3, 0xffffffe3, }, + new uint [] {0xffffffd7, 0xfffffff7, }, new uint [] {0xffffffc2, 0xffffffe2, }, + new uint [] {0xffffffce, 0xffffffee, }, new uint [] {0xffffffcd, 0xffffffed, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0xffffffd6, 0xfffffff6, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [42] = new KeyboardLayout (3098, "Serbian keyboard layout us,sr", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, 0x32, 0x22, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, 0x36, 0x26, }, new uint [] {0x37, 0x26, 0x37, 0x2f, }, + new uint [] {0x38, 0x2a, 0x38, 0x28, }, new uint [] {0x39, 0x28, 0x39, 0x29, }, + new uint [] {0x30, 0x29, 0x30, 0x3d, }, new uint [] {0x2d, 0x5f, 0x27, 0x3f, }, + new uint [] {0x3d, 0x2b, 0x2b, 0x2a, }, new uint [] {0x71, 0x51, 0xffffffa9, 0xffffffb9, }, + new uint [] {0x77, 0x57, 0xffffffaa, 0xffffffba, }, new uint [] {0x65, 0x45, 0xffffffc5, 0xffffffe5, }, + new uint [] {0x72, 0x52, 0xffffffd2, 0xfffffff2, }, new uint [] {0x74, 0x54, 0xffffffd4, 0xfffffff4, }, + new uint [] {0x79, 0x59, 0xffffffda, 0xfffffffa, }, new uint [] {0x75, 0x55, 0xffffffd5, 0xfffffff5, }, + new uint [] {0x69, 0x49, 0xffffffc9, 0xffffffe9, }, new uint [] {0x6f, 0x4f, 0xffffffcf, 0xffffffef, }, + new uint [] {0x70, 0x50, 0xffffffd0, 0xfffffff0, }, new uint [] {0x5b, 0x7b, 0xffffffdb, 0xfffffffb, }, + new uint [] {0x5d, 0x7d, 0x5b, 0x5d, }, new uint [] {0x61, 0x41, 0xffffffc1, 0xffffffe1, }, + new uint [] {0x73, 0x53, 0xffffffd3, 0xfffffff3, }, new uint [] {0x64, 0x44, 0xffffffc4, 0xffffffe4, }, + new uint [] {0x66, 0x46, 0xffffffc6, 0xffffffe6, }, new uint [] {0x67, 0x47, 0xffffffc7, 0xffffffe7, }, + new uint [] {0x68, 0x48, 0xffffffc8, 0xffffffe8, }, new uint [] {0x6a, 0x4a, 0xffffffa8, 0xffffffb8, }, + new uint [] {0x6b, 0x4b, 0xffffffcb, 0xffffffeb, }, new uint [] {0x6c, 0x4c, 0xffffffcc, 0xffffffec, }, + new uint [] {0x3b, 0x3a, 0xffffffde, 0xfffffffe, }, new uint [] {0x27, 0x22, 0xffffffab, 0xffffffbb, }, + new uint [] {0x5c, 0x7c, 0x2d, 0x5f, }, new uint [] {0x7a, 0x5a, 0xffffffa1, 0xffffffb1, }, + new uint [] {0x78, 0x58, 0xffffffaf, 0xffffffbf, }, new uint [] {0x63, 0x43, 0xffffffc3, 0xffffffe3, }, + new uint [] {0x76, 0x56, 0xffffffd7, 0xfffffff7, }, new uint [] {0x62, 0x42, 0xffffffc2, 0xffffffe2, }, + new uint [] {0x6e, 0x4e, 0xffffffce, 0xffffffee, }, new uint [] {0x6d, 0x4d, 0xffffffcd, 0xffffffed, }, + new uint [] {0x2c, 0x3c, 0x2c, 0x3b, }, new uint [] {0x2e, 0x3e, 0x2e, 0x3a, }, + new uint [] {0x2f, 0x3f, 0xffffffd6, 0xfffffff6, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [43] = new KeyboardLayout (1050, "Croatian keyboard layout", 0, 1, new uint [][] { + new uint [] {0xffffffb8, 0xffffffa8, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x3d, }, new uint [] {0x27, 0x3f, }, + new uint [] {0x2b, 0x2a, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x7a, 0x5a, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xffffffb9, 0xffffffa9, }, + new uint [] {0xfffffff0, 0xffffffd0, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xffffffe8, 0xffffffc8, }, new uint [] {0xffffffe6, 0xffffffc6, }, + new uint [] {0xffffffbe, 0xffffffae, }, new uint [] {0x79, 0x59, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2f, 0x3f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [44] = new KeyboardLayout (1050, "Croatian keyboard layout (specific)", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0x5b, 0x7b, 0xffffffb9, 0xffffffa9, }, + new uint [] {0x5d, 0x7d, 0xfffffff0, 0xffffffd0, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0x3b, 0x3a, 0xffffffe8, 0xffffffc8, }, new uint [] {0x27, 0x22, 0xffffffe6, 0xffffffc6, }, + new uint [] {0x5c, 0x7c, 0xffffffbe, 0xffffffae, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3c, }, new uint [] {0x2e, 0x3e, }, + new uint [] {0x2f, 0x3f, }, new uint [] {0x3c, 0x3e, 0x7c, }, + new uint [] {}, }); + table [45] = new KeyboardLayout (1041, "Japanese 106 keyboard layout", 3, 7, new uint [][] { + new uint [] {0x31, 0x21, }, new uint [] {0x32, 0x22, }, + new uint [] {0x33, 0x23, }, new uint [] {0x34, 0x24, }, + new uint [] {0x35, 0x25, }, new uint [] {0x36, 0x26, }, + new uint [] {0x37, 0x27, }, new uint [] {0x38, 0x28, }, + new uint [] {0x39, 0x29, }, new uint [] {0x30, 0x7e, }, + new uint [] {0x2d, 0x3d, }, new uint [] {0x5e, 0x7e, }, + new uint [] {0x5c, 0x7c, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0x40, 0x60, }, + new uint [] {0x5b, 0x7b, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0x3b, 0x2b, }, new uint [] {0x3a, 0x2a, }, + new uint [] {0x5d, 0x7d, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3c, }, new uint [] {0x2e, 0x3e, }, + new uint [] {0x2f, 0x3f, }, new uint [] {0x5c, 0x5f, }, + new uint [] {}, }); + table [46] = new KeyboardLayout (1041, "Japanese pc98x1 keyboard layout", 0, 0, new uint [][] { + new uint [] {0x31, 0x21, }, new uint [] {0x32, 0x22, }, + new uint [] {0x33, 0x23, }, new uint [] {0x34, 0x24, }, + new uint [] {0x35, 0x25, }, new uint [] {0x36, 0x26, }, + new uint [] {0x37, 0x27, }, new uint [] {0x38, 0x28, }, + new uint [] {0x39, 0x29, }, new uint [] {0x30, }, + new uint [] {0x2d, 0x3d, }, new uint [] {0x5e, 0x60, }, + new uint [] {0x5c, 0x7c, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0x40, 0x7e, }, + new uint [] {0x5b, 0x7b, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0x3b, 0x2b, }, new uint [] {0x3a, 0x2a, }, + new uint [] {0x5d, 0x7d, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3c, }, new uint [] {0x2e, 0x3e, }, + new uint [] {0x2f, 0x3f, }, new uint [] {0x5c, 0x5f, }, + new uint [] {}, }); + table [47] = new KeyboardLayout (1051, "Slovak keyboard layout", 0, 0, new uint [][] { + new uint [] {0x3b, 0x30, }, new uint [] {0x2b, 0x31, }, + new uint [] {0xffffffb5, 0x32, }, new uint [] {0xffffffb9, 0x33, }, + new uint [] {0xffffffe8, 0x34, }, new uint [] {0xffffffbb, 0x35, }, + new uint [] {0xffffffbe, 0x36, }, new uint [] {0xfffffffd, 0x37, }, + new uint [] {0xffffffe1, 0x38, }, new uint [] {0xffffffed, 0x39, }, + new uint [] {0xffffffe9, 0x30, }, new uint [] {0x3d, 0x25, }, + new uint [] {0x27, 0x76, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xfffffffa, 0x2f, }, + new uint [] {0xffffffe4, 0x28, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xfffffff4, 0x22, }, new uint [] {0xffffffa7, 0x21, }, + new uint [] {0xfffffff2, 0x29, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3f, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [48] = new KeyboardLayout (1051, "Slovak and Czech keyboard layout without dead keys", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, 0xffffffe4, 0xffffffc4, }, + new uint [] {0x77, 0x57, 0xffffffec, 0xffffffcc, }, new uint [] {0x65, 0x45, 0xffffffe9, 0xffffffc9, }, + new uint [] {0x72, 0x52, 0xfffffff8, 0xffffffd8, }, new uint [] {0x74, 0x54, 0xffffffbb, 0xffffffab, }, + new uint [] {0x79, 0x59, 0xfffffffd, 0xffffffdd, }, new uint [] {0x75, 0x55, 0xfffffff9, 0xffffffd9, }, + new uint [] {0x69, 0x49, 0xffffffed, 0xffffffcd, }, new uint [] {0x6f, 0x4f, 0xfffffff3, 0xffffffd3, }, + new uint [] {0x70, 0x50, 0xfffffff6, 0xffffffd6, }, new uint [] {0x5b, 0x7b, }, + new uint [] {0x5d, 0x7d, }, new uint [] {0x61, 0x41, 0xffffffe1, 0xffffffc1, }, + new uint [] {0x73, 0x53, 0xffffffb9, 0xffffffa9, }, new uint [] {0x64, 0x44, 0xffffffef, 0xffffffcf, }, + new uint [] {0x66, 0x46, 0xffffffeb, 0xffffffcb, }, new uint [] {0x67, 0x47, 0xffffffe0, 0xffffffc0, }, + new uint [] {0x68, 0x48, 0xfffffffa, 0xffffffda, }, new uint [] {0x6a, 0x4a, 0xfffffffc, 0xffffffdc, }, + new uint [] {0x6b, 0x4b, 0xfffffff4, 0xffffffd4, }, new uint [] {0x6c, 0x4c, 0xffffffb5, 0xffffffa5, }, + new uint [] {0x3b, 0x3a, }, new uint [] {0x27, 0x22, }, + new uint [] {0x5c, 0x7c, }, new uint [] {0x7a, 0x5a, 0xffffffbe, 0xffffffae, }, + new uint [] {0x78, 0x58, 0xffffffa4, }, new uint [] {0x63, 0x43, 0xffffffe8, 0xffffffc8, }, + new uint [] {0x76, 0x56, 0xffffffe7, 0xffffffc7, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, 0xfffffff2, 0xffffffd2, }, new uint [] {0x6d, 0x4d, 0xffffffe5, 0xffffffc5, }, + new uint [] {0x2c, 0x3c, }, new uint [] {0x2e, 0x3e, }, + new uint [] {0x2f, 0x3f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [49] = new KeyboardLayout (1029, "Czech keyboard layout", 0, 0, new uint [][] { + new uint [] {0x3b, }, new uint [] {0x2b, 0x31, }, + new uint [] {0xffffffec, 0x32, }, new uint [] {0xffffffb9, 0x33, }, + new uint [] {0xffffffe8, 0x34, }, new uint [] {0xfffffff8, 0x35, }, + new uint [] {0xffffffbe, 0x36, }, new uint [] {0xfffffffd, 0x37, }, + new uint [] {0xffffffe1, 0x38, }, new uint [] {0xffffffed, 0x39, }, + new uint [] {0xffffffe9, 0x30, 0xffffffbd, 0x29, }, new uint [] {0x3d, 0x25, }, + new uint [] {}, new uint [] {0x71, 0x51, 0x5c, }, + new uint [] {0x77, 0x57, 0x7c, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xfffffffa, 0x2f, 0x5b, 0x7b, }, + new uint [] {0x29, 0x28, 0x5d, 0x7d, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, 0xfffffff0, }, new uint [] {0x64, 0x44, 0xffffffd0, }, + new uint [] {0x66, 0x46, 0x5b, }, new uint [] {0x67, 0x47, 0x5d, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, 0xffffffb3, }, new uint [] {0x6c, 0x4c, 0xffffffa3, }, + new uint [] {0xfffffff9, 0x22, 0x24, }, new uint [] {0xffffffa7, 0x21, 0xffffffdf, }, + new uint [] {0xffffffa8, 0x27, }, new uint [] {0x7a, 0x5a, 0x3e, }, + new uint [] {0x78, 0x58, 0x23, }, new uint [] {0x63, 0x43, 0x26, }, + new uint [] {0x76, 0x56, 0x40, }, new uint [] {0x62, 0x42, 0x7b, }, + new uint [] {0x6e, 0x4e, 0x7d, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3f, 0x3c, }, new uint [] {0x2e, 0x3a, 0x3e, }, + new uint [] {0x2d, 0x5f, 0x2a, }, new uint [] {0x3c, 0x3e, 0x5c, 0x7c, }, + new uint [] {}, }); + table [50] = new KeyboardLayout (1029, "Czech keyboard layout cz", 0, 1, new uint [][] { + new uint [] {0x3b, }, new uint [] {0x2b, 0x31, }, + new uint [] {0xffffffec, 0x32, }, new uint [] {0xffffffb9, 0x33, }, + new uint [] {0xffffffe8, 0x34, }, new uint [] {0xfffffff8, 0x35, }, + new uint [] {0xffffffbe, 0x36, }, new uint [] {0xfffffffd, 0x37, }, + new uint [] {0xffffffe1, 0x38, }, new uint [] {0xffffffed, 0x39, }, + new uint [] {0xffffffe9, 0x30, }, new uint [] {0x3d, 0x25, }, + new uint [] {0xffffffb4, 0xffffffb7, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x7a, 0x5a, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xfffffffa, 0x2f, }, + new uint [] {0x29, 0x28, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xfffffff9, 0x22, }, new uint [] {0xffffffa7, 0x21, }, + new uint [] {0xffffffa8, 0x27, }, new uint [] {0x79, 0x59, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3f, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x5c, }, + new uint [] {}, }); + table [51] = new KeyboardLayout (1029, "Czech keyboard layout cz_qwerty", 0, 0, new uint [][] { + new uint [] {0x3b, }, new uint [] {0x2b, 0x31, }, + new uint [] {0xffffffec, 0x32, }, new uint [] {0xffffffb9, 0x33, }, + new uint [] {0xffffffe8, 0x34, }, new uint [] {0xfffffff8, 0x35, }, + new uint [] {0xffffffbe, 0x36, }, new uint [] {0xfffffffd, 0x37, }, + new uint [] {0xffffffe1, 0x38, }, new uint [] {0xffffffed, 0x39, }, + new uint [] {0xffffffe9, 0x30, }, new uint [] {0x3d, 0x25, }, + new uint [] {0xffffffb4, 0xffffffb7, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xfffffffa, 0x2f, }, + new uint [] {0x29, 0x28, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xfffffff9, 0x22, }, new uint [] {0xffffffa7, 0x21, }, + new uint [] {0xffffffa8, 0x27, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3f, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x5c, }, + new uint [] {}, }); + table [52] = new KeyboardLayout (1034, "Latin American keyboard layout", 0, 0, new uint [][] { + new uint [] {0x7c, 0xffffffb0, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x3d, }, new uint [] {0x27, 0x3f, }, + new uint [] {0xffffffbf, 0xffffffa1, }, new uint [] {0x71, 0x51, 0x40, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xffffffb4, 0xffffffa8, }, + new uint [] {0x2b, 0x2a, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xfffffff1, 0xffffffd1, }, new uint [] {0x7b, 0x5b, 0x5e, }, + new uint [] {0x7d, 0x5d, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [53] = new KeyboardLayout (1063, "Lithuanian (Baltic) keyboard layout", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, }, new uint [] {0xffffffe0, 0xffffffc0, }, + new uint [] {0xffffffe8, 0xffffffc8, }, new uint [] {0xffffffe6, 0xffffffc6, }, + new uint [] {0xffffffeb, 0xffffffcb, }, new uint [] {0xffffffe1, 0xffffffc1, }, + new uint [] {0xfffffff0, 0xffffffd0, }, new uint [] {0xfffffff8, 0xffffffd8, }, + new uint [] {0xfffffffb, 0xffffffdb, }, new uint [] {0xffffffa5, 0x28, }, + new uint [] {0xffffffb4, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0xfffffffe, 0xffffffde, }, new uint [] {0x5c, 0x7c, }, + new uint [] {0x71, 0x51, }, new uint [] {0x77, 0x57, }, + new uint [] {0x65, 0x45, }, new uint [] {0x72, 0x52, }, + new uint [] {0x74, 0x54, }, new uint [] {0x79, 0x59, }, + new uint [] {0x75, 0x55, }, new uint [] {0x69, 0x49, }, + new uint [] {0x6f, 0x4f, }, new uint [] {0x70, 0x50, }, + new uint [] {0x5b, 0x7b, }, new uint [] {0x5d, 0x7d, }, + new uint [] {0x61, 0x41, }, new uint [] {0x73, 0x53, }, + new uint [] {0x64, 0x44, }, new uint [] {0x66, 0x46, }, + new uint [] {0x67, 0x47, }, new uint [] {0x68, 0x48, }, + new uint [] {0x6a, 0x4a, }, new uint [] {0x6b, 0x4b, }, + new uint [] {0x6c, 0x4c, }, new uint [] {0x3b, 0x3a, }, + new uint [] {0x27, 0x22, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3c, }, new uint [] {0x2e, 0x3e, }, + new uint [] {0x2f, 0x3f, }, new uint [] {}, + new uint [] {}, }); + table [54] = new KeyboardLayout (1055, "Turkish keyboard layout", 0, 0, new uint [][] { + new uint [] {0x22, 0xffffffe9, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x27, }, new uint [] {0x33, 0x5e, 0x23, }, + new uint [] {0x34, 0x2b, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, 0x7b, }, + new uint [] {0x38, 0x28, 0x5b, }, new uint [] {0x39, 0x29, 0x5d, }, + new uint [] {0x30, 0x3d, 0x7d, }, new uint [] {0x2a, 0x3f, 0x5c, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x71, 0x51, 0x40, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0xfffffffd, 0x49, 0xffffffee, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xfffffff0, 0xffffffd0, }, + new uint [] {0xfffffffc, 0xffffffdc, 0x7e, }, new uint [] {0x61, 0x41, 0xffffffe6, }, + new uint [] {0x73, 0x53, 0xffffffdf, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xfffffffe, 0xffffffde, }, new uint [] {0x69, 0xffffffdd, }, + new uint [] {0x2c, 0x3b, 0x60, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0xfffffff6, 0xffffffd6, }, new uint [] {0xffffffe7, 0xffffffc7, }, + new uint [] {0x2e, 0x3a, }, new uint [] {}, + new uint [] {}, }); + table [55] = new KeyboardLayout (1055, "Turkish keyboard layout tr", 0, 0, new uint [][] { + new uint [] {0x22, 0x5c, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x27, }, new uint [] {0x33, 0x5e, }, + new uint [] {0x34, 0x2b, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x2f, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x3d, }, new uint [] {0x2a, 0x3f, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0xffffffb9, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xffffffbb, 0xffffffab, }, + new uint [] {0xfffffffc, 0xffffffdc, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0xffffffba, 0xffffffaa, }, new uint [] {0x69, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0xfffffff6, 0xffffffd6, }, new uint [] {0xffffffe7, 0xffffffc7, }, + new uint [] {0x2e, 0x3a, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [56] = new KeyboardLayout (1055, "Turkish keyboard layout trf", 0, 0, new uint [][] { + new uint [] {0x2b, 0x2a, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x5e, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x27, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x3d, }, new uint [] {0x2f, 0x3f, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x66, 0x46, }, + new uint [] {0x67, 0x47, }, new uint [] {0xffffffbb, 0xffffffab, }, + new uint [] {0xffffffb9, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x64, 0x44, }, new uint [] {0x72, 0x52, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x68, 0x48, }, + new uint [] {0x70, 0x50, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, }, new uint [] {0x65, 0x45, }, + new uint [] {0x61, 0x41, }, new uint [] {0xfffffffc, 0xffffffdc, }, + new uint [] {0x74, 0x54, }, new uint [] {0x6b, 0x4b, }, + new uint [] {0x6d, 0x4d, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0x79, 0x59, }, new uint [] {0xffffffba, 0xffffffaa, }, + new uint [] {0x78, 0x58, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0xfffffff6, 0xffffffd6, }, new uint [] {0x76, 0x56, }, + new uint [] {0x63, 0x43, }, new uint [] {0xffffffe7, 0xffffffc7, }, + new uint [] {0x7a, 0x5a, }, new uint [] {0x73, 0x53, }, + new uint [] {0x62, 0x42, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [57] = new KeyboardLayout (1037, "Israelian keyboard layout", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, 0x3b, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, 0x2f, }, + new uint [] {0x77, 0x57, 0x27, }, new uint [] {0x65, 0x45, 0xfffffff7, }, + new uint [] {0x72, 0x52, 0xfffffff8, }, new uint [] {0x74, 0x54, 0xffffffe0, }, + new uint [] {0x79, 0x59, 0xffffffe8, }, new uint [] {0x75, 0x55, 0xffffffe5, }, + new uint [] {0x69, 0x49, 0xffffffef, }, new uint [] {0x6f, 0x4f, 0xffffffed, }, + new uint [] {0x70, 0x50, 0xfffffff4, }, new uint [] {0x5b, 0x7b, }, + new uint [] {0x5d, 0x7d, }, new uint [] {0x61, 0x41, 0xfffffff9, }, + new uint [] {0x73, 0x53, 0xffffffe3, }, new uint [] {0x64, 0x44, 0xffffffe2, }, + new uint [] {0x66, 0x46, 0xffffffeb, }, new uint [] {0x67, 0x47, 0xfffffff2, }, + new uint [] {0x68, 0x48, 0xffffffe9, }, new uint [] {0x6a, 0x4a, 0xffffffe7, }, + new uint [] {0x6b, 0x4b, 0xffffffec, }, new uint [] {0x6c, 0x4c, 0xffffffea, }, + new uint [] {0x3b, 0x3a, 0xfffffff3, }, new uint [] {0x27, 0x22, 0x2c, }, + new uint [] {0x5c, 0x7c, }, new uint [] {0x7a, 0x5a, 0xffffffe6, }, + new uint [] {0x78, 0x58, 0xfffffff1, }, new uint [] {0x63, 0x43, 0xffffffe1, }, + new uint [] {0x76, 0x56, 0xffffffe4, }, new uint [] {0x62, 0x42, 0xfffffff0, }, + new uint [] {0x6e, 0x4e, 0xffffffee, }, new uint [] {0x6d, 0x4d, 0xfffffff6, }, + new uint [] {0x2c, 0x3c, 0xfffffffa, }, new uint [] {0x2e, 0x3e, 0xfffffff5, }, + new uint [] {0x2f, 0x3f, 0x2e, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [58] = new KeyboardLayout (1037, "Israelian phonetic keyboard layout", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, 0xfffffff7, }, + new uint [] {0x77, 0x57, 0xffffffe5, }, new uint [] {0x65, 0x45, 0xffffffe0, }, + new uint [] {0x72, 0x52, 0xfffffff8, }, new uint [] {0x74, 0x54, 0xfffffffa, }, + new uint [] {0x79, 0x59, 0xfffffff2, }, new uint [] {0x75, 0x55, 0xffffffe5, }, + new uint [] {0x69, 0x49, 0xffffffe9, }, new uint [] {0x6f, 0x4f, 0xfffffff1, }, + new uint [] {0x70, 0x50, 0xfffffff4, }, new uint [] {0x5b, 0x7b, }, + new uint [] {0x5d, 0x7d, }, new uint [] {0x61, 0x41, 0xffffffe0, }, + new uint [] {0x73, 0x53, 0xfffffff9, }, new uint [] {0x64, 0x44, 0xffffffe3, }, + new uint [] {0x66, 0x46, 0xfffffff4, }, new uint [] {0x67, 0x47, 0xffffffe2, }, + new uint [] {0x68, 0x48, 0xffffffe4, }, new uint [] {0x6a, 0x4a, 0xffffffe9, }, + new uint [] {0x6b, 0x4b, 0xffffffeb, }, new uint [] {0x6c, 0x4c, 0xffffffec, }, + new uint [] {0x3b, 0x3a, }, new uint [] {0x27, 0x22, }, + new uint [] {0x5c, 0x7c, }, new uint [] {0x7a, 0x5a, 0xffffffe6, }, + new uint [] {0x78, 0x58, 0xffffffe7, }, new uint [] {0x63, 0x43, 0xfffffff6, }, + new uint [] {0x76, 0x56, 0xffffffe5, }, new uint [] {0x62, 0x42, 0xffffffe1, }, + new uint [] {0x6e, 0x4e, 0xfffffff0, }, new uint [] {0x6d, 0x4d, 0xffffffee, }, + new uint [] {0x2c, 0x3c, }, new uint [] {0x2e, 0x3e, }, + new uint [] {0x2f, 0x3f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [59] = new KeyboardLayout (1037, "Israelian Saharon keyboard layout", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, 0xfffffff7, }, + new uint [] {0x77, 0x57, 0xfffffff1, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, 0xfffffff8, }, new uint [] {0x74, 0x54, 0xffffffe8, }, + new uint [] {0x79, 0x59, 0xffffffe3, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, 0xfffffff4, }, new uint [] {0x5b, 0x7b, }, + new uint [] {0x5d, 0x7d, }, new uint [] {0x61, 0x41, 0xffffffe0, }, + new uint [] {0x73, 0x53, 0xffffffe5, }, new uint [] {0x64, 0x44, 0xffffffec, }, + new uint [] {0x66, 0x46, 0xfffffffa, }, new uint [] {0x67, 0x47, 0xffffffe2, }, + new uint [] {0x68, 0x48, 0xffffffe4, }, new uint [] {0x6a, 0x4a, 0xfffffff9, }, + new uint [] {0x6b, 0x4b, 0xffffffeb, }, new uint [] {0x6c, 0x4c, 0xffffffe9, }, + new uint [] {0x3b, 0x3a, }, new uint [] {0x27, 0x22, }, + new uint [] {0x5c, 0x7c, }, new uint [] {0x7a, 0x5a, 0xffffffe6, }, + new uint [] {0x78, 0x58, 0xffffffe7, }, new uint [] {0x63, 0x43, 0xfffffff6, }, + new uint [] {0x76, 0x56, 0xfffffff2, }, new uint [] {0x62, 0x42, 0xffffffe1, }, + new uint [] {0x6e, 0x4e, 0xfffffff0, }, new uint [] {0x6d, 0x4d, 0xffffffee, }, + new uint [] {0x2c, 0x3c, }, new uint [] {0x2e, 0x3e, }, + new uint [] {0x2f, 0x3f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [60] = new KeyboardLayout (1033, "VNC keyboard layout", 4, 8, new uint [][] { + new uint [] {0x31, 0x21, }, new uint [] {0x32, 0x40, }, + new uint [] {0x33, 0x23, }, new uint [] {0x34, 0x24, }, + new uint [] {0x35, 0x25, }, new uint [] {0x36, 0x5e, }, + new uint [] {0x37, 0x26, }, new uint [] {0x38, 0x2a, }, + new uint [] {0x39, 0x28, }, new uint [] {0x30, 0x29, }, + new uint [] {0x2d, 0x5f, }, new uint [] {0x3d, 0x2b, }, + new uint [] {0x5b, 0x7b, }, new uint [] {0x5d, 0x7d, }, + new uint [] {0x3b, 0x3a, }, new uint [] {0x27, 0x22, }, + new uint [] {0x60, 0x7e, }, new uint [] {0x2c, 0x3c, }, + new uint [] {0x2e, 0x3e, }, new uint [] {0x2f, 0x3f, }, + new uint [] {0x5c, 0x7c, }, new uint [] {0x61, 0x41, }, + new uint [] {0x62, 0x42, }, new uint [] {0x63, 0x43, }, + new uint [] {0x64, 0x44, }, new uint [] {0x65, 0x45, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x69, 0x49, }, + new uint [] {0x6a, 0x4a, }, new uint [] {0x6b, 0x4b, }, + new uint [] {0x6c, 0x4c, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0x71, 0x51, }, + new uint [] {0x72, 0x52, }, new uint [] {0x73, 0x53, }, + new uint [] {0x74, 0x54, }, new uint [] {0x75, 0x55, }, + new uint [] {0x76, 0x56, }, new uint [] {0x77, 0x57, }, + new uint [] {0x78, 0x58, }, new uint [] {0x79, 0x59, }, + new uint [] {0x7a, 0x5a, }, new uint [] {}, + new uint [] {}, }); + table [61] = new KeyboardLayout (1032, "Greek keyboard layout", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x40, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x5e, }, new uint [] {0x37, 0x26, }, + new uint [] {0x38, 0x2a, }, new uint [] {0x39, 0x28, }, + new uint [] {0x30, 0x29, }, new uint [] {0x2d, 0x5f, }, + new uint [] {0x3d, 0x2b, }, new uint [] {0x71, 0x51, 0x3b, 0x3a, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, 0xffffffe5, 0xffffffc5, }, + new uint [] {0x72, 0x52, 0xfffffff1, 0xffffffd1, }, new uint [] {0x74, 0x54, 0xfffffff4, 0xffffffd4, }, + new uint [] {0x79, 0x59, 0xfffffff5, 0xffffffd5, }, new uint [] {0x75, 0x55, 0xffffffe8, 0xffffffc8, }, + new uint [] {0x69, 0x49, 0xffffffe9, 0xffffffc9, }, new uint [] {0x6f, 0x4f, 0xffffffef, 0xffffffcf, }, + new uint [] {0x70, 0x50, 0xfffffff0, 0xffffffd0, }, new uint [] {0x5b, 0x7b, }, + new uint [] {0x5d, 0x7d, }, new uint [] {0x61, 0x41, 0xffffffe1, 0xffffffc1, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, 0xffffffe4, 0xffffffc4, }, + new uint [] {0x66, 0x46, 0xfffffff6, 0xffffffd6, }, new uint [] {0x67, 0x47, 0xffffffe3, 0xffffffc3, }, + new uint [] {0x68, 0x48, 0xffffffe7, 0xffffffc7, }, new uint [] {0x6a, 0x4a, 0xffffffee, 0xffffffce, }, + new uint [] {0x6b, 0x4b, 0xffffffea, 0xffffffca, }, new uint [] {0x6c, 0x4c, 0xffffffeb, 0xffffffcb, }, + new uint [] {0x3b, 0x3a, 0xffffffb4, 0xffffffa8, }, new uint [] {0x27, 0x22, }, + new uint [] {0x5c, 0x7c, }, new uint [] {0x7a, 0x5a, 0xffffffe6, 0xffffffc6, }, + new uint [] {0x78, 0x58, 0xfffffff7, 0xffffffd7, }, new uint [] {0x63, 0x43, 0xfffffff8, 0xffffffd8, }, + new uint [] {0x76, 0x56, 0xfffffff9, 0xffffffd9, }, new uint [] {0x62, 0x42, 0xffffffe2, 0xffffffc2, }, + new uint [] {0x6e, 0x4e, 0xffffffed, 0xffffffcd, }, new uint [] {0x6d, 0x4d, 0xffffffec, 0xffffffcc, }, + new uint [] {0x2c, 0x3c, }, new uint [] {0x2e, 0x3e, }, + new uint [] {0x2f, 0x3f, }, new uint [] {0x3c, 0x3e, }, + new uint [] {}, }); + table [62] = new KeyboardLayout (1054, "Thai (Kedmanee) keyboard layout", 0, 0, new uint [][] { + new uint [] {0x60, 0x7e, 0x5f, 0x25, }, new uint [] {0x31, 0x21, 0xffffffe5, 0x2b, }, + new uint [] {0x32, 0x40, 0x2f, 0xfffffff1, }, new uint [] {0x33, 0x23, 0x2d, 0xfffffff2, }, + new uint [] {0x34, 0x24, 0xffffffc0, 0xfffffff3, }, new uint [] {0x35, 0x25, 0xffffffb6, 0xfffffff4, }, + new uint [] {0x36, 0x5e, 0xffffffd8, 0xffffffd9, }, new uint [] {0x37, 0x26, 0xffffffd6, 0xffffffdf, }, + new uint [] {0x38, 0x2a, 0xffffffa4, 0xfffffff5, }, new uint [] {0x39, 0x28, 0xffffffb5, 0xfffffff6, }, + new uint [] {0x30, 0x29, 0xffffffa8, 0xfffffff7, }, new uint [] {0x2d, 0x5f, 0xffffffa2, 0xfffffff8, }, + new uint [] {0x3d, 0x2b, 0xffffffaa, 0xfffffff9, }, new uint [] {0x71, 0x51, 0xffffffe6, 0xfffffff0, }, + new uint [] {0x77, 0x57, 0xffffffe4, 0x22, }, new uint [] {0x65, 0x45, 0xffffffd3, 0xffffffae, }, + new uint [] {0x72, 0x52, 0xffffffbe, 0xffffffb1, }, new uint [] {0x74, 0x54, 0xffffffd0, 0xffffffb8, }, + new uint [] {0x79, 0x59, 0xffffffd1, 0xffffffed, }, new uint [] {0x75, 0x55, 0xffffffd5, 0xffffffea, }, + new uint [] {0x69, 0x49, 0xffffffc3, 0xffffffb3, }, new uint [] {0x6f, 0x4f, 0xffffffb9, 0xffffffcf, }, + new uint [] {0x70, 0x50, 0xffffffc2, 0xffffffad, }, new uint [] {0x5b, 0x7b, 0xffffffba, 0xffffffb0, }, + new uint [] {0x5d, 0x7d, 0xffffffc5, 0x2c, }, new uint [] {0x61, 0x41, 0xffffffbf, 0xffffffc4, }, + new uint [] {0x73, 0x53, 0xffffffcb, 0xffffffa6, }, new uint [] {0x64, 0x44, 0xffffffa1, 0xffffffaf, }, + new uint [] {0x66, 0x46, 0xffffffb4, 0xffffffe2, }, new uint [] {0x67, 0x47, 0xffffffe0, 0xffffffac, }, + new uint [] {0x68, 0x48, 0xffffffe9, 0xffffffe7, }, new uint [] {0x6a, 0x4a, 0xffffffe8, 0xffffffeb, }, + new uint [] {0x6b, 0x4b, 0xffffffd2, 0xffffffc9, }, new uint [] {0x6c, 0x4c, 0xffffffca, 0xffffffc8, }, + new uint [] {0x3b, 0x3a, 0xffffffc7, 0xffffffab, }, new uint [] {0x27, 0x22, 0xffffffa7, 0x2e, }, + new uint [] {0x5c, 0x7c, 0xffffffa3, 0xffffffa5, }, new uint [] {0x7a, 0x5a, 0xffffffbc, 0x28, }, + new uint [] {0x78, 0x58, 0xffffffbb, 0x29, }, new uint [] {0x63, 0x43, 0xffffffe1, 0xffffffa9, }, + new uint [] {0x76, 0x56, 0xffffffcd, 0xffffffce, }, new uint [] {0x62, 0x42, 0xffffffda, }, + new uint [] {0x6e, 0x4e, 0xffffffd7, 0xffffffec, }, new uint [] {0x6d, 0x4d, 0xffffffb7, 0x3f, }, + new uint [] {0x2c, 0x3c, 0xffffffc1, 0xffffffb2, }, new uint [] {0x2e, 0x3e, 0xffffffe3, 0xffffffcc, }, + new uint [] {0x2f, 0x3f, 0xffffffbd, 0xffffffc6, }, new uint [] {}, + new uint [] {}, }); + table [63] = new KeyboardLayout (1043, "Dutch keyboard layout", 0, 0, new uint [][] { + new uint [] {0x40, 0xffffffa7, }, new uint [] {0x31, 0x21, }, + new uint [] {0x32, 0x22, }, new uint [] {0x33, 0x23, }, + new uint [] {0x34, 0x24, }, new uint [] {0x35, 0x25, }, + new uint [] {0x36, 0x26, }, new uint [] {0x37, 0x5f, }, + new uint [] {0x38, 0x28, }, new uint [] {0x39, 0x29, }, + new uint [] {0x30, 0x27, }, new uint [] {0x2f, 0x3f, }, + new uint [] {0xffffffb0, 0x7e, }, new uint [] {0x71, 0x51, }, + new uint [] {0x77, 0x57, }, new uint [] {0x65, 0x45, }, + new uint [] {0x72, 0x52, }, new uint [] {0x74, 0x54, }, + new uint [] {0x79, 0x59, }, new uint [] {0x75, 0x55, }, + new uint [] {0x69, 0x49, }, new uint [] {0x6f, 0x4f, }, + new uint [] {0x70, 0x50, }, new uint [] {0xffffffa8, 0x7e, }, + new uint [] {0x2a, 0x7c, }, new uint [] {0x61, 0x41, }, + new uint [] {0x73, 0x53, }, new uint [] {0x64, 0x44, }, + new uint [] {0x66, 0x46, }, new uint [] {0x67, 0x47, }, + new uint [] {0x68, 0x48, }, new uint [] {0x6a, 0x4a, }, + new uint [] {0x6b, 0x4b, }, new uint [] {0x6c, 0x4c, }, + new uint [] {0x2b, 0xffffffb1, }, new uint [] {0x27, 0x60, }, + new uint [] {0x3c, 0x3e, }, new uint [] {0x7a, 0x5a, }, + new uint [] {0x78, 0x58, }, new uint [] {0x63, 0x43, }, + new uint [] {0x76, 0x56, }, new uint [] {0x62, 0x42, }, + new uint [] {0x6e, 0x4e, }, new uint [] {0x6d, 0x4d, }, + new uint [] {0x2c, 0x3b, }, new uint [] {0x2e, 0x3a, }, + new uint [] {0x2d, 0x3d, }, new uint [] {0x5b, 0x5d, }, + new uint [] {}, }); + + + rsxw.AddResource ("keyboard_table", table); + + short [][] scan_table = new short [][] { + main_key_scan_qwerty, main_key_scan_dvorak, main_key_scan_abnt_qwerty, + main_key_scan_qwerty_jp106, main_key_scan_vnc + }; + rsxw.AddResource ("scan_table", scan_table); + + VirtualKeys [][] vkeys = new VirtualKeys [][] { + main_key_vkey_qwerty, main_key_vkey_qwertz, main_key_vkey_dvorak, + main_key_vkey_qwertz_105, main_key_vkey_azerty, main_key_vkey_qwerty_v2, + main_key_vkey_abnt_qwerty, main_key_vkey_qwerty_jp106, main_key_vkey_vnc + }; + int [][] vkey_table = new int [vkeys.Length][]; + for (int i = 0; i < vkeys.Length; i++) { + int [] cp = new int [vkeys [i].Length]; + for (int r = 0; r < vkeys [i].Length; r++) + cp [r] = (int) vkeys [i][r]; + vkey_table [i] = cp; + } + + rsxw.AddResource ("vkey_table", vkey_table); + + rsxw.Close (); + } + + private static readonly short [] main_key_scan_vnc = new short [] + { + 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B, + 0x1E,0x30,0x2E,0x20,0x12,0x21,0x22,0x23,0x17,0x24,0x25,0x26,0x32,0x31,0x18,0x19,0x10,0x13,0x1F,0x14,0x16,0x2F,0x11,0x2D,0x15,0x2C, + 0x56 + }; + + private static readonly short [] main_key_scan_qwerty_jp106 = new short [] + { + 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x29, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B, + 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B, + 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35, + 0x56 /* the 102nd key (actually to the right of l-shift) */ + }; + + private static readonly VirtualKeys [] main_key_vkey_vnc = new VirtualKeys [] + { + VirtualKeys.VK_1, VirtualKeys.VK_2, VirtualKeys.VK_3, VirtualKeys.VK_4, VirtualKeys.VK_5, VirtualKeys.VK_6, + VirtualKeys.VK_7, VirtualKeys.VK_8, VirtualKeys.VK_9, VirtualKeys.VK_0, VirtualKeys.VK_OEM_MINUS, + VirtualKeys.VK_OEM_PLUS, VirtualKeys.VK_OEM_4, VirtualKeys.VK_OEM_6, VirtualKeys.VK_OEM_1, + VirtualKeys.VK_OEM_7, VirtualKeys.VK_OEM_3, VirtualKeys.VK_OEM_COMMA, VirtualKeys.VK_OEM_PERIOD, + VirtualKeys.VK_OEM_2, VirtualKeys.VK_OEM_5, VirtualKeys.VK_A, VirtualKeys.VK_B, VirtualKeys.VK_C, + VirtualKeys.VK_D, VirtualKeys.VK_E, VirtualKeys.VK_F, VirtualKeys.VK_G, VirtualKeys.VK_H, + VirtualKeys.VK_I, VirtualKeys.VK_J, VirtualKeys.VK_K, VirtualKeys.VK_L, VirtualKeys.VK_M, + VirtualKeys.VK_N, VirtualKeys.VK_O, VirtualKeys.VK_P, VirtualKeys.VK_Q, VirtualKeys.VK_R, + VirtualKeys.VK_S, VirtualKeys.VK_T, VirtualKeys.VK_U, VirtualKeys.VK_V, VirtualKeys.VK_W, + VirtualKeys.VK_X, VirtualKeys.VK_Y, VirtualKeys.VK_Z, VirtualKeys.VK_OEM_102 + }; + + private static readonly short [] main_key_scan_qwerty = new short [] + { + /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */ + /* ` 1 2 3 4 5 6 7 8 9 0 - = */ + 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D, + /* q w e r t y u i o p [ ] */ + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B, + /* a s d f g h j k l ; ' \ */ + 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B, + /* z x c v b n m , . / */ + 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35, + 0x56 /* the 102nd key (actually to the right of l-shift) */ + }; + + private static readonly short [] main_key_scan_dvorak = new short [] + { + /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */ + 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B, + /* ' , . p y f g c r l / = */ + 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D, + /* a o e u i d h t n s - \ */ + 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B, + /* ; q j k x b m w v z */ + 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C, + 0x56 /* the 102nd key (actually to the right of l-shift) */ + }; + + private static readonly short [] main_key_scan_abnt_qwerty = new short [] + { + 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B, + 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B, + 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35, + 0x56,0x35, + }; + + private static readonly VirtualKeys [] main_key_vkey_qwerty = new VirtualKeys [] + { + // NOTE: this layout must concur with the scan codes layout above + VirtualKeys.VK_OEM_3, VirtualKeys.VK_1, VirtualKeys.VK_2, VirtualKeys.VK_3, VirtualKeys.VK_4, + VirtualKeys.VK_5, VirtualKeys.VK_6, VirtualKeys.VK_7, VirtualKeys.VK_8, VirtualKeys.VK_9, + VirtualKeys.VK_0, VirtualKeys.VK_OEM_MINUS, VirtualKeys.VK_OEM_PLUS, VirtualKeys.VK_Q, + VirtualKeys.VK_W, VirtualKeys.VK_E, VirtualKeys.VK_R, VirtualKeys.VK_T, VirtualKeys.VK_Y, + VirtualKeys.VK_U, VirtualKeys.VK_I, VirtualKeys.VK_O, VirtualKeys.VK_P, VirtualKeys.VK_OEM_4, + VirtualKeys.VK_OEM_6, VirtualKeys.VK_A, VirtualKeys.VK_S, VirtualKeys.VK_D, VirtualKeys.VK_F, + VirtualKeys.VK_G, VirtualKeys.VK_H, VirtualKeys.VK_J, VirtualKeys.VK_K, VirtualKeys.VK_L, + VirtualKeys.VK_OEM_1, VirtualKeys.VK_OEM_7, VirtualKeys.VK_OEM_5, VirtualKeys.VK_Z, + VirtualKeys.VK_X, VirtualKeys.VK_C, VirtualKeys.VK_V, VirtualKeys.VK_B, VirtualKeys.VK_N, + VirtualKeys.VK_M, VirtualKeys.VK_OEM_COMMA, VirtualKeys.VK_OEM_PERIOD, VirtualKeys.VK_OEM_2, + VirtualKeys.VK_OEM_102 // the 102nd key (actually to the right of l-shift) + }; + + private static readonly VirtualKeys [] main_key_vkey_qwertz = new VirtualKeys [] + { + VirtualKeys.VK_OEM_3, VirtualKeys.VK_1, VirtualKeys.VK_2, VirtualKeys.VK_3, VirtualKeys.VK_4, + VirtualKeys.VK_5, VirtualKeys.VK_6, VirtualKeys.VK_7, VirtualKeys.VK_8, VirtualKeys.VK_9, + VirtualKeys.VK_0, VirtualKeys.VK_OEM_MINUS, VirtualKeys.VK_OEM_PLUS, + VirtualKeys.VK_Q, VirtualKeys.VK_W, VirtualKeys.VK_E, VirtualKeys.VK_R, VirtualKeys.VK_T, VirtualKeys.VK_Z, + VirtualKeys.VK_U, VirtualKeys.VK_I, VirtualKeys.VK_O, VirtualKeys.VK_P, VirtualKeys.VK_OEM_4, + VirtualKeys.VK_OEM_6, VirtualKeys.VK_A, VirtualKeys.VK_S, VirtualKeys.VK_D, VirtualKeys.VK_F, + VirtualKeys.VK_G, VirtualKeys.VK_H, VirtualKeys.VK_J, VirtualKeys.VK_K, VirtualKeys.VK_L, + VirtualKeys.VK_OEM_1, VirtualKeys.VK_OEM_7, VirtualKeys.VK_OEM_5, VirtualKeys.VK_Y, + VirtualKeys.VK_X, VirtualKeys.VK_C, VirtualKeys.VK_V, VirtualKeys.VK_B, VirtualKeys.VK_N, + VirtualKeys.VK_M, VirtualKeys.VK_OEM_COMMA, VirtualKeys.VK_OEM_PERIOD, VirtualKeys.VK_OEM_2, + VirtualKeys.VK_OEM_102 // the 102nd key (actually to the right of l-shift) + }; + + private static readonly VirtualKeys [] main_key_vkey_dvorak = new VirtualKeys [] + { + // NOTE: this layout must concur with the scan codes layout above + VirtualKeys.VK_OEM_3, VirtualKeys.VK_1, VirtualKeys.VK_2, VirtualKeys.VK_3, VirtualKeys.VK_4, + VirtualKeys.VK_5, VirtualKeys.VK_6, VirtualKeys.VK_7, VirtualKeys.VK_8, VirtualKeys.VK_9, + VirtualKeys.VK_0, VirtualKeys.VK_OEM_4, VirtualKeys.VK_OEM_6, VirtualKeys.VK_OEM_7, + VirtualKeys.VK_OEM_COMMA, VirtualKeys.VK_OEM_PERIOD, VirtualKeys.VK_P, VirtualKeys.VK_Y, + VirtualKeys.VK_F, VirtualKeys.VK_G, VirtualKeys.VK_C, VirtualKeys.VK_R, VirtualKeys.VK_L, + VirtualKeys.VK_OEM_2, VirtualKeys.VK_OEM_PLUS, VirtualKeys.VK_A, VirtualKeys.VK_O, + VirtualKeys.VK_E, VirtualKeys.VK_U, VirtualKeys.VK_I, VirtualKeys.VK_D, VirtualKeys.VK_H, + VirtualKeys.VK_T, VirtualKeys.VK_N, VirtualKeys.VK_S, VirtualKeys.VK_OEM_MINUS, VirtualKeys.VK_OEM_5, + VirtualKeys.VK_OEM_1, VirtualKeys.VK_Q, VirtualKeys.VK_J, VirtualKeys.VK_K, VirtualKeys.VK_X, + VirtualKeys.VK_B, VirtualKeys.VK_M, VirtualKeys.VK_W, VirtualKeys.VK_V, VirtualKeys.VK_Z, + VirtualKeys.VK_OEM_102 // the 102nd key (actually to the right of l-shift) + }; + + private static readonly VirtualKeys [] main_key_vkey_azerty = new VirtualKeys [] + { + // NOTE: this layout must concur with the scan codes layout above + VirtualKeys.VK_OEM_7, VirtualKeys.VK_1, VirtualKeys.VK_2, VirtualKeys.VK_3, VirtualKeys.VK_4, + VirtualKeys.VK_5, VirtualKeys.VK_6, VirtualKeys.VK_7, VirtualKeys.VK_8, VirtualKeys.VK_9, + VirtualKeys.VK_0, VirtualKeys.VK_OEM_4, VirtualKeys.VK_OEM_PLUS, VirtualKeys.VK_A, VirtualKeys.VK_Z, + VirtualKeys.VK_E, VirtualKeys.VK_R, VirtualKeys.VK_T, VirtualKeys.VK_Y, VirtualKeys.VK_U, + VirtualKeys.VK_I, VirtualKeys.VK_O, VirtualKeys.VK_P, VirtualKeys.VK_OEM_6, VirtualKeys.VK_OEM_1, + VirtualKeys.VK_Q, VirtualKeys.VK_S, VirtualKeys.VK_D, VirtualKeys.VK_F, VirtualKeys.VK_G, + VirtualKeys.VK_H, VirtualKeys.VK_J, VirtualKeys.VK_K, VirtualKeys.VK_L, VirtualKeys.VK_M, + VirtualKeys.VK_OEM_3, VirtualKeys.VK_OEM_5, VirtualKeys.VK_W, VirtualKeys.VK_X, VirtualKeys.VK_C, + VirtualKeys.VK_V, VirtualKeys.VK_B, VirtualKeys.VK_N, VirtualKeys.VK_OEM_COMMA, VirtualKeys.VK_OEM_PERIOD, + VirtualKeys.VK_OEM_2, VirtualKeys.VK_OEM_8, + VirtualKeys.VK_OEM_102 // the 102nd key (actually to the right of l-shift) + }; + + + //// WRONG + private static readonly VirtualKeys [] main_key_vkey_qwerty_jp106 = new VirtualKeys [] + { + // NOTE: this layout must concur with the scan codes layout above + VirtualKeys.VK_OEM_7, VirtualKeys.VK_1, VirtualKeys.VK_2, VirtualKeys.VK_3, VirtualKeys.VK_4, + VirtualKeys.VK_5, VirtualKeys.VK_6, VirtualKeys.VK_7, VirtualKeys.VK_8, VirtualKeys.VK_9, + VirtualKeys.VK_0, VirtualKeys.VK_OEM_4, VirtualKeys.VK_OEM_PLUS, VirtualKeys.VK_A, VirtualKeys.VK_Z, + VirtualKeys.VK_E, VirtualKeys.VK_R, VirtualKeys.VK_T, VirtualKeys.VK_Y, VirtualKeys.VK_U, + VirtualKeys.VK_I, VirtualKeys.VK_O, VirtualKeys.VK_P, VirtualKeys.VK_OEM_6, VirtualKeys.VK_OEM_1, + VirtualKeys.VK_Q, VirtualKeys.VK_S, VirtualKeys.VK_D, VirtualKeys.VK_F, VirtualKeys.VK_G, + VirtualKeys.VK_H, VirtualKeys.VK_J, VirtualKeys.VK_K, VirtualKeys.VK_L, VirtualKeys.VK_M, + VirtualKeys.VK_OEM_3, VirtualKeys.VK_OEM_5, VirtualKeys.VK_W, VirtualKeys.VK_X, VirtualKeys.VK_C, + VirtualKeys.VK_V, VirtualKeys.VK_B, VirtualKeys.VK_N, VirtualKeys.VK_OEM_COMMA, VirtualKeys.VK_OEM_PERIOD, + VirtualKeys.VK_OEM_2, VirtualKeys.VK_OEM_8, + VirtualKeys.VK_OEM_ATTN, + VirtualKeys.VK_OEM_102, // the 102nd key (actually to the right of l-shift) + VirtualKeys.VK_OEM_COPY, + VirtualKeys.VK_OEM_AUTO, + VirtualKeys.VK_OEM_ENLW, + VirtualKeys.VK_OEM_BACKTAB, + }; + + //// WRONG + private static readonly VirtualKeys [] main_key_vkey_qwertz_105 = new VirtualKeys [] + { + // NOTE: this layout must concur with the scan codes layout above + VirtualKeys.VK_OEM_7, VirtualKeys.VK_1, VirtualKeys.VK_2, VirtualKeys.VK_3, VirtualKeys.VK_4, + VirtualKeys.VK_5, VirtualKeys.VK_6, VirtualKeys.VK_7, VirtualKeys.VK_8, VirtualKeys.VK_9, + VirtualKeys.VK_0, VirtualKeys.VK_OEM_4, VirtualKeys.VK_OEM_PLUS, VirtualKeys.VK_A, VirtualKeys.VK_Z, + VirtualKeys.VK_E, VirtualKeys.VK_R, VirtualKeys.VK_T, VirtualKeys.VK_Y, VirtualKeys.VK_U, + VirtualKeys.VK_I, VirtualKeys.VK_O, VirtualKeys.VK_P, VirtualKeys.VK_OEM_6, VirtualKeys.VK_OEM_1, + VirtualKeys.VK_Q, VirtualKeys.VK_S, VirtualKeys.VK_D, VirtualKeys.VK_F, VirtualKeys.VK_G, + VirtualKeys.VK_H, VirtualKeys.VK_J, VirtualKeys.VK_K, VirtualKeys.VK_L, VirtualKeys.VK_M, + VirtualKeys.VK_OEM_3, VirtualKeys.VK_OEM_5, VirtualKeys.VK_W, VirtualKeys.VK_X, VirtualKeys.VK_C, + VirtualKeys.VK_V, VirtualKeys.VK_B, VirtualKeys.VK_N, VirtualKeys.VK_OEM_COMMA, VirtualKeys.VK_OEM_PERIOD, + VirtualKeys.VK_OEM_2, VirtualKeys.VK_OEM_8, + VirtualKeys.VK_OEM_102 // the 102nd key (actually to the right of l-shift) + }; + + //// WRONG + private static readonly VirtualKeys [] main_key_vkey_qwerty_v2 = new VirtualKeys [] + { + // NOTE: this layout must concur with the scan codes layout above + VirtualKeys.VK_OEM_7, VirtualKeys.VK_1, VirtualKeys.VK_2, VirtualKeys.VK_3, VirtualKeys.VK_4, + VirtualKeys.VK_5, VirtualKeys.VK_6, VirtualKeys.VK_7, VirtualKeys.VK_8, VirtualKeys.VK_9, + VirtualKeys.VK_0, VirtualKeys.VK_OEM_4, VirtualKeys.VK_OEM_PLUS, VirtualKeys.VK_A, VirtualKeys.VK_Z, + VirtualKeys.VK_E, VirtualKeys.VK_R, VirtualKeys.VK_T, VirtualKeys.VK_Y, VirtualKeys.VK_U, + VirtualKeys.VK_I, VirtualKeys.VK_O, VirtualKeys.VK_P, VirtualKeys.VK_OEM_6, VirtualKeys.VK_OEM_1, + VirtualKeys.VK_Q, VirtualKeys.VK_S, VirtualKeys.VK_D, VirtualKeys.VK_F, VirtualKeys.VK_G, + VirtualKeys.VK_H, VirtualKeys.VK_J, VirtualKeys.VK_K, VirtualKeys.VK_L, VirtualKeys.VK_M, + VirtualKeys.VK_OEM_3, VirtualKeys.VK_OEM_5, VirtualKeys.VK_W, VirtualKeys.VK_X, VirtualKeys.VK_C, + VirtualKeys.VK_V, VirtualKeys.VK_B, VirtualKeys.VK_N, VirtualKeys.VK_OEM_COMMA, VirtualKeys.VK_OEM_PERIOD, + VirtualKeys.VK_OEM_2, VirtualKeys.VK_OEM_8, + VirtualKeys.VK_OEM_102 // the 102nd key (actually to the right of l-shift) + }; + + private static readonly VirtualKeys [] main_key_vkey_abnt_qwerty = new VirtualKeys [] + { + // NOTE: this layout must concur with the scan codes layout above + VirtualKeys.VK_OEM_7, VirtualKeys.VK_1, VirtualKeys.VK_2, VirtualKeys.VK_3, VirtualKeys.VK_4, + VirtualKeys.VK_5, VirtualKeys.VK_6, VirtualKeys.VK_7, VirtualKeys.VK_8, VirtualKeys.VK_9, + VirtualKeys.VK_0, VirtualKeys.VK_OEM_MINUS, VirtualKeys.VK_OEM_PLUS, VirtualKeys.VK_Q, + VirtualKeys.VK_W, VirtualKeys.VK_E, VirtualKeys.VK_R, VirtualKeys.VK_T, VirtualKeys.VK_Y, + VirtualKeys.VK_U, VirtualKeys.VK_I, VirtualKeys.VK_O, VirtualKeys.VK_P, VirtualKeys.VK_OEM_3, + VirtualKeys.VK_OEM_4, VirtualKeys.VK_A, VirtualKeys.VK_S, VirtualKeys.VK_D, VirtualKeys.VK_F, + VirtualKeys.VK_G, VirtualKeys.VK_H, VirtualKeys.VK_J, VirtualKeys.VK_K, VirtualKeys.VK_L, + VirtualKeys.VK_OEM_8, VirtualKeys.VK_OEM_102, VirtualKeys.VK_OEM_6, VirtualKeys.VK_Z, + VirtualKeys.VK_X, VirtualKeys.VK_C, VirtualKeys.VK_V, VirtualKeys.VK_B, VirtualKeys.VK_N, + VirtualKeys.VK_M, VirtualKeys.VK_OEM_COMMA, VirtualKeys.VK_OEM_PERIOD, VirtualKeys.VK_OEM_1, + VirtualKeys.VK_OEM_2, VirtualKeys.VK_OEM_5 + }; + /* + private static readonly VirtualKeys [] main_key_vkey_qwerty_jp = new VirtualKeys [] + { + VirtualKeys.VK_1, VirtualKeys.VK_2, VirtualKeys.VK_3, VirtualKeys.VK_4, + VirtualKeys.VK_5, VirtualKeys.VK_6, VirtualKeys.VK_7, VirtualKeys.VK_8, VirtualKeys.VK_9, + VirtualKeys.VK_0, VirtualKeys.VK_OEM_MINUS, VirtualKeys.VK_OEM_PLUS,VirtualKeys.VK_OEM_3, + VirtualKeys.VK_Q, VirtualKeys.VK_W, VirtualKeys.VK_E, VirtualKeys.VK_R, VirtualKeys.VK_T + VirtualKeys.VK_Y, VirtualKeys.VK_U, VirtualKeys.VK_I, VirtualKeys.VK_O, VirtualKeys.VK_P + VirtualKeys.VK_OEM_4,VirtualKeys.VK_OEM_6, + VirtualKeys.VK_A, VirtualKeys.VK_S, VirtualKeys.VK_D, VirtualKeys.VK_F, + VirtualKeys.VK_G, VirtualKeys.VK_H, VirtualKeys.VK_J, VirtualKeys.VK_K, VirtualKeys.VK_L, + VirtualKeys.VK_OEM_1, VirtualKeys.VK_OEM_7, VirtualKeys.VK_OEM_5, VirtualKeys.VK_Z, + VirtualKeys.VK_X, VirtualKeys.VK_C, VirtualKeys.VK_V, VirtualKeys.VK_B, VirtualKeys.VK_N, + VirtualKeys.VK_M, VirtualKeys.VK_OEM_COMMA, VirtualKeys.VK_OEM_PERIOD, VirtualKeys.VK_OEM_2, + VirtualKeys.VK_OEM_102 + };*/ + + internal enum VirtualKeys { + VK_LBUTTON = 0x01, + VK_RBUTTON = 0x02, + VK_CANCEL = 0x03, + VK_MBUTTON = 0x04, + VK_XBUTTON1 = 0x05, + VK_XBUTTON2 = 0x06, + VK_BACK = 0x08, + VK_TAB = 0x09, + VK_CLEAR = 0x0C, + VK_RETURN = 0x0D, + VK_SHIFT = 0x10, + VK_CONTROL = 0x11, + VK_MENU = 0x12, + VK_PAUSE = 0x13, + VK_CAPITAL = 0x14, + VK_ESCAPE = 0x1B, + VK_SPACE = 0x20, + VK_PRIOR = 0x21, + VK_NEXT = 0x22, + VK_END = 0x23, + VK_HOME = 0x24, + VK_LEFT = 0x25, + VK_UP = 0x26, + VK_RIGHT = 0x27, + VK_DOWN = 0x28, + VK_SELECT = 0x29, + VK_PRINT = 0x2A, + VK_EXECUTE = 0x2B, + VK_SNAPSHOT = 0x2C, + VK_INSERT = 0x2D, + VK_DELETE = 0x2E, + VK_HELP = 0x2F, + VK_0 = 0x30, + VK_1 = 0x31, + VK_2 = 0x32, + VK_3 = 0x33, + VK_4 = 0x34, + VK_5 = 0x35, + VK_6 = 0x36, + VK_7 = 0x37, + VK_8 = 0x38, + VK_9 = 0x39, + VK_A = 0x41, + VK_B = 0x42, + VK_C = 0x43, + VK_D = 0x44, + VK_E = 0x45, + VK_F = 0x46, + VK_G = 0x47, + VK_H = 0x48, + VK_I = 0x49, + VK_J = 0x4A, + VK_K = 0x4B, + VK_L = 0x4C, + VK_M = 0x4D, + VK_N = 0x4E, + VK_O = 0x4F, + VK_P = 0x50, + VK_Q = 0x51, + VK_R = 0x52, + VK_S = 0x53, + VK_T = 0x54, + VK_U = 0x55, + VK_V = 0x56, + VK_W = 0x57, + VK_X = 0x58, + VK_Y = 0x59, + VK_Z = 0x5A, + VK_LWIN = 0x5B, + VK_RWIN = 0x5C, + VK_APPS = 0x5D, + VK_NUMPAD0 = 0x60, + VK_NUMPAD1 = 0x61, + VK_NUMPAD2 = 0x62, + VK_NUMPAD3 = 0x63, + VK_NUMPAD4 = 0x64, + VK_NUMPAD5 = 0x65, + VK_NUMPAD6 = 0x66, + VK_NUMPAD7 = 0x67, + VK_NUMPAD8 = 0x68, + VK_NUMPAD9 = 0x69, + VK_MULTIPLY = 0x6A, + VK_ADD = 0x6B, + VK_SEPARATOR = 0x6C, + VK_SUBTRACT = 0x6D, + VK_DECIMAL = 0x6E, + VK_DIVIDE = 0x6F, + VK_F1 = 0x70, + VK_F2 = 0x71, + VK_F3 = 0x72, + VK_F4 = 0x73, + VK_F5 = 0x74, + VK_F6 = 0x75, + VK_F7 = 0x76, + VK_F8 = 0x77, + VK_F9 = 0x78, + VK_F10 = 0x79, + VK_F11 = 0x7A, + VK_F12 = 0x7B, + VK_F13 = 0x7C, + VK_F14 = 0x7D, + VK_F15 = 0x7E, + VK_F16 = 0x7F, + VK_F17 = 0x80, + VK_F18 = 0x81, + VK_F19 = 0x82, + VK_F20 = 0x83, + VK_F21 = 0x84, + VK_F22 = 0x85, + VK_F23 = 0x86, + VK_F24 = 0x87, + VK_NUMLOCK = 0x90, + VK_SCROLL = 0x91, + VK_LSHIFT = 0xA0, + VK_RSHIFT = 0xA1, + VK_LCONTROL = 0xA2, + VK_RCONTROL = 0xA3, + VK_LMENU = 0xA4, + VK_RMENU = 0xA5, + VK_OEM_1 = 0xBA, + VK_OEM_PLUS = 0xBB, + VK_OEM_COMMA = 0xBC, + VK_OEM_MINUS = 0xBD, + VK_OEM_PERIOD = 0xBE, + VK_OEM_2 = 0xBF, + VK_OEM_3 = 0xC0, + VK_OEM_4 = 0xDB, + VK_OEM_5 = 0xDC, + VK_OEM_6 = 0xDD, + VK_OEM_7 = 0xDE, + VK_OEM_8 = 0xDF, + VK_OEM_AX = 0xE1, + VK_OEM_102 = 0xE2, + VK_ICO_HELP = 0xE3, + VK_ICO_00 = 0xE4, + VK_PROCESSKEY = 0xE5, + VK_OEM_ATTN = 0xF0, + VK_OEM_COPY = 0xF2, + VK_OEM_AUTO = 0xF3, + VK_OEM_ENLW = 0xF4, + VK_OEM_BACKTAB = 0xF5, + VK_ATTN = 0xF6, + VK_CRSEL = 0xF7, + VK_EXSEL = 0xF8, + VK_EREOF = 0xF9, + VK_PLAY = 0xFA, + VK_ZOOM = 0xFB, + VK_NONAME = 0xFC, + VK_PA1 = 0xFD, + VK_OEM_CLEAR = 0xFE, + } +} + diff --git a/source/ShiftUI/Link/LinkArea.cs b/source/ShiftUI/Link/LinkArea.cs new file mode 100644 index 0000000..a2e6427 --- /dev/null +++ b/source/ShiftUI/Link/LinkArea.cs @@ -0,0 +1,183 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// +// Dennis Hayes, dennish@raytek.com +// Andreas Nahr, ClassDevelopment@A-SoftTech.com +// Jordi Mas i Hernandez, jordi@ximian.com +// + + +// COMPLETE + +using System.ComponentModel; +using System.Globalization; +using System; + +namespace ShiftUI +{ + [Serializable] + [TypeConverter(typeof(LinkArea.LinkAreaConverter))] + public struct LinkArea + { + #region LinkAreaConverter Class + public class LinkAreaConverter : TypeConverter { + public LinkAreaConverter() { + } + + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { + if (sourceType == typeof(string)) { + return true; + } + return base.CanConvertFrom(context, sourceType); + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { + if (destinationType == typeof(string)) { + return true; + } + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) { + string[] parts; + int start; + int length; + + if ((value == null) || !(value is String)) { + return base.ConvertFrom (context, culture, value); + } + + if (culture == null) { + culture = CultureInfo.CurrentCulture; + } + + parts = ((string)value).Split(culture.TextInfo.ListSeparator.ToCharArray()); + start = int.Parse(parts[0].Trim()); + length = int.Parse(parts[1].Trim()); + return new LinkArea(start, length); + } + + public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) { + LinkArea l; + + if ((value == null) || !(value is LinkArea) || (destinationType != typeof(string))) { + return base.ConvertTo (context, culture, value, destinationType); + } + + if (culture == null) { + culture = CultureInfo.CurrentCulture; + } + + l = (LinkArea)value; + + + return l.Start.ToString() + culture.TextInfo.ListSeparator + l.Length.ToString(); + } + + public override object CreateInstance(ITypeDescriptorContext context, System.Collections.IDictionary propertyValues) { + return new LinkArea((int)propertyValues["Start"], (int)propertyValues["Length"]); + } + + public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) { + return true; + } + + public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) { + return TypeDescriptor.GetProperties(typeof(LinkArea), attributes); + } + + public override bool GetPropertiesSupported(ITypeDescriptorContext context) { + return true; + } + } + #endregion // LinkAreaConverter Class + + private int start; + private int length; + + public LinkArea (int start, int length) + { + this.start = start; + this.length = length; + } + + #region Public Properties + + public int Start { + get { return start; } + set { start = value; } + } + + public int Length { + get { return length; } + set { length = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public bool IsEmpty { + get { + if (start == 0 && length == 0) + return true; + else + return false; + + } + } + + #endregion //Public Properties + + #region Methods + + public override bool Equals (object o) + { + if (!(o is LinkArea)) + return false; + + LinkArea comp = (LinkArea) o; + return (comp.Start == start && comp.Length == length); + } + + public override int GetHashCode () + { + return start << 4 | length; + } + + public override string ToString () + { + return string.Format ("{{Start={0}, Length={1}}}", this.start.ToString (), this.length.ToString ()); + } + + public static bool operator == (LinkArea linkArea1, LinkArea linkArea2) + { + return (linkArea1.Length == linkArea2.Length) && (linkArea1.Start == linkArea2.Start); + } + + public static bool operator != (LinkArea linkArea1, LinkArea linkArea2) + { + return !(linkArea1 == linkArea2); + } + #endregion //Methods + + } +} diff --git a/source/ShiftUI/Link/LinkBehavior.cs b/source/ShiftUI/Link/LinkBehavior.cs new file mode 100644 index 0000000..9c9ad4f --- /dev/null +++ b/source/ShiftUI/Link/LinkBehavior.cs @@ -0,0 +1,39 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// + + +// COMPLETE + +namespace ShiftUI +{ + public enum LinkBehavior + { + SystemDefault = 0, + AlwaysUnderline = 1, + HoverUnderline = 2, + NeverUnderline = 3, + } +} + diff --git a/source/ShiftUI/Link/LinkClickedEventArgs.cs b/source/ShiftUI/Link/LinkClickedEventArgs.cs new file mode 100644 index 0000000..29b9801 --- /dev/null +++ b/source/ShiftUI/Link/LinkClickedEventArgs.cs @@ -0,0 +1,49 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// + + +// COMPLETE + +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI +{ + [ComVisible(true)] + public class LinkClickedEventArgs : EventArgs + { + private string link_text; + + public LinkClickedEventArgs (string linkText) + { + this.link_text = linkText; + } + + public string LinkText + { + get { return link_text; } + } + } +} diff --git a/source/ShiftUI/Link/LinkClickedEventHandler.cs b/source/ShiftUI/Link/LinkClickedEventHandler.cs new file mode 100644 index 0000000..fe3da4a --- /dev/null +++ b/source/ShiftUI/Link/LinkClickedEventHandler.cs @@ -0,0 +1,33 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// +// COMPLETE + +namespace ShiftUI +{ + public delegate void LinkClickedEventHandler (object sender, LinkClickedEventArgs e); +} + + + diff --git a/source/ShiftUI/Link/LinkConverter.cs b/source/ShiftUI/Link/LinkConverter.cs new file mode 100644 index 0000000..a711c92 --- /dev/null +++ b/source/ShiftUI/Link/LinkConverter.cs @@ -0,0 +1,86 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Jonathan Pobst monkey@jpobst.com +// + +using System.ComponentModel; +using System.Globalization; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI +{ + public class LinkConverter : TypeConverter + { + #region Constructors + public LinkConverter () { } + #endregion Constructors + + #region Public Methods + public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof (string)) + return true; + + return false; + } + + public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof (string)) + return true; + + return base.CanConvertTo (context, destinationType); + } + + public override object ConvertFrom (ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + { + if ((value == null) || !(value is String)) + return base.ConvertFrom (context, culture, value); + + if (culture == null) + culture = CultureInfo.CurrentCulture; + + if (((string)value).Length == 0) + return null; + + string[] parts = ((string)value).Split (culture.TextInfo.ListSeparator.ToCharArray ()); + + return new LinkLabel.Link (int.Parse (parts[0].Trim ()), int.Parse (parts[1].Trim ())); + } + + public override object ConvertTo (ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) + { + if ((value == null) || !(value is LinkLabel.Link) || (destinationType != typeof (string))) + return base.ConvertTo (context, culture, value, destinationType); + + if (culture == null) + culture = CultureInfo.CurrentCulture; + + LinkLabel.Link l = (LinkLabel.Link)value; + + return string.Format ("{0}{2} {1}", l.Start, l.Length, culture.TextInfo.ListSeparator); + } + #endregion Public Methods + } +} diff --git a/source/ShiftUI/Link/LinkLabelLinkClickedEventArgs.cs b/source/ShiftUI/Link/LinkLabelLinkClickedEventArgs.cs new file mode 100644 index 0000000..2eb781f --- /dev/null +++ b/source/ShiftUI/Link/LinkLabelLinkClickedEventArgs.cs @@ -0,0 +1,58 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// Everaldo Canuto, ecanuto@novell.com +// + +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI +{ + [ComVisible(true)] + public class LinkLabelLinkClickedEventArgs : EventArgs + { + private MouseButtons button; + private LinkLabel.Link link; + + public LinkLabelLinkClickedEventArgs (LinkLabel.Link link) + { + this.button = MouseButtons.Left; + this.link = link; + } + + public LinkLabelLinkClickedEventArgs (LinkLabel.Link link, MouseButtons button) + { + this.button = button; + this.link = link; + } + + public MouseButtons Button { + get { return this.button; } + } + + public LinkLabel.Link Link { + get { return link; } + } + } +} diff --git a/source/ShiftUI/Link/LinkLabelLinkClickedEventHandler.cs b/source/ShiftUI/Link/LinkLabelLinkClickedEventHandler.cs new file mode 100644 index 0000000..05fd87f --- /dev/null +++ b/source/ShiftUI/Link/LinkLabelLinkClickedEventHandler.cs @@ -0,0 +1,38 @@ +// +// System.LinkLabelLinkClickEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// Dennis hayes (dennish@raytek.com) +// +// + + +// COMPLETE + +namespace ShiftUI +{ + public delegate void LinkLabelLinkClickedEventHandler (object sender, LinkLabelLinkClickedEventArgs e); + +} diff --git a/source/ShiftUI/Link/LinkState.cs b/source/ShiftUI/Link/LinkState.cs new file mode 100644 index 0000000..b500298 --- /dev/null +++ b/source/ShiftUI/Link/LinkState.cs @@ -0,0 +1,41 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// + + +// COMPLETE + + +namespace ShiftUI +{ + public enum LinkState + { + Normal = 0, + Hover = 1, + Active = 2, + Visited = 4 + } +} + + diff --git a/source/ShiftUI/ListView/ColumnClickEventArgs.cs b/source/ShiftUI/ListView/ColumnClickEventArgs.cs new file mode 100644 index 0000000..24e07aa --- /dev/null +++ b/source/ShiftUI/ListView/ColumnClickEventArgs.cs @@ -0,0 +1,52 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Ravindra (rkumar@novell.com) +// + + +// COMPLETE + +using System; + +namespace ShiftUI +{ + public class ColumnClickEventArgs : EventArgs + { + private int column; + + #region Public Constructors + public ColumnClickEventArgs (int column) + { + this.column = column; + } + #endregion // Public Constructors + + #region Public Instance Properties + public int Column { + get { + return column; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/ListView/ColumnClickEventHandler.cs b/source/ShiftUI/ListView/ColumnClickEventHandler.cs new file mode 100644 index 0000000..725e57b --- /dev/null +++ b/source/ShiftUI/ListView/ColumnClickEventHandler.cs @@ -0,0 +1,29 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Ravindra (rkumar@novell.com) +// + +namespace ShiftUI +{ + public delegate void ColumnClickEventHandler (object sender, ColumnClickEventArgs e); +} diff --git a/source/ShiftUI/ListView/ColumnHeader.cs b/source/ShiftUI/ListView/ColumnHeader.cs new file mode 100644 index 0000000..118d9a6 --- /dev/null +++ b/source/ShiftUI/ListView/ColumnHeader.cs @@ -0,0 +1,398 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Author: +// Ravindra (rkumar@novell.com) +// + + +// COMPLETE + + +using System.ComponentModel; +using System.Drawing; +using System; + +namespace ShiftUI +{ + [DefaultProperty ("Text")] + [DesignTimeVisible (false)] + [ToolboxItem (false)] + [TypeConverter (typeof (ColumnHeaderConverter))] + public class ColumnHeader : Component, ICloneable + { + #region Instance Variables + private StringFormat format = new StringFormat (); + private string text = "ColumnHeader"; + private HorizontalAlignment text_alignment = HorizontalAlignment.Left; + private int width = ThemeEngine.Current.ListViewDefaultColumnWidth; + private int image_index = -1; + private string image_key = String.Empty; + private string name = String.Empty; + private object tag; + private int display_index = -1; + + // internal variables + Rectangle column_rect = Rectangle.Empty; + bool pressed = false; + ListView owner; + #endregion // Instance Variables + + #region Internal Constructor + internal ColumnHeader (ListView owner, string text, + HorizontalAlignment alignment, int width) + { + this.owner = owner; + this.text = text; + this.width = width; + this.text_alignment = alignment; + CalcColumnHeader (); + } + + internal ColumnHeader (string key, string text, int width, HorizontalAlignment textAlign) + { + Name = key; + Text = text; + this.width = width; + this.text_alignment = textAlign; + CalcColumnHeader (); + } + #endregion // Internal Constructor + + #region Public Constructors + public ColumnHeader () { } + + public ColumnHeader (int imageIndex) + { + ImageIndex = imageIndex; + } + + public ColumnHeader (string imageKey) + { + ImageKey = imageKey; + } + #endregion // Public Constructors + + #region Private Internal Methods Properties + internal bool Pressed { + get { return pressed; } + set { pressed = value; } + } + + internal int X { + get { return column_rect.X; } + set { column_rect.X = value; } + } + + internal int Y { + get { return column_rect.Y; } + set { column_rect.Y = value; } + } + + internal int Wd { + get { return column_rect.Width; } + set { column_rect.Width = value; } + } + + internal int Ht { + get { return column_rect.Height; } + set { column_rect.Height = value; } + } + + internal Rectangle Rect { + get { return column_rect; } + set { column_rect = value; } + } + + internal StringFormat Format { + get { return format; } + } + + internal int InternalDisplayIndex { + get { return display_index; } + set { display_index = value; } + } + + internal void CalcColumnHeader () + { + if (text_alignment == HorizontalAlignment.Center) + format.Alignment = StringAlignment.Center; + else if (text_alignment == HorizontalAlignment.Right) + format.Alignment = StringAlignment.Far; + else + format.Alignment = StringAlignment.Near; + format.LineAlignment = StringAlignment.Center; + format.Trimming = StringTrimming.EllipsisCharacter; + // text is wrappable only in LargeIcon and SmallIcon views + format.FormatFlags = StringFormatFlags.NoWrap; + + if (owner != null) + column_rect.Height = ThemeEngine.Current.ListViewGetHeaderHeight (owner, owner.Font); + else + column_rect.Height = ThemeEngine.Current.ListViewGetHeaderHeight (null, ThemeEngine.Current.DefaultFont); + + column_rect.Width = 0; + + if (width >= 0) // manual width + column_rect.Width = width; + else if (Index != -1) { // automatic width, either -1 or -2 + // try to expand if we are the last column + bool expand_to_right = Index == owner.Columns.Count - 1 && width == -2; + Rectangle visible_area = owner.ClientRectangle; + + column_rect.Width = owner.GetChildColumnSize (Index).Width; + width = column_rect.Width; + + // expand only if we have free space to the right + if (expand_to_right && column_rect.X + column_rect.Width < visible_area.Width) { + width = visible_area.Width - column_rect.X; + if (owner.v_scroll.Visible) + width -= owner.v_scroll.Width; + + column_rect.Width = width; + } + } + } + + internal void SetListView (ListView list_view) + { + owner = list_view; + } + + #endregion // Private Internal Methods Properties + + #region Public Instance Properties + + [Localizable (true)] + [RefreshProperties (RefreshProperties.Repaint)] + public int DisplayIndex { + get { + if (owner == null) + return display_index; + + return owner.GetReorderedColumnIndex (this); + } + set { + if (owner == null) { + display_index = value; + return; + } + if (value < 0 || value >= owner.Columns.Count) + throw new ArgumentOutOfRangeException ("DisplayIndex"); + + owner.ReorderColumn (this, value, false); + } + } + + [DefaultValue (-1)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, + //"System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)] + [RefreshProperties (RefreshProperties.Repaint)] + [TypeConverter (typeof (ImageIndexConverter))] + public int ImageIndex { + get { + return image_index; + } + set { + if (value < -1) + throw new ArgumentOutOfRangeException ("ImageIndex"); + + image_index = value; + image_key = String.Empty; + + if (owner != null) + owner.header_control.Invalidate (); + } + } + + [DefaultValue ("")] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, + //"System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)] + [RefreshProperties (RefreshProperties.Repaint)] + [TypeConverter (typeof (ImageKeyConverter))] + public string ImageKey { + get { + return image_key; + } + set { + image_key = value == null ? String.Empty : value; + image_index = -1; + + if (owner != null) + owner.header_control.Invalidate (); + } + } + + [Browsable (false)] + public ImageList ImageList { + get { + if (owner == null) + return null; + + return owner.SmallImageList; + } + } + + [Browsable (false)] + public int Index { + get { + if (owner != null) + return owner.Columns.IndexOf (this); + + return -1; + } + } + + [Browsable (false)] + public ListView ListView { + get { return owner; } + } + + [Browsable (false)] + public string Name { + get { + return name; + } + set { + name = value == null ? String.Empty : value; + } + } + + [DefaultValue (null)] + [BindableAttribute (true)] + [LocalizableAttribute (false)] + [TypeConverter (typeof (StringConverter))] + public object Tag { + get { + return tag; + } + set { + tag = value; + } + } + + [Localizable (true)] + public string Text { + get { return text; } + set { + if (text != value) { + text = value; + if (owner != null) + owner.Redraw (true); + + // UIA Framework: Raising Value changed event + OnUIATextChanged (); + } + } + } + + [DefaultValue (HorizontalAlignment.Left)] + [Localizable (true)] + public HorizontalAlignment TextAlign { + get { return text_alignment; } + set { + text_alignment = value; + if (owner != null) + owner.Redraw (true); + } + } + + [DefaultValue (60)] + [Localizable (true)] + public int Width { + get { return width; } + set { + if (width != value) { + width = value; + if (owner != null) { + owner.Redraw (true); + owner.RaiseColumnWidthChanged (this); + } + } + } + } + #endregion // Public Instance Properties + + #region Public Methods + public void AutoResize (ColumnHeaderAutoResizeStyle headerAutoResize) + { + switch (headerAutoResize) { + case ColumnHeaderAutoResizeStyle.None: + break; + case ColumnHeaderAutoResizeStyle.ColumnContent: + Width = -1; + break; + case ColumnHeaderAutoResizeStyle.HeaderSize: + Width = -2; + break; + default: + throw new InvalidEnumArgumentException ("headerAutoResize", (int) headerAutoResize, + typeof (ColumnHeaderAutoResizeStyle)); + } + } + + public object Clone () + { + ColumnHeader columnHeader = new ColumnHeader (); + columnHeader.text = text; + columnHeader.text_alignment = text_alignment; + columnHeader.width = width; + columnHeader.owner = owner; + columnHeader.format = (StringFormat) Format.Clone (); + columnHeader.column_rect = Rectangle.Empty; + return columnHeader; + } + + public override string ToString () + { + return string.Format ("ColumnHeader: Text: {0}", text); + } + #endregion // Public Methods + + #region Protected Methods + protected override void Dispose (bool disposing) + { + base.Dispose (disposing); + } + #endregion // Protected Methods + + + #region UIA Framework: Methods, Properties and Events + + static object UIATextChangedEvent = new object (); + + internal event EventHandler UIATextChanged { + add { Events.AddHandler (UIATextChangedEvent, value); } + remove { Events.RemoveHandler (UIATextChangedEvent, value); } + } + + private void OnUIATextChanged () + { + EventHandler eh = (EventHandler) Events [UIATextChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + + #endregion + } +} diff --git a/source/ShiftUI/ListView/ColumnHeaderAutoResizeStyle.cs b/source/ShiftUI/ListView/ColumnHeaderAutoResizeStyle.cs new file mode 100644 index 0000000..4856dee --- /dev/null +++ b/source/ShiftUI/ListView/ColumnHeaderAutoResizeStyle.cs @@ -0,0 +1,38 @@ +// +// ColumnHeaderAutoResizeStyle.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum ColumnHeaderAutoResizeStyle + { + None = 0, + HeaderSize = 1, + ColumnContent = 2 + } +} diff --git a/source/ShiftUI/ListView/ColumnHeaderConverter.cs b/source/ShiftUI/ListView/ColumnHeaderConverter.cs new file mode 100644 index 0000000..8334d40 --- /dev/null +++ b/source/ShiftUI/ListView/ColumnHeaderConverter.cs @@ -0,0 +1,96 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// olivier Dufour olivier.duff@free.fr +// + + +// COMPLETE + +using System.ComponentModel; +using System.ComponentModel.Design.Serialization; +using System.Collections; +using System.Globalization; +using System.Reflection; +using System; + +namespace ShiftUI +{ + public class ColumnHeaderConverter : ExpandableObjectConverter + { + public ColumnHeaderConverter () + { + } + + public override Object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, Object value, Type destinationType) + { + if (destinationType == typeof (InstanceDescriptor) && value is ColumnHeader) + { + ConstructorInfo constructor_info; + Type[] type; + ColumnHeader column_header; + + column_header = (ColumnHeader)value; + if (column_header.ImageIndex != -1) + { + type = new Type[] { typeof (int) }; + constructor_info = typeof (ColumnHeader).GetConstructor (type); + if (constructor_info != null) + { + object[] arguments = new object[] { column_header.ImageIndex }; + return new InstanceDescriptor (constructor_info, (ICollection)arguments, false); + } + } + else if (string.IsNullOrEmpty(column_header.ImageKey)) + { + type = new Type[] { typeof (string) }; + constructor_info = typeof (ColumnHeader).GetConstructor (type); + if (constructor_info != null) + { + object[] arguments = new object[] { column_header.ImageKey }; + return new InstanceDescriptor (constructor_info, (ICollection)arguments, false); + } + } + else + { + type = Type.EmptyTypes; + constructor_info = typeof (ColumnHeader).GetConstructor (type); + if (constructor_info != null) + { + object[] arguments = new object[0] {}; + return new InstanceDescriptor (constructor_info, (ICollection)arguments, false); + } + } + + } + return base.ConvertTo (context, culture, value, destinationType); + } + + public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof (InstanceDescriptor)) + return true; + else + return base.CanConvertTo (context, destinationType); + } + } +} diff --git a/source/ShiftUI/ListView/ColumnHeaderStyle.cs b/source/ShiftUI/ListView/ColumnHeaderStyle.cs new file mode 100644 index 0000000..ec66f6a --- /dev/null +++ b/source/ShiftUI/ListView/ColumnHeaderStyle.cs @@ -0,0 +1,36 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Ravindra (rkumar@novell.com) +// +// COMPLETE +// + +namespace ShiftUI +{ + public enum ColumnHeaderStyle + { + None = 0, + Nonclickable = 1, + Clickable = 2 + } +} diff --git a/source/ShiftUI/ListView/ColumnReorderedEventArgs.cs b/source/ShiftUI/ListView/ColumnReorderedEventArgs.cs new file mode 100644 index 0000000..b9f6fa0 --- /dev/null +++ b/source/ShiftUI/ListView/ColumnReorderedEventArgs.cs @@ -0,0 +1,64 @@ +// +// ColumnReorderedEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +using System.ComponentModel; + +namespace ShiftUI +{ + public class ColumnReorderedEventArgs : CancelEventArgs + { + + private ColumnHeader header; + private int new_display_index; + private int old_display_index; + + #region Public Constructors + public ColumnReorderedEventArgs(int oldDisplayIndex, int newDisplayIndex, ColumnHeader header) : base () + { + this.old_display_index = oldDisplayIndex; + this.new_display_index = newDisplayIndex; + this.header = header; + } + #endregion // Public Constructors + + #region Public Instance Properties + public int OldDisplayIndex { + get { return this.old_display_index; } + } + + public int NewDisplayIndex { + get { return this.new_display_index; } + } + + public ColumnHeader Header { + get { return this.header; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/ListView/ColumnReorderedEventHandler.cs b/source/ShiftUI/ListView/ColumnReorderedEventHandler.cs new file mode 100644 index 0000000..2a2daa0 --- /dev/null +++ b/source/ShiftUI/ListView/ColumnReorderedEventHandler.cs @@ -0,0 +1,32 @@ +// +// ColumnReorderedEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ColumnReorderedEventHandler(object sender, ColumnReorderedEventArgs e); +} diff --git a/source/ShiftUI/ListView/ColumnStyle.cs b/source/ShiftUI/ListView/ColumnStyle.cs new file mode 100644 index 0000000..430f884 --- /dev/null +++ b/source/ShiftUI/ListView/ColumnStyle.cs @@ -0,0 +1,72 @@ +// +// ColumnStyle.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Author: +// Miguel de Icaza (miguel@gnome.org) +// +// (C) 2004 Novell, Inc. +// +using System; + + +namespace ShiftUI +{ + public class ColumnStyle : TableLayoutStyle + { + float width; + + public ColumnStyle () + { + this.width = 0; + } + + public ColumnStyle (SizeType sizeType) + { + this.width = 0; + base.SizeType = sizeType; + } + + public ColumnStyle (SizeType sizeType, float width) + { + if (width < 0) + throw new ArgumentOutOfRangeException ("height"); + + base.SizeType = sizeType; + this.width = width; + } + + public float Width { + get { return this.width; } + set { + if (value < 0) + throw new ArgumentOutOfRangeException (); + + if (width != value) { + width = value; + if (base.Owner != null) + base.Owner.PerformLayout (); + } + } + } + } +} diff --git a/source/ShiftUI/ListView/ColumnWidthChangedEventArgs.cs b/source/ShiftUI/ListView/ColumnWidthChangedEventArgs.cs new file mode 100644 index 0000000..9c412b5 --- /dev/null +++ b/source/ShiftUI/ListView/ColumnWidthChangedEventArgs.cs @@ -0,0 +1,50 @@ +// +// ColumnWidthChangedEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + public class ColumnWidthChangedEventArgs : EventArgs + { + + private int column_index; + + #region Public Constructors + public ColumnWidthChangedEventArgs(int columnIndex) : base () + { + this.column_index = columnIndex; + } + #endregion // Public Constructors + + #region Public Instance Properties + public int ColumnIndex { + get { return this.column_index; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/ListView/ColumnWidthChangedEventHandler.cs b/source/ShiftUI/ListView/ColumnWidthChangedEventHandler.cs new file mode 100644 index 0000000..af566a6 --- /dev/null +++ b/source/ShiftUI/ListView/ColumnWidthChangedEventHandler.cs @@ -0,0 +1,32 @@ +// +// ColumnWidthChangedEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ColumnWidthChangedEventHandler (object sender, ColumnWidthChangedEventArgs e); +} diff --git a/source/ShiftUI/ListView/ColumnWidthChangingEventArgs.cs b/source/ShiftUI/ListView/ColumnWidthChangingEventArgs.cs new file mode 100644 index 0000000..94ba54f --- /dev/null +++ b/source/ShiftUI/ListView/ColumnWidthChangingEventArgs.cs @@ -0,0 +1,61 @@ +// +// ColumnWidthChangingEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.ComponentModel; + +namespace ShiftUI +{ + public class ColumnWidthChangingEventArgs : CancelEventArgs + { + private int column_index; + private int new_width; + + #region Public Constructors + public ColumnWidthChangingEventArgs (int columnIndex, int newWidth) : this (columnIndex, newWidth, false) + { + } + + public ColumnWidthChangingEventArgs (int columnIndex, int newWidth, bool cancel) : base (cancel) + { + this.column_index = columnIndex; + this.new_width = newWidth; + } + #endregion // Public Constructors + + #region Public Instance Properties + public int ColumnIndex { + get { return this.column_index; } + } + + public int NewWidth { + get { return this.new_width; } + set { this.new_width = value; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/ListView/ColumnWidthChangingEventHandler.cs b/source/ShiftUI/ListView/ColumnWidthChangingEventHandler.cs new file mode 100644 index 0000000..42a6be7 --- /dev/null +++ b/source/ShiftUI/ListView/ColumnWidthChangingEventHandler.cs @@ -0,0 +1,32 @@ +// +// ColumnWidthChangingEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ColumnWidthChangingEventHandler (object sender, ColumnWidthChangingEventArgs e); +} diff --git a/source/ShiftUI/ListView/ListViewAlignment.cs b/source/ShiftUI/ListView/ListViewAlignment.cs new file mode 100644 index 0000000..67d8314 --- /dev/null +++ b/source/ShiftUI/ListView/ListViewAlignment.cs @@ -0,0 +1,36 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Ravindra (rkumar@novell.com) +// + + +namespace ShiftUI +{ + public enum ListViewAlignment + { + Default = 0, + Left = 1, + Top = 2, + SnapToGrid = 5 + } +} diff --git a/source/ShiftUI/ListView/ListViewGroup.cs b/source/ShiftUI/ListView/ListViewGroup.cs new file mode 100644 index 0000000..516e045 --- /dev/null +++ b/source/ShiftUI/ListView/ListViewGroup.cs @@ -0,0 +1,265 @@ +// +// ListViewGroup.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Daniel Nauck +// +// Author: +// Daniel Nauck (dna(at)mono-project(dot)de) + +using System; +using System.Text; +using System.Runtime.Serialization; +using System.ComponentModel; +using System.Drawing; + +namespace ShiftUI +{ + [SerializableAttribute] + [ToolboxItem(false)] + [DesignTimeVisible(false)] + [DefaultProperty("Header")] + [TypeConverter (typeof (ListViewGroupConverter))] + public sealed class ListViewGroup : ISerializable + { + internal string header = string.Empty; + private string name = null; + private HorizontalAlignment header_alignment = HorizontalAlignment.Left; + private ListView list_view_owner = null; + private ListView.ListViewItemCollection items = null; + private object tag = null; + private Rectangle header_bounds = Rectangle.Empty; + internal int starting_row; // At which row the group starts + internal int starting_item; // The first display item in group + internal int rows; + internal int current_item; // Current item when doing layout + internal Point items_area_location; + bool is_default_group; + int item_count; // Used by default group to store item count + + #region ListViewGroup constructors + + public ListViewGroup () : this ("ListViewGroup", HorizontalAlignment.Left) + { + } + + public ListViewGroup (string header) : this (header, HorizontalAlignment.Left) + { + } + + public ListViewGroup (string key, string headerText) : this (headerText, HorizontalAlignment.Left) + { + name = key; + } + + public ListViewGroup (string header, HorizontalAlignment headerAlignment) + { + this.header = header; + header_alignment = headerAlignment; + items = new ListView.ListViewItemCollection (list_view_owner, this); + } + + private ListViewGroup(SerializationInfo info, StreamingContext context) + { + header = info.GetString("Header"); + name = info.GetString("Name"); + header_alignment = (HorizontalAlignment)info.GetInt32("HeaderAlignment"); + tag = info.GetValue("Tag", typeof(object)); + + int count = info.GetInt32("ListViewItemCount"); + if (count > 0) { + if(items == null) + items = new ListView.ListViewItemCollection(list_view_owner); + + for (int i = 0; i < count; i++) + { + items.Add((ListViewItem)info.GetValue(string.Format("ListViewItem_{0}", i), typeof(ListViewItem))); + } + } + } + + #endregion + + #region ListViewGroup properties + + public string Header { + get { return header; } + set { + if (!header.Equals(value)) { + header = value; + + if (list_view_owner != null) + list_view_owner.Redraw(true); + } + } + } + + [DefaultValue (HorizontalAlignment.Left)] + public HorizontalAlignment HeaderAlignment { + get { return header_alignment; } + set { + if (!header_alignment.Equals(value)) { + if (value != HorizontalAlignment.Left && value != HorizontalAlignment.Right && + value != HorizontalAlignment.Center) + throw new InvalidEnumArgumentException("HeaderAlignment", (int)value, typeof(HorizontalAlignment)); + + header_alignment = value; + + if (list_view_owner != null) + list_view_owner.Redraw(true); + } + } + } + + [Browsable(false)] + public ListView.ListViewItemCollection Items { + get { + return items; + } + } + + //[DesignerSerializationVisibility(0)] + [Browsable(false)] + public ListView ListView { + get { return list_view_owner; } + } + + internal ListView ListViewOwner { + get { return list_view_owner; } + set { + list_view_owner = value; + if (!is_default_group) + items.Owner = value; + } + } + + internal Rectangle HeaderBounds { + get { + Rectangle retval = header_bounds; + retval.X -= list_view_owner.h_marker; + retval.Y -= list_view_owner.v_marker; + return retval; + } + set { + if (list_view_owner != null) + list_view_owner.item_control.Invalidate (HeaderBounds); + + header_bounds = value; + + if (list_view_owner != null) + list_view_owner.item_control.Invalidate (HeaderBounds); + + } + } + + internal bool IsDefault { + get { + return is_default_group; + } + set { + is_default_group = value; + } + } + + internal int ItemCount { + get { + return is_default_group ? item_count : items.Count; + } + set { + if (!is_default_group) + throw new InvalidOperationException ("ItemCount cannot be set for non-default groups."); + + item_count = value; + } + } + + internal int GetActualItemCount () + { + if (is_default_group) + return item_count; + + int count = 0; + for (int i = 0; i < items.Count; i++) + if (items [i].ListView != null) // Ignore. + count++; + + return count; + } + + [Browsable(true)] + [DefaultValue("")] + public string Name { + get { return name; } + set { name = value; } + } + + [TypeConverter(typeof(StringConverter))] + [DefaultValue(null)] + [Localizable(false)] + [Bindable(true)] + public Object Tag { + get { return tag; } + set { tag = value; } + } + + #endregion + + public override string ToString() + { + return header; + } + + #region ISerializable Members + + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("Header", header); + info.AddValue("Name", name); + info.AddValue("HeaderAlignment", header_alignment); + info.AddValue("Tag", tag); + + info.AddValue("ListViewItemCount", items.Count); + + int i = 0; + foreach (ListViewItem item in items) + { + info.AddValue(string.Format("ListViewItem_{0}", i), item); + i++; + } + } + + #endregion + } + + internal class ListViewGroupConverter : TypeConverter + { + public override bool GetStandardValuesSupported (ITypeDescriptorContext context) + { + return true; + } + + // Weird + public override StandardValuesCollection GetStandardValues (ITypeDescriptorContext context) + { + return new StandardValuesCollection (new object [] {}); + } + } +} diff --git a/source/ShiftUI/ListView/ListViewGroupCollection.cs b/source/ShiftUI/ListView/ListViewGroupCollection.cs new file mode 100644 index 0000000..b2eceb8 --- /dev/null +++ b/source/ShiftUI/ListView/ListViewGroupCollection.cs @@ -0,0 +1,332 @@ +// +// ListViewGroupCollection.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Daniel Nauck +// +// Author: +// Daniel Nauck (dna(at)mono-project(dot)de) +// Carlos Alberto Cortez + +using System; +using System.Text; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; + +namespace ShiftUI +{ + [ListBindable(false)] + public class ListViewGroupCollection : IList, ICollection, IEnumerable + { + private List list = null; + private ListView list_view_owner = null; + private ListViewGroup default_group; + + ListViewGroupCollection() + { + list = new List (); + + default_group = new ListViewGroup ("Default Group"); + default_group.IsDefault = true; + } + + internal ListViewGroupCollection(ListView listViewOwner) : this() + { + list_view_owner = listViewOwner; + default_group.ListViewOwner = listViewOwner; + } + + internal ListView ListViewOwner { + get { return list_view_owner; } + set { list_view_owner = value; } + } + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return list.GetEnumerator(); + } + + #endregion + + #region ICollection Members + + public void CopyTo(Array array, int index) + { + ((ICollection) list).CopyTo(array, index); + } + + public int Count { + get { return list.Count; } + } + + bool ICollection.IsSynchronized { + get { return true; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + #endregion + + #region IList Members + + int IList.Add(object value) + { + if (!(value is ListViewGroup)) + throw new ArgumentException("value"); + + return Add((ListViewGroup)value); + } + + public int Add(ListViewGroup group) + { + if (Contains(group)) + return -1; + + AddGroup (group); + + if (this.list_view_owner != null) + list_view_owner.Redraw(true); + + return list.Count - 1; + } + + public ListViewGroup Add(string key, string headerText) + { + ListViewGroup newGroup = new ListViewGroup(key, headerText); + Add(newGroup); + + return newGroup; + } + + public void Clear() + { + foreach (ListViewGroup group in list) + group.ListViewOwner = null; + + list.Clear (); + + if(list_view_owner != null) + list_view_owner.Redraw(true); + } + + bool IList.Contains(object value) + { + if (value is ListViewGroup) + return Contains((ListViewGroup)value); + else + return false; + } + + public bool Contains(ListViewGroup value) + { + return list.Contains(value); + } + + int IList.IndexOf(object value) + { + if (value is ListViewGroup) + return IndexOf((ListViewGroup)value); + else + return -1; + } + + public int IndexOf(ListViewGroup value) + { + return list.IndexOf(value); + } + + void IList.Insert(int index, object value) + { + if (value is ListViewGroup) + Insert(index, (ListViewGroup)value); + } + + public void Insert(int index, ListViewGroup group) + { + if (Contains(group)) + return; + + CheckListViewItemsInGroup(group); + group.ListViewOwner = list_view_owner; + list.Insert(index, group); + + if(list_view_owner != null) + list_view_owner.Redraw(true); + } + + bool IList.IsFixedSize { + get { return false; } + } + + bool IList.IsReadOnly { + get { return false; } + } + + void IList.Remove(object value) + { + Remove((ListViewGroup)value); + } + + public void Remove (ListViewGroup group) + { + int idx = list.IndexOf (group); + if (idx != -1) + RemoveAt (idx); + } + + public void RemoveAt (int index) + { + if (list.Count <= index || index < 0) + return; + + ListViewGroup group = list [index]; + group.ListViewOwner = null; + + list.RemoveAt (index); + if (list_view_owner != null) + list_view_owner.Redraw (true); + } + + object IList.this[int index] { + get { return this[index]; } + set { + if (value is ListViewGroup) + this[index] = (ListViewGroup)value; + } + } + + public ListViewGroup this[int index] { + get { + if (list.Count <= index || index < 0) + throw new ArgumentOutOfRangeException("index"); + + return list [index]; + } + set { + if (list.Count <= index || index < 0) + throw new ArgumentOutOfRangeException("index"); + + if (Contains (value)) + return; + + if (value != null) + CheckListViewItemsInGroup (value); + + list [index] = value; + + if (list_view_owner != null) + list_view_owner.Redraw(true); + } + } + + public ListViewGroup this [string key] { + get { + int idx = IndexOfKey (key); + if (idx != -1) + return this [idx]; + + return null; + } + set { + int idx = IndexOfKey (key); + if (idx == -1) + return; + + this [idx] = value; + } + } + + int IndexOfKey (string key) + { + for (int i = 0; i < list.Count; i++) + if (list [i].Name == key) + return i; + + return -1; + } + + #endregion + + public void AddRange(ListViewGroup[] groups) + { + foreach (ListViewGroup group in groups) + AddGroup (group); + + if (list_view_owner != null) + list_view_owner.Redraw (true); + } + + public void AddRange(ListViewGroupCollection groups) + { + foreach (ListViewGroup group in groups) + AddGroup (group); + + if (list_view_owner != null) + list_view_owner.Redraw (true); + } + + internal ListViewGroup GetInternalGroup (int index) + { + if (index == 0) + return default_group; + + return list [index - 1]; + } + + internal int InternalCount { + get { + return list.Count + 1; + } + } + + internal ListViewGroup DefaultGroup { + get { + return default_group; + } + } + + void AddGroup (ListViewGroup group) + { + if (Contains (group)) + return; + + CheckListViewItemsInGroup (group); + group.ListViewOwner = list_view_owner; + list.Add (group); + } + + private void CheckListViewItemsInGroup(ListViewGroup value) + { + //check for correct ListView + foreach (ListViewItem item in value.Items) + { + if (item.ListView != null && item.ListView != this.list_view_owner) + throw new ArgumentException("ListViewItem belongs to a ListView control other than the one that owns this ListViewGroupCollection.", + "ListViewGroup"); + } + } + } +} diff --git a/source/ShiftUI/ListView/ListViewHitTestInfo.cs b/source/ShiftUI/ListView/ListViewHitTestInfo.cs new file mode 100644 index 0000000..5ec676b --- /dev/null +++ b/source/ShiftUI/ListView/ListViewHitTestInfo.cs @@ -0,0 +1,62 @@ +// +// ListViewHitTestInfo.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Daniel Nauck +// +// Author: +// Daniel Nauck (dna(at)mono-project(dot)de) + +using System; +using ShiftUI; + +namespace ShiftUI +{ + public class ListViewHitTestInfo + { + ListViewItem item = null; + ListViewItem.ListViewSubItem subItem = null; + ListViewHitTestLocations location = ListViewHitTestLocations.None; + + public ListViewHitTestInfo(ListViewItem hitItem, ListViewItem.ListViewSubItem hitSubItem, + ListViewHitTestLocations hitLocation) + { + item = hitItem; + subItem = hitSubItem; + location = hitLocation; + } + + public ListViewItem Item + { + get { return item; } + } + + public ListViewHitTestLocations Location + { + get { return location; } + } + + public ListViewItem.ListViewSubItem SubItem + { + get { return subItem; } + } + } +} diff --git a/source/ShiftUI/ListView/ListViewHitTestLocations.cs b/source/ShiftUI/ListView/ListViewHitTestLocations.cs new file mode 100644 index 0000000..684fbec --- /dev/null +++ b/source/ShiftUI/ListView/ListViewHitTestLocations.cs @@ -0,0 +1,44 @@ +// +// ListViewHitTestLocations.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + [Flags] + public enum ListViewHitTestLocations + { + None = 1, + Image = 2, + Label = 4, + BelowClientArea = 16, + RightOfClientArea = 32, + LeftOfClientArea = 64, + AboveClientArea = 256, + StateImage = 512 + } +} diff --git a/source/ShiftUI/ListView/ListViewInsertionMark.cs b/source/ShiftUI/ListView/ListViewInsertionMark.cs new file mode 100644 index 0000000..9661d42 --- /dev/null +++ b/source/ShiftUI/ListView/ListViewInsertionMark.cs @@ -0,0 +1,152 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Carlos Alberto Cortez +// + + +using System; +using System.Drawing; + +namespace ShiftUI +{ + public sealed class ListViewInsertionMark + { + ListView listview_owner; + bool appears_after_item; + Rectangle bounds; + Color? color; + int index = 0; + + internal ListViewInsertionMark (ListView listview) + { + listview_owner = listview; + } + + public bool AppearsAfterItem { + get { + return appears_after_item; + } + set { + if (value == appears_after_item) + return; + + appears_after_item = value; + + listview_owner.item_control.Invalidate (bounds); + UpdateBounds (); + listview_owner.item_control.Invalidate (bounds); + } + } + + public Rectangle Bounds { + get { + return bounds; + } + } + + public Color Color { + get { + return color == null ? listview_owner.ForeColor : color.Value; + } + set { + color = value; + } + } + + public int Index { + get { + return index; + } + set { + if (value == index) + return; + + index = value; + + listview_owner.item_control.Invalidate (bounds); + UpdateBounds (); + listview_owner.item_control.Invalidate (bounds); + } + } + + void UpdateBounds () + { + if (index < 0 || index >= listview_owner.Items.Count) { + bounds = Rectangle.Empty; + return; + } + + Rectangle item_bounds = listview_owner.Items [index].Bounds; + int x_origin = (appears_after_item ? item_bounds.Right : item_bounds.Left) - 2; + int height = item_bounds.Height + ThemeEngine.Current.ListViewVerticalSpacing; + + bounds = new Rectangle (x_origin, item_bounds.Top, 7, height); + } + + public int NearestIndex (Point pt) + { + double distance = Double.MaxValue; + int nearest = -1; + + for (int i = 0; i < listview_owner.Items.Count; i++) { + Point pos = listview_owner.GetItemLocation (i); + double d = Math.Pow (pos.X - pt.X, 2) + Math.Pow (pos.Y - pt.Y, 2); + if (d < distance) { + distance = d; + nearest = i; + } + } + + if (listview_owner.item_control.dragged_item_index == nearest) + return -1; + + return nearest; + } + + internal PointF [] TopTriangle { + get { + PointF p1 = new PointF (bounds.X, bounds.Y); + PointF p2 = new PointF (bounds.Right, bounds.Y); + PointF p3 = new PointF (bounds.X + (bounds.Right - bounds.X) / 2, bounds.Y + 5); + + return new PointF [] {p1, p2, p3}; + } + } + + internal PointF [] BottomTriangle { + get { + PointF p1 = new PointF (bounds.X, bounds.Bottom); + PointF p2 = new PointF (bounds.Right, bounds.Bottom); + PointF p3 = new PointF (bounds.X + (bounds.Right - bounds.X) / 2, bounds.Bottom - 5); + + return new PointF [] {p1, p2, p3}; + } + } + + internal Rectangle Line { + get { + return new Rectangle (bounds.X + 2, bounds.Y + 2, 2, bounds.Height - 5); + } + } + } +} diff --git a/source/ShiftUI/ListView/ListViewItemConverter.cs b/source/ShiftUI/ListView/ListViewItemConverter.cs new file mode 100644 index 0000000..bd09096 --- /dev/null +++ b/source/ShiftUI/ListView/ListViewItemConverter.cs @@ -0,0 +1,97 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Ravindra (rkumar@novell.com) + + +// COMPLETE + + +using System; +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design.Serialization; +using System.Drawing; +using System.Globalization; +using System.Reflection; + +namespace ShiftUI +{ + public class ListViewItemConverter : ExpandableObjectConverter + { + #region Public Constructors + public ListViewItemConverter () { } + #endregion // Public Constructors + + #region Public Instance Methods + public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType) { + if (destinationType == typeof (string)) { + return true; + } + + return base.CanConvertTo (context, destinationType); + } + + public override object ConvertTo (ITypeDescriptorContext context, + CultureInfo culture, object value, + Type destinationType) + { + if (destinationType == typeof (string)) { + return value.ToString (); + } else { + return base.ConvertTo (context, culture, value, destinationType); + } + } + #endregion // Public Instance Methods + } + + internal class ListViewSubItemConverter : ExpandableObjectConverter { + #region Public Instance Methods + public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType) { + if (destinationType == typeof(InstanceDescriptor)) { + return true; + } else { + return base.CanConvertTo(context, destinationType); + } + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { + if (destinationType == typeof(InstanceDescriptor) && value is ListViewItem.ListViewSubItem) { + ConstructorInfo constructor_info; + Type[] type; + ListViewItem.ListViewSubItem sub_item; + + sub_item = (ListViewItem.ListViewSubItem)value; + type = new Type[] { typeof(ListViewItem), typeof(string), typeof(Color), typeof(Color), typeof(Font)}; + + constructor_info = typeof(ListViewItem.ListViewSubItem).GetConstructor(type); + if (constructor_info != null) { + object[] arguments = new object[] {sub_item.Text, sub_item.ForeColor, sub_item.BackColor, sub_item.Font}; + return new InstanceDescriptor(constructor_info, (ICollection) arguments, true); + } + + } + return base.ConvertTo(context, culture, value, destinationType); + } + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/ListView/ListViewItemMouseHoverEventArgs.cs b/source/ShiftUI/ListView/ListViewItemMouseHoverEventArgs.cs new file mode 100644 index 0000000..7bb2abe --- /dev/null +++ b/source/ShiftUI/ListView/ListViewItemMouseHoverEventArgs.cs @@ -0,0 +1,53 @@ +// +// ListViewItemMouseHoverEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI +{ + [ComVisible (true)] + public class ListViewItemMouseHoverEventArgs : EventArgs + { + private ListViewItem item; + + #region Public Constructors + public ListViewItemMouseHoverEventArgs (ListViewItem item) : base () + { + this.item = item; + } + #endregion // Public Constructors + + #region Public Instance Properties + public ListViewItem Item { + get { return this.item; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/ListView/ListViewItemMouseHoverEventHandler.cs b/source/ShiftUI/ListView/ListViewItemMouseHoverEventHandler.cs new file mode 100644 index 0000000..b801f62 --- /dev/null +++ b/source/ShiftUI/ListView/ListViewItemMouseHoverEventHandler.cs @@ -0,0 +1,32 @@ +// +// ListViewItemMouseHoverEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ListViewItemMouseHoverEventHandler (object sender, ListViewItemMouseHoverEventArgs e); +} diff --git a/source/ShiftUI/ListView/ListViewItemSelectionChangedEventArgs.cs b/source/ShiftUI/ListView/ListViewItemSelectionChangedEventArgs.cs new file mode 100644 index 0000000..27d92b9 --- /dev/null +++ b/source/ShiftUI/ListView/ListViewItemSelectionChangedEventArgs.cs @@ -0,0 +1,61 @@ +// +// ListViewItemSelectionChangedEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + public class ListViewItemSelectionChangedEventArgs : EventArgs + { + private bool is_selected; + private ListViewItem item; + private int item_index; + + #region Public Constructors + public ListViewItemSelectionChangedEventArgs (ListViewItem item, int itemIndex, bool isSelected) : base () + { + this.item = item; + this.item_index = itemIndex; + this.is_selected = isSelected; + } + #endregion // Public Constructors + + #region Public Instance Properties + public ListViewItem Item { + get { return this.item; } + } + + public bool IsSelected { + get { return this.is_selected; } + } + + public int ItemIndex { + get { return this.item_index; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/ListView/ListViewItemSelectionChangedEventHandler.cs b/source/ShiftUI/ListView/ListViewItemSelectionChangedEventHandler.cs new file mode 100644 index 0000000..670fa7d --- /dev/null +++ b/source/ShiftUI/ListView/ListViewItemSelectionChangedEventHandler.cs @@ -0,0 +1,32 @@ +// +// ListViewItemSelectionChangedEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ListViewItemSelectionChangedEventHandler (object sender, ListViewItemSelectionChangedEventArgs e); +} diff --git a/source/ShiftUI/ListView/ListViewItemStates.cs b/source/ShiftUI/ListView/ListViewItemStates.cs new file mode 100644 index 0000000..dc995fd --- /dev/null +++ b/source/ShiftUI/ListView/ListViewItemStates.cs @@ -0,0 +1,45 @@ +// +// ListViewItemStates.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + [Flags] + public enum ListViewItemStates + { + Selected = 1, + Grayed = 2, + Checked = 8, + Focused = 16, + Default = 32, + Hot = 64, + Marked = 128, + Indeterminate = 256, + ShowKeyboardCues = 512 + } +} diff --git a/source/ShiftUI/ListView/ListViewVirtualItemsSelectionRangeChangedEventArgs.cs b/source/ShiftUI/ListView/ListViewVirtualItemsSelectionRangeChangedEventArgs.cs new file mode 100644 index 0000000..13c675b --- /dev/null +++ b/source/ShiftUI/ListView/ListViewVirtualItemsSelectionRangeChangedEventArgs.cs @@ -0,0 +1,61 @@ +// +// ListViewVirtualItemsSelectionRangeChangedEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + public class ListViewVirtualItemsSelectionRangeChangedEventArgs : EventArgs + { + private bool is_selected; + private int end_index; + private int start_index; + + #region Public Constructors + public ListViewVirtualItemsSelectionRangeChangedEventArgs (int startIndex, int endIndex, bool isSelected) : base () + { + this.start_index = startIndex; + this.end_index = endIndex; + this.is_selected = isSelected; + } + #endregion // Public Constructors + + #region Public Instance Properties + public int StartIndex { + get { return this.start_index; } + } + + public bool IsSelected { + get { return this.is_selected; } + } + + public int EndIndex { + get { return this.end_index; } + } + #endregion // Public Instance Properties + } +} \ No newline at end of file diff --git a/source/ShiftUI/ListView/ListViewVirtualItemsSelectionRangeChangedEventHandler.cs b/source/ShiftUI/ListView/ListViewVirtualItemsSelectionRangeChangedEventHandler.cs new file mode 100644 index 0000000..8b45862 --- /dev/null +++ b/source/ShiftUI/ListView/ListViewVirtualItemsSelectionRangeChangedEventHandler.cs @@ -0,0 +1,32 @@ +// +// ListViewVirtualItemsSelectionRangeChangedEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ListViewVirtualItemsSelectionRangeChangedEventHandler (object sender, ListViewVirtualItemsSelectionRangeChangedEventArgs e); +} diff --git a/source/ShiftUI/Menu/Menu.cs b/source/ShiftUI/Menu/Menu.cs new file mode 100644 index 0000000..0e04d70 --- /dev/null +++ b/source/ShiftUI/Menu/Menu.cs @@ -0,0 +1,621 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// +// TODO: +// - FindMenuItem +// - MdiListItem +// + +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Collections.Generic; +using System.Drawing; +using System; + +namespace ShiftUI +{ + [ToolboxItemFilter("ShiftUI", ToolboxItemFilterType.Allow)] + [ListBindable(false)] + public abstract class Menu : Component + { + internal MenuItemCollection menu_items; + internal IntPtr menu_handle = IntPtr.Zero; + internal Menu parent_menu = null; + System.Drawing.Rectangle rect = new Rectangle (); + // UIA Framework Note: Used to keep track of expanded menus + internal Widget Wnd; + internal MenuTracker tracker; + private string control_name; + private object control_tag; + public const int FindHandle = 0; + public const int FindShortcut = 1; + + protected Menu (MenuItem[] items) + { + menu_items = new MenuItemCollection (this); + + if (items != null) + menu_items.AddRange (items); + } + + #region Public Properties + + [BrowsableAttribute(false)] + //[EditorBrowsableAttribute(EditorBrowsableState.Advanced)] + //[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] + public IntPtr Handle { + get { return menu_handle; } + } + + internal virtual void OnMenuChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [MenuChangedEvent]); + if (eh != null) + eh (this, e); + } + + [BrowsableAttribute(false)] + //[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] + public virtual bool IsParent { + get { + if (menu_items != null && menu_items.Count > 0) + return true; + else + return false; + } + } + + [BrowsableAttribute(false)] + //[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] + public MenuItem MdiListItem { + get { + throw new NotImplementedException (); + } + } + + [BrowsableAttribute(false)] + //[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content)] + [MergableProperty(false)] + public MenuItemCollection MenuItems { + get { return menu_items; } + } + + [BrowsableAttribute(false)] + //[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] + public string Name { + get { return control_name; } + set { control_name = value; } + } + + [Localizable(false)] + [Bindable(true)] + [TypeConverter(typeof(StringConverter))] + [DefaultValue(null)] + [MWFCategory("Data")] + public object Tag { + get { return control_tag; } + set { control_tag = value; } + } + + #endregion Public Properties + + #region Private Properties + + // UIA Framework Note: Used to obtain menu bounds + internal Rectangle Rect { + get { return rect; } + } + + internal MenuItem SelectedItem { + get { + foreach (MenuItem item in MenuItems) + if (item.Selected) + return item; + + return null; + } + } + + internal int Height { + get { return rect.Height; } + set { rect.Height = value; } + } + + internal int Width { + get { return rect.Width; } + set { rect.Width = value; } + } + + internal int X { + get { return rect.X; } + set { rect.X = value; } + } + + internal int Y { + get { return rect.Y; } + set { rect.Y = value; } + } + + internal MenuTracker Tracker { + get { + Menu top = this; + while (top.parent_menu != null) + top = top.parent_menu; + + return top.tracker; + } + } + #endregion Private Properties + + #region Public Methods + + protected void CloneMenu (Menu menuSrc) + { + Dispose (true); + + menu_items = new MenuItemCollection (this); + + for (int i = 0; i < menuSrc.MenuItems.Count ; i++) + menu_items.Add (menuSrc.MenuItems [i].CloneMenu ()); + } + + protected virtual IntPtr CreateMenuHandle () + { + return IntPtr.Zero; + } + + protected override void Dispose (bool disposing) + { + if (disposing) { + if (menu_items != null) { + // MenuItem.Dispose removes the item from the list + while (menu_items.Count > 0) { + menu_items [0].Dispose (); + } + } + if (menu_handle != IntPtr.Zero) { + menu_handle = IntPtr.Zero; + } + } + } + + // From Microsoft documentation is impossible to guess that + // this method is supossed to do + // + // update: according to MS documentation, first parameter is on of this + // constant values FindHandle or FindShortcut, value depends from what + // you what to search, by shortcut or handle. FindHandle and FindShortcut + // is a constant fields and was defined for this class. + public MenuItem FindMenuItem (int type, IntPtr value) + { + return null; + } + + protected int FindMergePosition (int mergeOrder) + { + int cnt = MenuItems.Count, cur, pos; + + for (pos = 0; pos < cnt; ) { + cur = (pos + cnt) /2; + if (MenuItems[cur].MergeOrder > mergeOrder) { + cnt = cur; + } else { + pos = cur +1; + } + } + + return pos; + } + + public MainMenu GetMainMenu () + { + for (Menu item = this; item != null; item = item.parent_menu) { + if (item is MainMenu) { + return (MainMenu) item; + } + } + + return null; + } + + internal virtual void InvalidateItem (MenuItem item) + { + if (Wnd != null) + Wnd.Invalidate (item.bounds); + } + + public virtual void MergeMenu (Menu menuSrc) + { + if (menuSrc == this) + throw new ArgumentException ("The menu cannot be merged with itself"); + + if (menuSrc == null) + return; + + for (int i = 0; i < menuSrc.MenuItems.Count; i++) { + + MenuItem sourceitem = menuSrc.MenuItems[i]; + + switch (sourceitem.MergeType) { + case MenuMerge.Remove: // Item not included + break; + + case MenuMerge.Add: + { + int pos = FindMergePosition (sourceitem.MergeOrder); + MenuItems.Add (pos, sourceitem.CloneMenu ()); + break; + } + + case MenuMerge.Replace: + case MenuMerge.MergeItems: + { + for (int pos = FindMergePosition (sourceitem.MergeOrder-1); pos <= MenuItems.Count; pos++) { + + if ((pos >= MenuItems.Count) || (MenuItems[pos].MergeOrder != sourceitem.MergeOrder)) { + MenuItems.Add (pos, sourceitem.CloneMenu ()); + break; + } + + MenuItem mergeitem = MenuItems[pos]; + + if (mergeitem.MergeType != MenuMerge.Add) { + if ((sourceitem.MergeType == MenuMerge.MergeItems) && (mergeitem.MergeType == MenuMerge.MergeItems)) { + mergeitem.MergeMenu (sourceitem); + } else { + MenuItems.Remove (sourceitem); + MenuItems.Add (pos, sourceitem.CloneMenu ()); + } + break; + } + } + + break; + } + + default: + break; + } + } + } + + protected internal virtual bool ProcessCmdKey (ref Message msg, Keys keyData) + { + if (tracker == null) + return false; + return tracker.ProcessKeys (ref msg, keyData); + } + + public override string ToString () + { + return base.ToString () + ", Items.Count: " + MenuItems.Count; + } + + #endregion Public Methods + static object MenuChangedEvent = new object (); + + // UIA Framework Note: Used to track changes in MenuItemCollection + internal event EventHandler MenuChanged { + add { Events.AddHandler (MenuChangedEvent, value); } + remove { Events.RemoveHandler (MenuChangedEvent, value); } + } + + [ListBindable(false)] + public class MenuItemCollection : IList, ICollection, IEnumerable + { + private Menu owner; + private ArrayList items = new ArrayList (); + + public MenuItemCollection (Menu owner) + { + this.owner = owner; + } + + #region Public Properties + + public int Count { + get { return items.Count;} + } + + public bool IsReadOnly { + get { return false; } + } + + bool ICollection.IsSynchronized { + get { return false;} + } + + object ICollection.SyncRoot { + get { return this;} + } + + bool IList.IsFixedSize { + get { return false;} + } + + public virtual MenuItem this [int index] { + get { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + return (MenuItem) items[index]; + } + } + + public virtual MenuItem this [string key] { + get { + if (string.IsNullOrEmpty (key)) + return null; + + foreach (MenuItem m in items) + if (string.Compare (m.Name, key, true) == 0) + return m; + + return null; + } + } + + object IList.this[int index] { + get { return items[index]; } + set { throw new NotSupportedException (); } + } + + #endregion Public Properties + + #region Public Methods + + public virtual int Add (MenuItem item) + { + if (item.Parent != null) + item.Parent.MenuItems.Remove (item); + + items.Add (item); + item.Index = items.Count - 1; + UpdateItem (item); + + owner.OnMenuChanged (EventArgs.Empty); + if (owner.parent_menu != null) + owner.parent_menu.OnMenuChanged (EventArgs.Empty); + return items.Count - 1; + } + + internal void AddNoEvents (MenuItem mi) + { + if (mi.Parent != null) + mi.Parent.MenuItems.Remove (mi); + + items.Add (mi); + mi.Index = items.Count - 1; + mi.parent_menu = owner; + } + + public virtual MenuItem Add (string caption) + { + MenuItem item = new MenuItem (caption); + Add (item); + return item; + } + + public virtual int Add (int index, MenuItem item) + { + if (index < 0 || index > Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + ArrayList new_items = new ArrayList (Count + 1); + + for (int i = 0; i < index; i++) + new_items.Add (items[i]); + + new_items.Add (item); + + for (int i = index; i < Count; i++) + new_items.Add (items[i]); + + items = new_items; + UpdateItemsIndices (); + UpdateItem (item); + + return index; + } + + private void UpdateItem (MenuItem mi) + { + mi.parent_menu = owner; + owner.OnMenuChanged (EventArgs.Empty); + if (owner.parent_menu != null) + owner.parent_menu.OnMenuChanged (EventArgs.Empty); + if (owner.Tracker != null) + owner.Tracker.AddShortcuts (mi); + } + + internal void Insert (int index, MenuItem mi) + { + if (index < 0 || index > Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + items.Insert (index, mi); + + UpdateItemsIndices (); + UpdateItem (mi); + } + + public virtual MenuItem Add (string caption, EventHandler onClick) + { + MenuItem item = new MenuItem (caption, onClick); + Add (item); + + return item; + } + + public virtual MenuItem Add (string caption, MenuItem[] items) + { + MenuItem item = new MenuItem (caption, items); + Add (item); + + return item; + } + + public virtual void AddRange (MenuItem[] items) + { + if (items == null) + throw new ArgumentNullException ("items"); + + foreach (MenuItem mi in items) + Add (mi); + } + + public virtual void Clear () + { + MenuTracker tracker = owner.Tracker; + foreach (MenuItem item in items) { + if (tracker != null) + tracker.RemoveShortcuts (item); + item.parent_menu = null; + } + items.Clear (); + owner.OnMenuChanged (EventArgs.Empty); + } + + public bool Contains (MenuItem value) + { + return items.Contains (value); + } + + public virtual bool ContainsKey (string key) + { + return !(this[key] == null); + } + + public void CopyTo (Array dest, int index) + { + items.CopyTo (dest, index); + } + + public MenuItem[] Find (string key, bool searchAllChildren) + { + if (string.IsNullOrEmpty (key)) + throw new ArgumentNullException ("key"); + + List list = new List (); + + foreach (MenuItem m in items) + if (string.Compare (m.Name, key, true) == 0) + list.Add (m); + + if (searchAllChildren) + foreach (MenuItem m in items) + list.AddRange (m.MenuItems.Find (key, true)); + + return list.ToArray (); + } + + public IEnumerator GetEnumerator () + { + return items.GetEnumerator (); + } + + int IList.Add (object value) + { + return Add ((MenuItem)value); + } + + bool IList.Contains (object value) + { + return Contains ((MenuItem)value); + } + + int IList.IndexOf (object value) + { + return IndexOf ((MenuItem)value); + } + + void IList.Insert (int index, object value) + { + Insert (index, (MenuItem) value); + } + + void IList.Remove (object value) + { + Remove ((MenuItem) value); + } + + public int IndexOf (MenuItem value) + { + return items.IndexOf (value); + } + + public virtual int IndexOfKey (string key) + { + if (string.IsNullOrEmpty (key)) + return -1; + + return IndexOf (this[key]); + } + + public virtual void Remove (MenuItem item) + { + RemoveAt (item.Index); + } + + public virtual void RemoveAt (int index) + { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + MenuItem item = (MenuItem) items [index]; + MenuTracker tracker = owner.Tracker; + if (tracker != null) + tracker.RemoveShortcuts (item); + item.parent_menu = null; + + items.RemoveAt (index); + + UpdateItemsIndices (); + owner.OnMenuChanged (EventArgs.Empty); + } + + public virtual void RemoveByKey (string key) + { + Remove (this[key]); + } + + #endregion Public Methods + + #region Private Methods + + private void UpdateItemsIndices () + { + for (int i = 0; i < Count; i++) // Recalculate indeces + ((MenuItem)items[i]).Index = i; + } + + #endregion Private Methods + } + } +} + + diff --git a/source/ShiftUI/Menu/MenuAPI.cs b/source/ShiftUI/Menu/MenuAPI.cs new file mode 100644 index 0000000..79a7a1d --- /dev/null +++ b/source/ShiftUI/Menu/MenuAPI.cs @@ -0,0 +1,836 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// Mike Kestner +// Everaldo Canuto +// + +using System.Collections; +using System.Drawing; +using System.Threading; +using System; + +namespace ShiftUI { + + /* + When writing this code the Wine project was of great help to + understand the logic behind some Win32 issues. Thanks to them. Jordi, + */ + // UIA Framework Note: This class used by UIA for its mouse action methods. + internal class MenuTracker { + + internal bool active; + internal bool popup_active; + internal bool popdown_menu; + internal bool hotkey_active; + private bool mouse_down = false; + public Menu CurrentMenu; + public Menu TopMenu; + public Widget GrabControl; + Point last_motion = Point.Empty; + + public MenuTracker (Menu top_menu) + { + TopMenu = CurrentMenu = top_menu; + foreach (MenuItem item in TopMenu.MenuItems) + AddShortcuts (item); + } + + enum KeyNavState { + Idle, + Startup, + NoPopups, + Navigating + } + + KeyNavState keynav_state = KeyNavState.Idle; + + public bool Navigating { + get { return keynav_state != KeyNavState.Idle || active; } + } + + internal static Point ScreenToMenu (Menu menu, Point pnt) + { + int x = pnt.X; + int y = pnt.Y; + XplatUI.ScreenToMenu (menu.Wnd.window.Handle, ref x, ref y); + return new Point (x, y); + } + + private void UpdateCursor () + { + Widget child_control = GrabControl.GetRealChildAtPoint (Cursor.Position); + if (child_control != null) { + if (active) + XplatUI.SetCursor (child_control.Handle, Cursors.Default.handle); + else + XplatUI.SetCursor (child_control.Handle, child_control.Cursor.handle); + } + } + + internal void Deactivate () + { + bool redrawbar = (keynav_state != KeyNavState.Idle) && (TopMenu is MainMenu); + + active = false; + popup_active = false; + hotkey_active = false; + if (GrabControl != null) + GrabControl.ActiveTracker = null; + keynav_state = KeyNavState.Idle; + CurrentMenu = TopMenu; + + if (redrawbar) + (TopMenu as MainMenu).Draw (); + } + + MenuItem FindItemByCoords (Menu menu, Point pt) + { + if (menu is MainMenu) + pt = ScreenToMenu (menu, pt); + else { + if (menu.Wnd == null) { + return null; + } + pt = menu.Wnd.PointToClient (pt); + } + foreach (MenuItem item in menu.MenuItems) { + Rectangle rect = item.bounds; + if (rect.Contains (pt)) + return item; + } + + return null; + } + + MenuItem GetItemAtXY (int x, int y) + { + Point pnt = new Point (x, y); + MenuItem item = null; + return item; + } + + // UIA Framework Note: Used to expand/collapse MenuItems + public bool OnMouseDown (MouseEventArgs args) + { + MenuItem item = GetItemAtXY (args.X, args.Y); + + mouse_down = true; + + if (item == null) { + Deactivate (); + return false; + } + + if ((args.Button & MouseButtons.Left) == 0) + return true; + + if (!item.Enabled) + return true; + + popdown_menu = active && item.VisibleItems; + + if (item.IsPopup || (item.Parent is MainMenu)) { + active = true; + item.Parent.InvalidateItem (item); + } + + if ((CurrentMenu == TopMenu) && !popdown_menu) + SelectItem (item.Parent, item, item.IsPopup); + + GrabControl.ActiveTracker = this; + return true; + } + + // UIA Framework Note: Used to select MenuItems + public void OnMotion (MouseEventArgs args) + { + // Windows helpfully sends us MOUSEMOVE messages when any key is pressed. + // So if the mouse hasn't actually moved since the last MOUSEMOVE, ignore it. + if (args.Location == last_motion) + return; + + last_motion = args.Location; + + MenuItem item = GetItemAtXY (args.X, args.Y); + + UpdateCursor (); + + if (CurrentMenu.SelectedItem == item) + return; + + GrabControl.ActiveTracker = (active || item != null) ? this : null; + + if (item == null) { + MenuItem old_item = CurrentMenu.SelectedItem; + + // Return when is a popup with visible subitems for MainMenu + if ((active && old_item.VisibleItems && old_item.IsPopup && (CurrentMenu is MainMenu))) + return; + + // Also returns when keyboard navigating + if (keynav_state == KeyNavState.Navigating) + return; + + // Select parent menu when move outside of menu item + if (old_item.Parent is MenuItem) { + MenuItem new_item = (old_item.Parent as MenuItem); + if (new_item.IsPopup) { + SelectItem (new_item.Parent, new_item, false); + return; + } + } + if (CurrentMenu != TopMenu) + CurrentMenu = CurrentMenu.parent_menu; + + DeselectItem (old_item); + } else { + keynav_state = KeyNavState.Idle; + SelectItem (item.Parent, item, active && item.IsPopup && popup_active && (CurrentMenu.SelectedItem != item)); + } + } + + // UIA Framework Note: Used to expand/collapse MenuItems + public void OnMouseUp (MouseEventArgs args) + { + /* mouse down dont comes from menu */ + if (!mouse_down) + return; + + mouse_down = false; + + /* is not left button */ + if ((args.Button & MouseButtons.Left) == 0) + return; + + MenuItem item = GetItemAtXY (args.X, args.Y); + + /* the user released the mouse button outside the menu */ + if (item == null) { + Deactivate (); + return; + } + + if (!item.Enabled) + return; + + /* Perform click when is not a popup */ + if (!item.IsPopup) { + DeselectItem (item); + + // Raise the form's MenuComplete event + if (TopMenu != null && TopMenu.Wnd != null) { + Form f = TopMenu.Wnd.FindForm (); + + if (f != null) + f.OnMenuComplete (EventArgs.Empty); + } + + item.PerformClick (); + } + } + + static public bool TrackPopupMenu (Menu menu, Point pnt) + { + return true; + } + + void DeselectItem (MenuItem item) + { + if (item == null) + return; + + item.Selected = false; + + /* When popup item then close all sub popups and unselect all sub items */ + if (item.IsPopup) { + HideSubPopups (item, TopMenu); + + /* Unselect all selected sub itens */ + foreach (MenuItem subitem in item.MenuItems) + if (subitem.Selected) + DeselectItem (subitem); + } + + Menu menu = item.Parent; + menu.InvalidateItem (item); + } + + void SelectItem (Menu menu, MenuItem item, bool execute) + { + MenuItem prev_item = CurrentMenu.SelectedItem; + + if (prev_item != item.Parent) { + DeselectItem (prev_item); + if ((CurrentMenu != menu) && (prev_item.Parent != item) && (prev_item.Parent is MenuItem)) { + DeselectItem (prev_item.Parent as MenuItem); + } + } + + if (CurrentMenu != menu) + CurrentMenu = menu; + + item.Selected = true; + menu.InvalidateItem (item); + + if (((CurrentMenu == TopMenu) && execute) || ((CurrentMenu != TopMenu) && popup_active)) + item.PerformSelect (); + + if ((execute) && ((prev_item == null) || (item != prev_item.Parent))) + ExecFocusedItem (menu, item); + } + + // Used when the user executes the action of an item (press enter, shortcut) + // or a sub-popup menu has to be shown + void ExecFocusedItem (Menu menu, MenuItem item) + { + if (item == null) + return; + + if (!item.Enabled) + return; + + if (item.IsPopup) { + ShowSubPopup (menu, item); + } else { + Deactivate (); + item.PerformClick (); + } + } + + // Create a popup window and show it or only show it if it is already created + void ShowSubPopup (Menu menu, MenuItem item) + { + if (item.Enabled == false) + return; + + if (!popdown_menu || !item.VisibleItems) + item.PerformPopup (); + + if (item.VisibleItems == false) + return; + + if (item.Wnd != null) { + item.Wnd.Dispose (); + } + + popup_active = true; + PopUpWindow puw = new PopUpWindow (GrabControl, item); + + Point pnt; + if (menu is MainMenu) + pnt = new Point (item.X, item.Y + item.Height - 2 - menu.Height); + else + pnt = new Point (item.X + item.Width - 3, item.Y - 3); + pnt = menu.Wnd.PointToScreen (pnt); + puw.Location = pnt; + item.Wnd = puw; + + puw.ShowWindow (); + } + + static public void HideSubPopups (Menu menu, Menu topmenu) + { + foreach (MenuItem item in menu.MenuItems) + if (item.IsPopup) + HideSubPopups (item, null); + + if (menu.Wnd == null) + return; + + PopUpWindow puw = menu.Wnd as PopUpWindow; + if (puw != null) { + puw.Hide (); + puw.Dispose (); + } + menu.Wnd = null; + + if ((topmenu != null) && (topmenu is MainMenu)) + ((MainMenu) topmenu).OnCollapse (EventArgs.Empty); + } + + MenuItem FindSubItemByCoord (Menu menu, Point pnt) + { + foreach (MenuItem item in menu.MenuItems) { + + if (item.IsPopup && item.Wnd != null && item.Wnd.Visible && item == menu.SelectedItem) { + MenuItem result = FindSubItemByCoord (item, pnt); + if (result != null) + return result; + } + + if (menu.Wnd == null || !menu.Wnd.Visible) + continue; + + Rectangle rect = item.bounds; + Point pnt_client = menu.Wnd.PointToScreen (new Point (item.X, item.Y)); + rect.X = pnt_client.X; + rect.Y = pnt_client.Y; + + if (rect.Contains (pnt) == true) + return item; + } + + return null; + } + + static MenuItem FindItemByKey (Menu menu, IntPtr key) + { + char key_char = Char.ToUpper ((char) (key.ToInt32() & 0xff)); + foreach (MenuItem item in menu.MenuItems) { + if (item.Mnemonic == key_char) + return item; + } + + string key_str = key_char.ToString (); + foreach (MenuItem item in menu.MenuItems) { + //if (item.Mnemonic == key_char) + if (item.Text.StartsWith (key_str)) + return item; + } + + return null; + } + + enum ItemNavigation { + First, + Last, + Next, + Previous, + } + + static MenuItem GetNextItem (Menu menu, ItemNavigation navigation) + { + int pos = 0; + bool selectable_items = false; + MenuItem item; + + // Check if there is at least a selectable item + for (int i = 0; i < menu.MenuItems.Count; i++) { + item = menu.MenuItems [i]; + if (item.Separator == false && item.Visible == true) { + selectable_items = true; + break; + } + } + + if (selectable_items == false) + return null; + + switch (navigation) { + case ItemNavigation.First: + + /* First item that is not separator and it is visible*/ + for (pos = 0; pos < menu.MenuItems.Count; pos++) { + item = menu.MenuItems [pos]; + if (item.Separator == false && item.Visible == true) + break; + } + + break; + + case ItemNavigation.Last: // Not used + break; + + case ItemNavigation.Next: + + pos = menu.SelectedItem == null ? - 1 : menu.SelectedItem.Index; + + /* Next item that is not separator and it is visible*/ + for (pos++; pos < menu.MenuItems.Count; pos++) { + item = menu.MenuItems [pos]; + if (item.Separator == false && item.Visible == true) + break; + } + + if (pos >= menu.MenuItems.Count) { /* Jump at the start of the menu */ + pos = 0; + /* Next item that is not separator and it is visible*/ + for (; pos < menu.MenuItems.Count; pos++) { + item = menu.MenuItems [pos]; + if (item.Separator == false && item.Visible == true) + break; + } + } + break; + + case ItemNavigation.Previous: + + if (menu.SelectedItem != null) + pos = menu.SelectedItem.Index; + + /* Previous item that is not separator and it is visible*/ + for (pos--; pos >= 0; pos--) { + item = menu.MenuItems [pos]; + if (item.Separator == false && item.Visible == true) + break; + } + + if (pos < 0 ) { /* Jump at the end of the menu*/ + pos = menu.MenuItems.Count - 1; + /* Previous item that is not separator and it is visible*/ + for (; pos >= 0; pos--) { + item = menu.MenuItems [pos]; + if (item.Separator == false && item.Visible == true) + break; + } + } + + break; + + default: + break; + } + + return menu.MenuItems [pos]; + } + + void ProcessMenuKey (Msg msg_type) + { + if (TopMenu.MenuItems.Count == 0) + return; + + MainMenu main_menu = TopMenu as MainMenu; + + switch (msg_type) { + case Msg.WM_SYSKEYDOWN: + switch (keynav_state) { + case KeyNavState.Idle: + keynav_state = KeyNavState.Startup; + hotkey_active = true; + GrabControl.ActiveTracker = this; + CurrentMenu = TopMenu; + main_menu.Draw (); + break; + case KeyNavState.Startup: + break; + default: + Deactivate (); + main_menu.Draw (); + break; + } + break; + + case Msg.WM_SYSKEYUP: + switch (keynav_state) { + case KeyNavState.Idle: + case KeyNavState.Navigating: + break; + case KeyNavState.Startup: + keynav_state = KeyNavState.NoPopups; + SelectItem (TopMenu, TopMenu.MenuItems [0], false); + break; + default: + Deactivate (); + main_menu.Draw (); + break; + } + break; + } + } + + bool ProcessMnemonic (Message msg, Keys key_data) + { + keynav_state = KeyNavState.Navigating; + MenuItem item = FindItemByKey (CurrentMenu, msg.WParam); + if ((item == null) || (GrabControl == null) || (GrabControl.ActiveTracker == null)) + return false; + + active = true; + GrabControl.ActiveTracker = this; + + SelectItem (CurrentMenu, item, true); + if (item.IsPopup) { + CurrentMenu = item; + SelectItem (item, item.MenuItems [0], false); + } + return true; + } + + Hashtable shortcuts = new Hashtable (); + + public void AddShortcuts (MenuItem item) + { + foreach (MenuItem child in item.MenuItems) { + AddShortcuts (child); + if (child.Shortcut != Shortcut.None) + shortcuts [(int)child.Shortcut] = child; + } + + if (item.Shortcut != Shortcut.None) + shortcuts [(int)item.Shortcut] = item; + } + + public void RemoveShortcuts (MenuItem item) + { + foreach (MenuItem child in item.MenuItems) { + RemoveShortcuts (child); + if (child.Shortcut != Shortcut.None) + shortcuts.Remove ((int)child.Shortcut); + } + + if (item.Shortcut != Shortcut.None) + shortcuts.Remove ((int)item.Shortcut); + } + + bool ProcessShortcut (Keys keyData) + { + MenuItem item = shortcuts [(int)keyData] as MenuItem; + if (item == null || !item.Enabled) + return false; + + if (active) + Deactivate (); + item.PerformClick (); + return true; + } + + public bool ProcessKeys (ref Message msg, Keys keyData) + { + // We should process Alt+key only if we don't have an active menu, + // and hide it otherwise. + if ((keyData & Keys.Alt) == Keys.Alt && active) { + Deactivate (); + return false; + } + + // If we get Alt-F4, Windows will ignore it because we have a capture, + // release the capture and the program will exit. (X11 doesn't care.) + if ((keyData & Keys.Alt) == Keys.Alt && (keyData & Keys.F4) == Keys.F4) { + if (GrabControl != null) + GrabControl.ActiveTracker = null; + + return false; + } + + if ((Msg)msg.Msg != Msg.WM_SYSKEYUP && ProcessShortcut (keyData)) + return true; + else if ((keyData & Keys.KeyCode) == Keys.Menu && TopMenu is MainMenu) { + ProcessMenuKey ((Msg) msg.Msg); + return true; + } else if ((keyData & Keys.Alt) == Keys.Alt) + return ProcessMnemonic (msg, keyData); + else if ((Msg)msg.Msg == Msg.WM_SYSKEYUP) + return false; + else if (!Navigating) + return false; + + MenuItem item; + + switch (keyData) { + case Keys.Up: + if (CurrentMenu is MainMenu) + return true; + else if (CurrentMenu.MenuItems.Count == 1 && CurrentMenu.parent_menu == TopMenu) { + DeselectItem (CurrentMenu.SelectedItem); + CurrentMenu = TopMenu; + return true; + } + item = GetNextItem (CurrentMenu, ItemNavigation.Previous); + if (item != null) + SelectItem (CurrentMenu, item, false); + break; + + case Keys.Down: + if (CurrentMenu is MainMenu) { + if (CurrentMenu.SelectedItem != null && CurrentMenu.SelectedItem.IsPopup) { + keynav_state = KeyNavState.Navigating; + item = CurrentMenu.SelectedItem; + ShowSubPopup (CurrentMenu, item); + SelectItem (item, item.MenuItems [0], false); + CurrentMenu = item; + active = true; + GrabControl.ActiveTracker = this; + } + return true; + } + item = GetNextItem (CurrentMenu, ItemNavigation.Next); + if (item != null) + SelectItem (CurrentMenu, item, false); + break; + + case Keys.Right: + if (CurrentMenu is MainMenu) { + item = GetNextItem (CurrentMenu, ItemNavigation.Next); + bool popup = item.IsPopup && keynav_state != KeyNavState.NoPopups; + SelectItem (CurrentMenu, item, popup); + if (popup) { + SelectItem (item, item.MenuItems [0], false); + CurrentMenu = item; + } + } else if (CurrentMenu.SelectedItem != null && CurrentMenu.SelectedItem.IsPopup) { + item = CurrentMenu.SelectedItem; + ShowSubPopup (CurrentMenu, item); + SelectItem (item, item.MenuItems [0], false); + CurrentMenu = item; + } else { + //Search up for a main menu + Menu Prnt = CurrentMenu.parent_menu; + while (Prnt != null && !(Prnt is MainMenu)) { + Prnt = Prnt.parent_menu; + } + if (Prnt is MainMenu) + { + item = GetNextItem(Prnt, ItemNavigation.Next); + SelectItem(Prnt, item, item.IsPopup); + if (item.IsPopup) + { + SelectItem(item, item.MenuItems[0], false); + CurrentMenu = item; + } + } + } + break; + + case Keys.Left: + if (CurrentMenu is MainMenu) { + item = GetNextItem (CurrentMenu, ItemNavigation.Previous); + bool popup = item.IsPopup && keynav_state != KeyNavState.NoPopups; + SelectItem (CurrentMenu, item, popup); + if (popup) { + SelectItem (item, item.MenuItems [0], false); + CurrentMenu = item; + } + } else if (CurrentMenu.parent_menu is MainMenu) { + item = GetNextItem (CurrentMenu.parent_menu, ItemNavigation.Previous); + SelectItem (CurrentMenu.parent_menu, item, item.IsPopup); + if (item.IsPopup) { + SelectItem (item, item.MenuItems [0], false); + CurrentMenu = item; + } + } + break; + + case Keys.Return: + if (CurrentMenu.SelectedItem != null && CurrentMenu.SelectedItem.IsPopup) { + keynav_state = KeyNavState.Navigating; + item = CurrentMenu.SelectedItem; + ShowSubPopup (CurrentMenu, item); + SelectItem (item, item.MenuItems [0], false); + CurrentMenu = item; + active = true; + GrabControl.ActiveTracker = this; + } else { + ExecFocusedItem (CurrentMenu, CurrentMenu.SelectedItem); + } + break; + + case Keys.Escape: + Deactivate (); + break; + + default: + ProcessMnemonic (msg, keyData); + break; + } + + return active; + } + } + + internal class PopUpWindow : Widget + { + private Menu menu; + private Widget form; + + public PopUpWindow (Widget form, Menu menu): base () + { + this.menu = menu; + this.form = form; + SetStyle (Widgetstyles.UserPaint | Widgetstyles.AllPaintingInWmPaint, true); + SetStyle (Widgetstyles.ResizeRedraw | Widgetstyles.Opaque, true); + is_visible = false; + } + + protected override CreateParams CreateParams + { + get { + CreateParams cp = base.CreateParams; + cp.Caption = "Menu PopUp"; + cp.Style = unchecked ((int)(WindowStyles.WS_POPUP)); + cp.ExStyle |= (int)(WindowExStyles.WS_EX_TOOLWINDOW | WindowExStyles.WS_EX_TOPMOST); + return cp; + } + } + + public void ShowWindow () + { + XplatUI.SetCursor(form.Handle, Cursors.Default.handle); + RefreshItems (); + Show (); + } + + internal override void OnPaintInternal (PaintEventArgs args) + { + ThemeEngine.Current.DrawPopupMenu (args.Graphics, menu, args.ClipRectangle, ClientRectangle); + } + + public void HideWindow () + { + XplatUI.SetCursor (form.Handle, form.Cursor.handle); + MenuTracker.HideSubPopups (menu, null); + Hide (); + } + + protected override void CreateHandle () + { + base.CreateHandle (); + RefreshItems (); + } + + // Called when the number of items has changed + internal void RefreshItems () + { + Point pt = new Point (Location.X, Location.Y); + + ThemeEngine.Current.CalcPopupMenuSize (DeviceContext, menu); + + if ((pt.X + menu.Rect.Width) > SystemInformation.VirtualScreen.Width) { + if (((pt.X - menu.Rect.Width) > 0) && !(menu.parent_menu is MainMenu)) + pt.X = pt.X - menu.Rect.Width; + else + pt.X = SystemInformation.VirtualScreen.Width - menu.Rect.Width; + + if (pt.X < 0) + pt.X = 0; + } + if ((pt.Y + menu.Rect.Height) > SystemInformation.VirtualScreen.Height) { + if ((pt.Y - menu.Rect.Height) > 0) + pt.Y = pt.Y - menu.Rect.Height; + else + pt.Y = SystemInformation.VirtualScreen.Height - menu.Rect.Height; + + if (pt.Y < 0) + pt.Y = 0; + } + + Location = pt; + Width = menu.Rect.Width; + Height = menu.Rect.Height; + } + + internal override bool ActivateOnShow { get { return false; } } + } +} + + diff --git a/source/ShiftUI/Menu/MenuGlyph.cs b/source/ShiftUI/Menu/MenuGlyph.cs new file mode 100644 index 0000000..92aa7f7 --- /dev/null +++ b/source/ShiftUI/Menu/MenuGlyph.cs @@ -0,0 +1,36 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com + + +// COMPLETE + +namespace ShiftUI { + public enum MenuGlyph { + Arrow = 0, + Min = 0, + Checkmark = 1, + Bullet = 2, + Max = 2 + } +} diff --git a/source/ShiftUI/Menu/MenuItem.cs b/source/ShiftUI/Menu/MenuItem.cs new file mode 100644 index 0000000..a893106 --- /dev/null +++ b/source/ShiftUI/Menu/MenuItem.cs @@ -0,0 +1,912 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// +// + +// NOT COMPLETE + +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Drawing.Text; +using System; + +namespace ShiftUI +{ + [DefaultProperty("Text")] + [DefaultEvent("Click")] + [DesignTimeVisible(false)] + [ToolboxItem(false)] + public class MenuItem : Menu + { + internal bool separator; + internal bool break_; + internal bool bar_break; + private Shortcut shortcut; + private string text; + private bool checked_; + private bool radiocheck; + private bool enabled; + private char mnemonic; + private bool showshortcut; + private int index; + private bool mdilist; + private Hashtable mdilist_items; + private Hashtable mdilist_forms; + private MdiClient mdicontainer; + private bool is_window_menu_item; + private bool defaut_item; + private bool visible; + private bool ownerdraw; + private int menuid; + private int mergeorder; + private int xtab; + private int menuheight; + private bool menubar; + private MenuMerge mergetype; + // UIA Framework Note: Used to obtain item bounds + internal Rectangle bounds; + + public MenuItem (): base (null) + { + CommonConstructor (string.Empty); + shortcut = Shortcut.None; + } + + public MenuItem (string text) : base (null) + { + CommonConstructor (text); + shortcut = Shortcut.None; + } + + public MenuItem (string text, EventHandler onClick) : base (null) + { + CommonConstructor (text); + shortcut = Shortcut.None; + Click += onClick; + } + + public MenuItem (string text, MenuItem[] items) : base (items) + { + CommonConstructor (text); + shortcut = Shortcut.None; + } + + public MenuItem (string text, EventHandler onClick, Shortcut shortcut) : base (null) + { + CommonConstructor (text); + Click += onClick; + this.shortcut = shortcut; + } + + public MenuItem (MenuMerge mergeType, int mergeOrder, Shortcut shortcut, string text, + EventHandler onClick, EventHandler onPopup, EventHandler onSelect, MenuItem[] items) + : base (items) + { + CommonConstructor (text); + this.shortcut = shortcut; + mergeorder = mergeOrder; + mergetype = mergeType; + + Click += onClick; + Popup += onPopup; + Select += onSelect; + } + + private void CommonConstructor (string text) + { + defaut_item = false; + separator = false; + break_ = false; + bar_break = false; + checked_ = false; + radiocheck = false; + enabled = true; + showshortcut = true; + visible = true; + ownerdraw = false; + menubar = false; + menuheight = 0; + xtab = 0; + index = -1; + mnemonic = '\0'; + menuid = -1; + mergeorder = 0; + mergetype = MenuMerge.Add; + Text = text; // Text can change separator status + } + + #region Events + static object ClickEvent = new object (); + static object DrawItemEvent = new object (); + static object MeasureItemEvent = new object (); + static object PopupEvent = new object (); + static object SelectEvent = new object (); + + public event EventHandler Click { + add { Events.AddHandler (ClickEvent, value); } + remove { Events.RemoveHandler (ClickEvent, value); } + } + + public event DrawItemEventHandler DrawItem { + add { Events.AddHandler (DrawItemEvent, value); } + remove { Events.RemoveHandler (DrawItemEvent, value); } + } + + public event MeasureItemEventHandler MeasureItem { + add { Events.AddHandler (MeasureItemEvent, value); } + remove { Events.RemoveHandler (MeasureItemEvent, value); } + } + + public event EventHandler Popup { + add { Events.AddHandler (PopupEvent, value); } + remove { Events.RemoveHandler (PopupEvent, value); } + } + + public event EventHandler Select { + add { Events.AddHandler (SelectEvent, value); } + remove { Events.RemoveHandler (SelectEvent, value); } + } + + #region UIA Framework Events + + static object UIACheckedChangedEvent = new object (); + + internal event EventHandler UIACheckedChanged { + add { Events.AddHandler (UIACheckedChangedEvent, value); } + remove { Events.RemoveHandler (UIACheckedChangedEvent, value); } + } + + internal void OnUIACheckedChanged (EventArgs e) + { + EventHandler eh = (EventHandler) Events [UIACheckedChangedEvent]; + if (eh != null) + eh (this, e); + } + + static object UIARadioCheckChangedEvent = new object (); + + internal event EventHandler UIARadioCheckChanged { + add { Events.AddHandler (UIARadioCheckChangedEvent, value); } + remove { Events.RemoveHandler (UIARadioCheckChangedEvent, value); } + } + + internal void OnUIARadioCheckChanged (EventArgs e) + { + EventHandler eh = (EventHandler) Events [UIARadioCheckChangedEvent]; + if (eh != null) + eh (this, e); + } + + static object UIAEnabledChangedEvent = new object (); + + internal event EventHandler UIAEnabledChanged { + add { Events.AddHandler (UIAEnabledChangedEvent, value); } + remove { Events.RemoveHandler (UIAEnabledChangedEvent, value); } + } + + internal void OnUIAEnabledChanged (EventArgs e) + { + EventHandler eh = (EventHandler) Events [UIAEnabledChangedEvent]; + if (eh != null) + eh (this, e); + } + + static object UIATextChangedEvent = new object (); + + internal event EventHandler UIATextChanged { + add { Events.AddHandler (UIATextChangedEvent, value); } + remove { Events.RemoveHandler (UIATextChangedEvent, value); } + } + + internal void OnUIATextChanged (EventArgs e) + { + EventHandler eh = (EventHandler) Events [UIATextChangedEvent]; + if (eh != null) + eh (this, e); + } + + #endregion + #endregion // Events + + #region Public Properties + + [Browsable(false)] + [DefaultValue(false)] + public bool BarBreak { + get { return break_; } + set { break_ = value; } + } + + [Browsable(false)] + [DefaultValue(false)] + public bool Break { + get { return bar_break; } + set { bar_break = value; } + } + + [DefaultValue(false)] + public bool Checked { + get { return checked_; } + set { + if (checked_ == value) + return; + + checked_ = value; + + // UIA Framework Event: Checked Changed + OnUIACheckedChanged (EventArgs.Empty); + } + } + + [DefaultValue(false)] + public bool DefaultItem { + get { return defaut_item; } + set { defaut_item = value; } + } + + [DefaultValue(true)] + [Localizable(true)] + public bool Enabled { + get { return enabled; } + set { + if (enabled == value) + return; + + enabled = value; + + // UIA Framework Event: Enabled Changed + OnUIAEnabledChanged (EventArgs.Empty); + + Invalidate (); + } + } + + [Browsable(false)] + public int Index { + get { return index; } + set { + if (Parent != null && Parent.MenuItems != null && (value < 0 || value >= Parent.MenuItems.Count)) + throw new ArgumentException ("'" + value + "' is not a valid value for 'value'"); + index = value; + } + } + + [Browsable(false)] + public override bool IsParent { + get { return IsPopup; } + } + + [DefaultValue(false)] + public bool MdiList { + get { return mdilist; } + set { + if (mdilist == value) + return; + mdilist = value; + + if (mdilist || mdilist_items == null) + return; + + foreach (MenuItem item in mdilist_items.Keys) + MenuItems.Remove (item); + mdilist_items.Clear (); + mdilist_items = null; + } + } + + protected int MenuID { + get { return menuid; } + } + + [DefaultValue(0)] + public int MergeOrder { + get { return mergeorder; } + set { mergeorder = value; } + } + + [DefaultValue(MenuMerge.Add)] + public MenuMerge MergeType { + get { return mergetype; } + set { + if (!Enum.IsDefined (typeof (MenuMerge), value)) + throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for MenuMerge", value)); + + mergetype = value; + } + } + + [Browsable(false)] + public char Mnemonic { + get { return mnemonic; } + } + + [DefaultValue(false)] + public bool OwnerDraw { + get { return ownerdraw; } + set { ownerdraw = value; } + } + + [Browsable(false)] + public Menu Parent { + get { return parent_menu;} + } + + [DefaultValue(false)] + public bool RadioCheck { + get { return radiocheck; } + set { + if (radiocheck == value) + return; + + radiocheck = value; + + // UIA Framework Event: Checked Changed + OnUIARadioCheckChanged (EventArgs.Empty); + } + } + + [DefaultValue(Shortcut.None)] + [Localizable(true)] + public Shortcut Shortcut { + get { return shortcut;} + set { + if (!Enum.IsDefined (typeof (Shortcut), value)) + throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for Shortcut", value)); + + shortcut = value; + UpdateMenuItem (); + } + } + + [DefaultValue(true)] + [Localizable(true)] + public bool ShowShortcut { + get { return showshortcut;} + set { showshortcut = value; } + } + + [Localizable(true)] + public string Text { + get { return text; } + set { + text = value; + + if (text == "-") + separator = true; + else + separator = false; + + // UIA Framework Event: Text Changed + OnUIATextChanged (EventArgs.Empty); + + ProcessMnemonic (); + Invalidate (); + } + } + + [DefaultValue(true)] + [Localizable(true)] + public bool Visible { + get { return visible;} + set { + if (value == visible) + return; + + visible = value; + + if (menu_items != null) { + foreach (MenuItem mi in menu_items) + mi.Visible = value; + } + + if (parent_menu != null) + parent_menu.OnMenuChanged (EventArgs.Empty); + } + } + + #endregion Public Properties + + #region Private Properties + + internal new int Height { + get { return bounds.Height; } + set { bounds.Height = value; } + } + + internal bool IsPopup { + get { + if (menu_items.Count > 0) + return true; + else + return false; + } + } + + internal bool MeasureEventDefined { + get { + if (ownerdraw == true && Events [MeasureItemEvent] != null) { + return true; + } else { + return false; + } + } + } + + internal bool MenuBar { + get { return menubar; } + set { menubar = value; } + } + + internal int MenuHeight { + get { return menuheight; } + set { menuheight = value; } + } + + bool selected; + internal bool Selected { + get { return selected; } + set { selected = value; } + } + + internal bool Separator { + get { return separator; } + set { separator = value; } + } + + internal DrawItemState Status { + get { + DrawItemState status = DrawItemState.None; + MenuTracker tracker = Parent.Tracker; + if (Selected) + status |= (tracker.active || tracker.Navigating ? DrawItemState.Selected : DrawItemState.HotLight); + if (!Enabled) + status |= DrawItemState.Grayed | DrawItemState.Disabled; + if (Checked) + status |= DrawItemState.Checked; + if (!tracker.Navigating) + status |= DrawItemState.NoAccelerator; + return status; + } + } + + internal bool VisibleItems { + get { + if (menu_items != null) { + foreach (MenuItem mi in menu_items) + if (mi.Visible) + return true; + } + return false; + } + } + + internal new int Width { + get { return bounds.Width; } + set { bounds.Width = value; } + } + + internal new int X { + get { return bounds.X; } + set { bounds.X = value; } + } + + internal int XTab { + get { return xtab; } + set { xtab = value; } + } + + internal new int Y { + get { return bounds.Y; } + set { bounds.Y = value; } + } + + #endregion Private Properties + + #region Public Methods + + public virtual MenuItem CloneMenu () + { + MenuItem item = new MenuItem (); + item.CloneMenu (this); + return item; + } + + protected void CloneMenu (MenuItem itemSrc) + { + base.CloneMenu (itemSrc); // Copy subitems + + // Window list + MdiList = itemSrc.MdiList; + is_window_menu_item = itemSrc.is_window_menu_item; + // Remove items corresponding to window menu items, and add new items + // (Otherwise window menu items would show up twice, since the PopulateWindowMenu doesn't + // now them) + bool populated = false; + for (int i = MenuItems.Count - 1; i >= 0; i--) { + if (MenuItems [i].is_window_menu_item) { + MenuItems.RemoveAt (i); + populated = true; + } + } + if (populated) + PopulateWindowMenu (); + + // Properties + BarBreak = itemSrc.BarBreak; + Break = itemSrc.Break; + Checked = itemSrc.Checked; + DefaultItem = itemSrc.DefaultItem; + Enabled = itemSrc.Enabled; + MergeOrder = itemSrc.MergeOrder; + MergeType = itemSrc.MergeType; + OwnerDraw = itemSrc.OwnerDraw; + //Parent = menuitem.Parent; + RadioCheck = itemSrc.RadioCheck; + Shortcut = itemSrc.Shortcut; + ShowShortcut = itemSrc.ShowShortcut; + Text = itemSrc.Text; + Visible = itemSrc.Visible; + Name = itemSrc.Name; + Tag = itemSrc.Tag; + + // Events + Events[ClickEvent] = itemSrc.Events[ClickEvent]; + Events[DrawItemEvent] = itemSrc.Events[DrawItemEvent]; + Events[MeasureItemEvent] = itemSrc.Events[MeasureItemEvent]; + Events[PopupEvent] = itemSrc.Events[PopupEvent]; + Events[SelectEvent] = itemSrc.Events[SelectEvent]; + } + + protected override void Dispose (bool disposing) + { + if (disposing && parent_menu != null) + parent_menu.MenuItems.Remove (this); + + base.Dispose (disposing); + } + + // This really clones the item + public virtual MenuItem MergeMenu () + { + MenuItem item = new MenuItem (); + item.CloneMenu (this); + return item; + } + + public void MergeMenu (MenuItem itemSrc) + { + base.MergeMenu (itemSrc); + } + + protected virtual void OnClick (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [ClickEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnDrawItem (DrawItemEventArgs e) + { + DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]); + if (eh != null) + eh (this, e); + } + + + protected virtual void OnInitMenuPopup (EventArgs e) + { + OnPopup (e); + } + + protected virtual void OnMeasureItem (MeasureItemEventArgs e) + { + if (!OwnerDraw) + return; + + MeasureItemEventHandler eh = (MeasureItemEventHandler)(Events [MeasureItemEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnPopup (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [PopupEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnSelect (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [SelectEvent]); + if (eh != null) + eh (this, e); + } + + public void PerformClick () + { + OnClick (EventArgs.Empty); + } + + public virtual void PerformSelect () + { + OnSelect (EventArgs.Empty); + } + + public override string ToString () + { + return base.ToString () + ", Items.Count: " + MenuItems.Count + ", Text: " + text; + } + + #endregion Public Methods + + #region Private Methods + + internal virtual void Invalidate () + { + if ((Parent == null) || !(Parent is MainMenu) || (Parent.Wnd == null)) + return; + + Form form = Parent.Wnd.FindForm (); + if ((form == null) || (!form.IsHandleCreated)) + return; + + XplatUI.RequestNCRecalc (form.Handle); + } + + internal void PerformPopup () + { + OnPopup (EventArgs.Empty); + } + + internal void PerformDrawItem (DrawItemEventArgs e) + { + PopulateWindowMenu (); + if (OwnerDraw) + OnDrawItem (e); + else + ThemeEngine.Current.DrawMenuItem (this, e); + } + + private void PopulateWindowMenu () + { + if (mdilist) { + if (mdilist_items == null) { + mdilist_items = new Hashtable (); + mdilist_forms = new Hashtable (); + } + + do { + MainMenu main = GetMainMenu (); + if (main == null || main.GetForm () == null) + break; + + Form form = main.GetForm (); + mdicontainer = form.MdiContainer; + if (mdicontainer == null) + break; + + + // Remove closed forms + MenuItem[] items = new MenuItem[mdilist_items.Count]; + mdilist_items.Keys.CopyTo (items, 0); + foreach (MenuItem item in items) { + Form mdichild = (Form) mdilist_items [item]; + if (!mdicontainer.mdi_child_list.Contains(mdichild)) { + mdilist_items.Remove (item); + mdilist_forms.Remove (mdichild); + MenuItems.Remove (item); + } + } + + // Add new forms and update state for existing forms. + for (int i = 0; i < mdicontainer.mdi_child_list.Count; i++) { + Form mdichild = (Form)mdicontainer.mdi_child_list[i]; + MenuItem item; + if (mdilist_forms.Contains (mdichild)) { + item = (MenuItem) mdilist_forms [mdichild]; + } else { + item = new MenuItem (); + item.is_window_menu_item = true; + item.Click += new EventHandler (MdiWindowClickHandler); + mdilist_items [item] = mdichild; + mdilist_forms [mdichild] = item; + MenuItems.AddNoEvents (item); + } + item.Visible = mdichild.Visible; + item.Text = "&" + (i + 1).ToString () + " " + mdichild.Text; + item.Checked = form.ActiveMdiChild == mdichild; + } + } while (false); + } else { + // Remove all forms + if (mdilist_items != null) { + foreach (MenuItem item in mdilist_items.Values) { + MenuItems.Remove (item); + } + + mdilist_forms.Clear (); + mdilist_items.Clear (); + } + } + } + + internal void PerformMeasureItem (MeasureItemEventArgs e) + { + OnMeasureItem (e); + } + + private void ProcessMnemonic () + { + if (text == null || text.Length < 2) { + mnemonic = '\0'; + return; + } + + bool bPrevAmp = false; + for (int i = 0; i < text.Length -1 ; i++) { + if (text[i] == '&') { + if (bPrevAmp == false && (text[i+1] != '&')) { + mnemonic = Char.ToUpper (text[i+1]); + return; + } + + bPrevAmp = true; + } + else + bPrevAmp = false; + } + + mnemonic = '\0'; + } + + private string GetShortCutTextCtrl () { return "Ctrl"; } + private string GetShortCutTextAlt () { return "Alt"; } + private string GetShortCutTextShift () { return "Shift"; } + + internal string GetShortCutText () + { + /* Ctrl+A - Ctrl+Z */ + if (Shortcut >= Shortcut.CtrlA && Shortcut <= Shortcut.CtrlZ) + return GetShortCutTextCtrl () + "+" + (char)((int) 'A' + (int)(Shortcut - Shortcut.CtrlA)); + + /* Alt+0 - Alt+9 */ + if (Shortcut >= Shortcut.Alt0 && Shortcut <= Shortcut.Alt9) + return GetShortCutTextAlt () + "+" + (char)((int) '0' + (int)(Shortcut - Shortcut.Alt0)); + + /* Alt+F1 - Alt+F2 */ + if (Shortcut >= Shortcut.AltF1 && Shortcut <= Shortcut.AltF9) + return GetShortCutTextAlt () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.AltF1)); + + /* Ctrl+0 - Ctrl+9 */ + if (Shortcut >= Shortcut.Ctrl0 && Shortcut <= Shortcut.Ctrl9) + return GetShortCutTextCtrl () + "+" + (char)((int) '0' + (int)(Shortcut - Shortcut.Ctrl0)); + + /* Ctrl+F0 - Ctrl+F9 */ + if (Shortcut >= Shortcut.CtrlF1 && Shortcut <= Shortcut.CtrlF9) + return GetShortCutTextCtrl () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.CtrlF1)); + + /* Ctrl+Shift+0 - Ctrl+Shift+9 */ + if (Shortcut >= Shortcut.CtrlShift0 && Shortcut <= Shortcut.CtrlShift9) + return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+" + (char)((int) '0' + (int)(Shortcut - Shortcut.CtrlShift0)); + + /* Ctrl+Shift+A - Ctrl+Shift+Z */ + if (Shortcut >= Shortcut.CtrlShiftA && Shortcut <= Shortcut.CtrlShiftZ) + return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+" + (char)((int) 'A' + (int)(Shortcut - Shortcut.CtrlShiftA)); + + /* Ctrl+Shift+F1 - Ctrl+Shift+F9 */ + if (Shortcut >= Shortcut.CtrlShiftF1 && Shortcut <= Shortcut.CtrlShiftF9) + return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.CtrlShiftF1)); + + /* F1 - F9 */ + if (Shortcut >= Shortcut.F1 && Shortcut <= Shortcut.F9) + return "F" + (char)((int) '1' + (int)(Shortcut - Shortcut.F1)); + + /* Shift+F1 - Shift+F9 */ + if (Shortcut >= Shortcut.ShiftF1 && Shortcut <= Shortcut.ShiftF9) + return GetShortCutTextShift () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.ShiftF1)); + + /* Special cases */ + switch (Shortcut) { + case Shortcut.AltBksp: + return "AltBksp"; + case Shortcut.AltF10: + return GetShortCutTextAlt () + "+F10"; + case Shortcut.AltF11: + return GetShortCutTextAlt () + "+F11"; + case Shortcut.AltF12: + return GetShortCutTextAlt () + "+F12"; + case Shortcut.CtrlDel: + return GetShortCutTextCtrl () + "+Del"; + case Shortcut.CtrlF10: + return GetShortCutTextCtrl () + "+F10"; + case Shortcut.CtrlF11: + return GetShortCutTextCtrl () + "+F11"; + case Shortcut.CtrlF12: + return GetShortCutTextCtrl () + "+F12"; + case Shortcut.CtrlIns: + return GetShortCutTextCtrl () + "+Ins"; + case Shortcut.CtrlShiftF10: + return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F10"; + case Shortcut.CtrlShiftF11: + return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F11"; + case Shortcut.CtrlShiftF12: + return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F12"; + case Shortcut.Del: + return "Del"; + case Shortcut.F10: + return "F10"; + case Shortcut.F11: + return "F11"; + case Shortcut.F12: + return "F12"; + case Shortcut.Ins: + return "Ins"; + case Shortcut.None: + return "None"; + case Shortcut.ShiftDel: + return GetShortCutTextShift () + "+Del"; + case Shortcut.ShiftF10: + return GetShortCutTextShift () + "+F10"; + case Shortcut.ShiftF11: + return GetShortCutTextShift () + "+F11"; + case Shortcut.ShiftF12: + return GetShortCutTextShift () + "+F12"; + case Shortcut.ShiftIns: + return GetShortCutTextShift () + "+Ins"; + default: + break; + } + + return ""; + } + + private void MdiWindowClickHandler (object sender, EventArgs e) + { + Form mdichild = (Form) mdilist_items [sender]; + + // people could add weird items to the Window menu + // so we can't assume its just us + if (mdichild == null) + return; + + mdicontainer.ActivateChild (mdichild); + } + + private void UpdateMenuItem () + { + if ((parent_menu == null) || (parent_menu.Tracker == null)) + return; + + parent_menu.Tracker.RemoveShortcuts (this); + parent_menu.Tracker.AddShortcuts (this); + } + + #endregion Private Methods + + } +} + + diff --git a/source/ShiftUI/Menu/MenuMerge.cs b/source/ShiftUI/Menu/MenuMerge.cs new file mode 100644 index 0000000..8731f64 --- /dev/null +++ b/source/ShiftUI/Menu/MenuMerge.cs @@ -0,0 +1,38 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// +// + +namespace ShiftUI +{ + public enum MenuMerge + { + Add = 0, + Replace = 1, + MergeItems = 2, + Remove = 3, + } +} + + diff --git a/source/ShiftUI/Menu/MenuStrip.cs b/source/ShiftUI/Menu/MenuStrip.cs new file mode 100644 index 0000000..85e585e --- /dev/null +++ b/source/ShiftUI/Menu/MenuStrip.cs @@ -0,0 +1,349 @@ +// +// MenuStrip.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Drawing; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + public class MenuStrip : ToolStrip + { + private ToolStripMenuItem mdi_window_list_item; + + public MenuStrip () : base () + { + base.CanOverflow = false; + this.GripStyle = ToolStripGripStyle.Hidden; + this.Stretch = true; + this.Dock = DockStyle.Top; + } + + #region Public Properties + [DefaultValue (false)] + [Browsable (false)] + public new bool CanOverflow { + get { return base.CanOverflow; } + set { base.CanOverflow = value; } + } + + [DefaultValue (ToolStripGripStyle.Hidden)] + public new ToolStripGripStyle GripStyle { + get { return base.GripStyle; } + set { base.GripStyle = value; } + } + + [DefaultValue (null)] + [MergableProperty (false)] + [TypeConverter (typeof (MdiWindowListItemConverter))] + public ToolStripMenuItem MdiWindowListItem { + get { return this.mdi_window_list_item; } + set { + if (this.mdi_window_list_item != value) { + this.mdi_window_list_item = value; + this.RefreshMdiItems (); + } + } + } + + [DefaultValue (false)] + public new bool ShowItemToolTips { + get { return base.ShowItemToolTips; } + set { base.ShowItemToolTips = value; } + } + + [DefaultValue (true)] + public new bool Stretch { + get { return base.Stretch; } + set { base.Stretch = value; } + } + #endregion + + #region Protected Properties + protected override Padding DefaultGripMargin { get { return new Padding (2, 2, 0, 2); } } + protected override Padding DefaultPadding { get { return new Padding (6, 2, 0, 2); } } + protected override bool DefaultShowItemToolTips { get { return false; } } + protected override Size DefaultSize { get { return new Size (200, 24); } } + #endregion + + #region Protected Methods + protected override AccessibleObject CreateAccessibilityInstance () + { + return new MenuStripAccessibleObject (); + } + + protected internal override ToolStripItem CreateDefaultItem (string text, Image image, EventHandler onClick) + { + return new ToolStripMenuItem (text, image, onClick); + } + + protected virtual void OnMenuActivate (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [MenuActivateEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnMenuDeactivate (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [MenuDeactivateEvent]); + if (eh != null) + eh (this, e); + } + + protected override bool ProcessCmdKey (ref Message m, Keys keyData) + { + return base.ProcessCmdKey (ref m, keyData); + } + + protected override void WndProc (ref Message m) + { + base.WndProc (ref m); + } + #endregion + + #region Public Events + static object MenuActivateEvent = new object (); + static object MenuDeactivateEvent = new object (); + + public event EventHandler MenuActivate { + add { Events.AddHandler (MenuActivateEvent, value); } + remove { Events.RemoveHandler (MenuActivateEvent, value); } + } + + public event EventHandler MenuDeactivate { + add { Events.AddHandler (MenuDeactivateEvent, value); } + remove { Events.RemoveHandler (MenuDeactivateEvent, value); } + } + #endregion + + #region Internal Properties + internal override bool KeyboardActive { + get { return base.KeyboardActive; } + set { + if (base.KeyboardActive != value) { + base.KeyboardActive = value; + + if (value) + this.OnMenuActivate (EventArgs.Empty); + else + this.OnMenuDeactivate (EventArgs.Empty); + } + } + } + + internal bool MenuDroppedDown { + get { return this.menu_selected; } + set { this.menu_selected = value; } + } + #endregion + + #region Internal Methods + internal override void Dismiss (ToolStripDropDownCloseReason reason) + { + // Make sure we don't auto-dropdown next time we're activated + this.MenuDroppedDown = false; + + base.Dismiss (reason); + + this.FireMenuDeactivate (); + } + + internal void FireMenuActivate () + { + // The tracker lets us know when the form is clicked or loses focus + ToolStripManager.AppClicked += new EventHandler (ToolStripMenuTracker_AppClicked); + ToolStripManager.AppFocusChange += new EventHandler (ToolStripMenuTracker_AppFocusChange); + + this.OnMenuActivate (EventArgs.Empty); + } + + internal void FireMenuDeactivate () + { + // Detach from the tracker + ToolStripManager.AppClicked -= new EventHandler (ToolStripMenuTracker_AppClicked); ; + ToolStripManager.AppFocusChange -= new EventHandler (ToolStripMenuTracker_AppFocusChange); + + this.OnMenuDeactivate (EventArgs.Empty); + } + + internal override bool OnMenuKey () + { + // Set ourselves active and select our first item + ToolStripManager.SetActiveToolStrip (this, true); + ToolStripItem tsi = this.SelectNextToolStripItem (null, true); + + if (tsi == null) + return false; + + if (tsi is MdiWidgetStrip.SystemMenuItem) + this.SelectNextToolStripItem (tsi, true); + + return true; + } + + private void ToolStripMenuTracker_AppFocusChange (object sender, EventArgs e) + { + this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppFocusChange); + } + + private void ToolStripMenuTracker_AppClicked (object sender, EventArgs e) + { + this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppClicked); + } + + internal void RefreshMdiItems () + { + if (this.mdi_window_list_item == null) + return; + + Form parent_form = this.FindForm (); + + if (parent_form == null || parent_form.MainMenuStrip != this) + return; + + MdiClient mdi = parent_form.MdiContainer; + + // If there isn't a MdiContainer, we don't need to worry about MdiItems :) + if (mdi == null) + return; + + // Make a copy so we can delete from the real one + ToolStripItem[] loopitems = new ToolStripItem[this.mdi_window_list_item.DropDownItems.Count]; + this.mdi_window_list_item.DropDownItems.CopyTo (loopitems, 0); + + // If the mdi child has been removed, remove our menu item + foreach (ToolStripItem tsi in loopitems) + if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry) + if (!mdi.mdi_child_list.Contains ((tsi as ToolStripMenuItem).MdiClientForm) || !(tsi as ToolStripMenuItem).MdiClientForm.Visible) + this.mdi_window_list_item.DropDownItems.Remove (tsi); + + // Add the new forms and update state + for (int i = 0; i < mdi.mdi_child_list.Count; i++) { + Form mdichild = (Form)mdi.mdi_child_list[i]; + ToolStripMenuItem tsi; + + if (!mdichild.Visible) + continue; + + if ((tsi = FindMdiMenuItemOfForm (mdichild)) == null) { + if (CountMdiMenuItems () == 0 && this.mdi_window_list_item.DropDownItems.Count > 0 && !(this.mdi_window_list_item.DropDownItems[this.mdi_window_list_item.DropDownItems.Count - 1] is ToolStripSeparator)) + this.mdi_window_list_item.DropDownItems.Add (new ToolStripSeparator ()); + + tsi = new ToolStripMenuItem (); + tsi.MdiClientForm = mdichild; + this.mdi_window_list_item.DropDownItems.Add (tsi); + } + + tsi.Text = string.Format ("&{0} {1}", i + 1, mdichild.Text); + tsi.Checked = parent_form.ActiveMdiChild == mdichild; + } + + // Check that everything is in the correct order + if (NeedToReorderMdi ()) + ReorderMdiMenu (); + } + + private ToolStripMenuItem FindMdiMenuItemOfForm (Form f) + { + // Not terribly efficient, but Mdi window lists shouldn't get too big + foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems) + if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).MdiClientForm == f) + return (ToolStripMenuItem)tsi; + + return null; + } + + private int CountMdiMenuItems () + { + int count = 0; + + foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems) + if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry) + count++; + + return count; + } + + private bool NeedToReorderMdi () + { + // Mdi menus must be: User Items, Separator, Mdi Items + bool seenMdi = false; + + foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems) { + if (tsi is ToolStripMenuItem) { + if (!(tsi as ToolStripMenuItem).IsMdiWindowListEntry) { + if (seenMdi) + return true; + } else + seenMdi = true; + } + } + + return false; + } + + private void ReorderMdiMenu () + { + ToolStripItem[] loopitems = new ToolStripItem[this.mdi_window_list_item.DropDownItems.Count]; + this.mdi_window_list_item.DropDownItems.CopyTo (loopitems, 0); + + this.mdi_window_list_item.DropDownItems.Clear (); + + foreach (ToolStripItem tsi in loopitems) + if (tsi is ToolStripSeparator || !(tsi as ToolStripMenuItem).IsMdiWindowListEntry) + this.mdi_window_list_item.DropDownItems.Add (tsi); + + int count = this.mdi_window_list_item.DropDownItems.Count; + + if (count > 0 && !(this.mdi_window_list_item.DropDownItems[count - 1] is ToolStripSeparator)) + this.mdi_window_list_item.DropDownItems.Add (new ToolStripSeparator ()); + + foreach (ToolStripItem tsi in loopitems) + if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry) + this.mdi_window_list_item.DropDownItems.Add (tsi); + } + #endregion + + #region MenuStripAccessibleObject + private class MenuStripAccessibleObject : AccessibleObject + { + } + #endregion + + } + + #region MdiWindowListItemConverter + internal class MdiWindowListItemConverter : TypeConverter + { + } + #endregion +} diff --git a/source/ShiftUI/MonoTODOAttribute.cs b/source/ShiftUI/MonoTODOAttribute.cs new file mode 100644 index 0000000..018db98 --- /dev/null +++ b/source/ShiftUI/MonoTODOAttribute.cs @@ -0,0 +1,120 @@ +// +// MonoTODOAttribute.cs +// +// Authors: +// Ravi Pratap (ravi@ximian.com) +// Eyal Alaluf +// +// (C) Ximian, Inc. http://www.ximian.com +// + +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// Copyright (C) 2006 Mainsoft, Inc (http://www.mainsoft.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace System { + + [AttributeUsage (AttributeTargets.All, AllowMultiple=true)] + internal class MonoTODOAttribute : Attribute { + + string comment; + + public MonoTODOAttribute () + { + } + + public MonoTODOAttribute (string comment) + { + this.comment = comment; + } + + public virtual string Comment { + get { return comment; } + } + } + + [AttributeUsage (AttributeTargets.All, AllowMultiple=true)] + internal class MonoDocumentationNoteAttribute : MonoTODOAttribute { + + public MonoDocumentationNoteAttribute (string comment) + : base (comment) + { + } + + public override string Comment { + get { return base.Comment; } + } + } + + [AttributeUsage (AttributeTargets.All, AllowMultiple=true)] + internal class MonoExtensionAttribute : MonoTODOAttribute { + + public MonoExtensionAttribute (string comment) + : base (comment) + { + } + + public override string Comment { + get { return base.Comment; } + } + } + + [AttributeUsage (AttributeTargets.All, AllowMultiple=true)] + internal class MonoInternalNoteAttribute : MonoTODOAttribute { + + public MonoInternalNoteAttribute (string comment) + : base (comment) + { + } + + public override string Comment { + get { return base.Comment; } + } + } + + [AttributeUsage (AttributeTargets.All, AllowMultiple=true)] + internal class MonoLimitationAttribute : MonoTODOAttribute { + + public MonoLimitationAttribute (string comment) + : base (comment) + { + } + + public override string Comment { + get { return base.Comment; } + } + } + + [AttributeUsage (AttributeTargets.All, AllowMultiple=true)] + internal class MonoNotSupportedAttribute : MonoTODOAttribute { + + public MonoNotSupportedAttribute (string comment) + : base (comment) + { + } + + public override string Comment { + get { return base.Comment; } + } + } +} diff --git a/source/ShiftUI/Mouse/DragAction.cs b/source/ShiftUI/Mouse/DragAction.cs new file mode 100644 index 0000000..ed52a7d --- /dev/null +++ b/source/ShiftUI/Mouse/DragAction.cs @@ -0,0 +1,39 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +using System.Runtime.InteropServices; + +namespace ShiftUI { + [ComVisible(true)] + public enum DragAction { + Continue = 0, + Drop = 1, + Cancel = 2 + } +} diff --git a/source/ShiftUI/Mouse/DragDropEffects.cs b/source/ShiftUI/Mouse/DragDropEffects.cs new file mode 100644 index 0000000..96a7f38 --- /dev/null +++ b/source/ShiftUI/Mouse/DragDropEffects.cs @@ -0,0 +1,41 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +namespace ShiftUI { + + [Flags] + public enum DragDropEffects { + None = 0x00000000, + Copy = 0x00000001, + Move = 0x00000002, + Link = 0x00000004, + Scroll = unchecked((int)0x80000000), + All = unchecked((int)0x80000003) + } +} diff --git a/source/ShiftUI/Mouse/DragEventArgs.cs b/source/ShiftUI/Mouse/DragEventArgs.cs new file mode 100644 index 0000000..9fec91e --- /dev/null +++ b/source/ShiftUI/Mouse/DragEventArgs.cs @@ -0,0 +1,96 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + [ComVisible(true)] + public class DragEventArgs : EventArgs { + internal int x; + internal int y; + internal int keystate; + internal DragDropEffects allowed_effect; + internal DragDropEffects current_effect; + internal IDataObject data_object; + + #region Public Constructors + public DragEventArgs(IDataObject data, int keyState, int x, int y, DragDropEffects allowedEffect, DragDropEffects effect) { + this.x=x; + this.y=y; + this.keystate=keyState; + this.allowed_effect=allowedEffect; + this.current_effect=effect; + this.data_object=data; + } + #endregion // Public Constructors + + #region Public Instance Properties + public DragDropEffects AllowedEffect { + get { + return this.allowed_effect; + } + } + + public IDataObject Data { + get { + return this.data_object; + } + } + + public DragDropEffects Effect { + get { + return this.current_effect; + } + + set { + current_effect = value; + } + } + + public int KeyState { + get { + return this.keystate; + } + } + + public int X { + get { + return this.x; + } + } + + public int Y { + get { + return this.y; + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Mouse/DragEventHandler.cs b/source/ShiftUI/Mouse/DragEventHandler.cs new file mode 100644 index 0000000..71e343c --- /dev/null +++ b/source/ShiftUI/Mouse/DragEventHandler.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +namespace ShiftUI { + public delegate void DragEventHandler (object sender, DragEventArgs e); +} diff --git a/source/ShiftUI/Mouse/MouseEventArgs.cs b/source/ShiftUI/Mouse/MouseEventArgs.cs new file mode 100644 index 0000000..295172f --- /dev/null +++ b/source/ShiftUI/Mouse/MouseEventArgs.cs @@ -0,0 +1,90 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + + +// COMPLETE + +using System.Runtime.InteropServices; +using System.Drawing; +using System; + +namespace ShiftUI { + [ComVisible(true)] + public class MouseEventArgs : EventArgs { + private MouseButtons buttons; + private int clicks; + private int delta; + private int x; + private int y; + + #region Public Constructors + public MouseEventArgs(MouseButtons button, int clicks, int x, int y, int delta) { + this.buttons=button; + this.clicks=clicks; + this.delta=delta; + this.x=x; + this.y=y; + } + #endregion // Public Constructors + + #region Public Instance Properties + public MouseButtons Button { + get { + return this.buttons; + } + } + + public int Clicks { + get { + return this.clicks; + } + } + + public int Delta { + get { + return this.delta; + } + } + + public int X { + get { + return this.x; + } + } + + public int Y { + get { + return this.y; + } + } + + public Point Location { + get { + return new Point (this.x, this.y); + } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/Mouse/MouseEventHandler.cs b/source/ShiftUI/Mouse/MouseEventHandler.cs new file mode 100644 index 0000000..76fc643 --- /dev/null +++ b/source/ShiftUI/Mouse/MouseEventHandler.cs @@ -0,0 +1,32 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +namespace ShiftUI { + public delegate void MouseEventHandler (object sender, MouseEventArgs e); +} diff --git a/source/ShiftUI/Properties/AssemblyInfo.cs b/source/ShiftUI/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0f66c80 --- /dev/null +++ b/source/ShiftUI/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using System.Resources; +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle ("ShiftUI")] +[assembly: AssemblyDescription("Windows Forms on meth.")] +[assembly: AssemblyConfiguration ("")] +[assembly: AssemblyCompany ("")] +[assembly: AssemblyProduct("ShiftUI")] +[assembly: AssemblyCopyright("Michael VanOverbeek, Mono developers.")] +[assembly: AssemblyTrademark ("")] +[assembly: AssemblyCulture ("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("0.0.1.0")] +[assembly: AssemblyFileVersion("0.0.1.0")] +[assembly: NeutralResourcesLanguage("en-US")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/source/ShiftUI/Properties/Resources.Designer.cs b/source/ShiftUI/Properties/Resources.Designer.cs new file mode 100644 index 0000000..a39c9de --- /dev/null +++ b/source/ShiftUI/Properties/Resources.Designer.cs @@ -0,0 +1,143 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ShiftUI.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ShiftUI.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + public static byte[] DnDCopy { + get { + object obj = ResourceManager.GetObject("DnDCopy", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + public static byte[] DnDLink { + get { + object obj = ResourceManager.GetObject("DnDLink", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + public static byte[] DnDMove { + get { + object obj = ResourceManager.GetObject("DnDMove", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + public static byte[] DnDNo { + get { + object obj = ResourceManager.GetObject("DnDNo", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + public static byte[] NESW { + get { + object obj = ResourceManager.GetObject("NESW", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + public static byte[] NWSE { + get { + object obj = ResourceManager.GetObject("NWSE", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + public static byte[] SplitterNS { + get { + object obj = ResourceManager.GetObject("SplitterNS", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + public static byte[] SplitterWE { + get { + object obj = ResourceManager.GetObject("SplitterWE", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/source/ShiftUI/Properties/Resources.resx b/source/ShiftUI/Properties/Resources.resx new file mode 100644 index 0000000..97b12fd --- /dev/null +++ b/source/ShiftUI/Properties/Resources.resx @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\DnDCopy.cur;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\DnDLink.cur;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\DnDMove.cur;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\DnDNo.cur;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\NESW.cur;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\NWSE.cur;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\SplitterNS.cur;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\SplitterWE.cur;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/source/ShiftUI/RTF/Charcode.cs b/source/ShiftUI/RTF/Charcode.cs new file mode 100644 index 0000000..02480b5 --- /dev/null +++ b/source/ShiftUI/RTF/Charcode.cs @@ -0,0 +1,413 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +using System.Collections; + +namespace ShiftUI.RTF { + internal class Charcode { + #region Local Variables + private StandardCharCode[] codes; + private Hashtable reverse; + private int size; + #endregion // Local Variables + + #region Cached Values + static Charcode ansi_generic; + #endregion + + #region Public Constructors + public Charcode() : this(256) { + } + + private Charcode(int size) { + this.size = size; + this.codes = new StandardCharCode[size]; + this.reverse = new Hashtable(size); + + // No need to reinitialize array to its default value + //for (int i = 0; i < size; i++) { + // codes[i] = StandardCharCode.nothing; + //} + } + #endregion // Public Constructors + + #region Public Instance Properties + public int this[StandardCharCode c] { + get { + object obj; + + obj = reverse[c]; + if (obj != null) { + return (int)obj; + } + for (int i = 0; i < size; i++) { + if (codes[i] == c) { + return i; + } + } + + return -1; + } + } + + public StandardCharCode this[int c] { + get { + if (c < 0 || c >= size) { + return StandardCharCode.nothing; + } + + return codes[c]; + } + + private set { + if (c < 0 || c >= size) { + return; + } + + codes[c] = value; + reverse[value] = c; + } + } + #endregion // Public Instance Properties + + #region Public Instance Methods + #endregion // Public Instance Methods + + #region Public Static Methods + public static Charcode AnsiGeneric { + get { + if (ansi_generic != null) + return ansi_generic; + + ansi_generic = new Charcode(256); + + ansi_generic[0x06] = StandardCharCode.formula; + ansi_generic[0x1e] = StandardCharCode.nobrkhyphen; + ansi_generic[0x1f] = StandardCharCode.opthyphen; + ansi_generic[' '] = StandardCharCode.space; + ansi_generic['!'] = StandardCharCode.exclam; + ansi_generic['"'] = StandardCharCode.quotedbl; + ansi_generic['#'] = StandardCharCode.numbersign; + ansi_generic['$'] = StandardCharCode.dollar; + ansi_generic['%'] = StandardCharCode.percent; + ansi_generic['&'] = StandardCharCode.ampersand; + ansi_generic['\\'] = StandardCharCode.quoteright; + ansi_generic['('] = StandardCharCode.parenleft; + ansi_generic[')'] = StandardCharCode.parenright; + ansi_generic['*'] = StandardCharCode.asterisk; + ansi_generic['+'] = StandardCharCode.plus; + ansi_generic[','] = StandardCharCode.comma; + ansi_generic['-'] = StandardCharCode.hyphen; + ansi_generic['.'] = StandardCharCode.period; + ansi_generic['/'] = StandardCharCode.slash; + ansi_generic['0'] = StandardCharCode.zero; + ansi_generic['1'] = StandardCharCode.one; + ansi_generic['2'] = StandardCharCode.two; + ansi_generic['3'] = StandardCharCode.three; + ansi_generic['4'] = StandardCharCode.four; + ansi_generic['5'] = StandardCharCode.five; + ansi_generic['6'] = StandardCharCode.six; + ansi_generic['7'] = StandardCharCode.seven; + ansi_generic['8'] = StandardCharCode.eight; + ansi_generic['9'] = StandardCharCode.nine; + ansi_generic[':'] = StandardCharCode.colon; + ansi_generic[';'] = StandardCharCode.semicolon; + ansi_generic['<'] = StandardCharCode.less; + ansi_generic['='] = StandardCharCode.equal; + ansi_generic['>'] = StandardCharCode.greater; + ansi_generic['?'] = StandardCharCode.question; + ansi_generic['@'] = StandardCharCode.at; + ansi_generic['A'] = StandardCharCode.A; + ansi_generic['B'] = StandardCharCode.B; + ansi_generic['C'] = StandardCharCode.C; + ansi_generic['D'] = StandardCharCode.D; + ansi_generic['E'] = StandardCharCode.E; + ansi_generic['F'] = StandardCharCode.F; + ansi_generic['G'] = StandardCharCode.G; + ansi_generic['H'] = StandardCharCode.H; + ansi_generic['I'] = StandardCharCode.I; + ansi_generic['J'] = StandardCharCode.J; + ansi_generic['K'] = StandardCharCode.K; + ansi_generic['L'] = StandardCharCode.L; + ansi_generic['M'] = StandardCharCode.M; + ansi_generic['N'] = StandardCharCode.N; + ansi_generic['O'] = StandardCharCode.O; + ansi_generic['P'] = StandardCharCode.P; + ansi_generic['Q'] = StandardCharCode.Q; + ansi_generic['R'] = StandardCharCode.R; + ansi_generic['S'] = StandardCharCode.S; + ansi_generic['T'] = StandardCharCode.T; + ansi_generic['U'] = StandardCharCode.U; + ansi_generic['V'] = StandardCharCode.V; + ansi_generic['W'] = StandardCharCode.W; + ansi_generic['X'] = StandardCharCode.X; + ansi_generic['Y'] = StandardCharCode.Y; + ansi_generic['Z'] = StandardCharCode.Z; + ansi_generic['['] = StandardCharCode.bracketleft; + ansi_generic['\\'] = StandardCharCode.backslash; + ansi_generic[']'] = StandardCharCode.bracketright; + ansi_generic['^'] = StandardCharCode.asciicircum; + ansi_generic['_'] = StandardCharCode.underscore; + ansi_generic['`'] = StandardCharCode.quoteleft; + ansi_generic['a'] = StandardCharCode.a; + ansi_generic['b'] = StandardCharCode.b; + ansi_generic['c'] = StandardCharCode.c; + ansi_generic['d'] = StandardCharCode.d; + ansi_generic['e'] = StandardCharCode.e; + ansi_generic['f'] = StandardCharCode.f; + ansi_generic['g'] = StandardCharCode.g; + ansi_generic['h'] = StandardCharCode.h; + ansi_generic['i'] = StandardCharCode.i; + ansi_generic['j'] = StandardCharCode.j; + ansi_generic['k'] = StandardCharCode.k; + ansi_generic['l'] = StandardCharCode.l; + ansi_generic['m'] = StandardCharCode.m; + ansi_generic['n'] = StandardCharCode.n; + ansi_generic['o'] = StandardCharCode.o; + ansi_generic['p'] = StandardCharCode.p; + ansi_generic['q'] = StandardCharCode.q; + ansi_generic['r'] = StandardCharCode.r; + ansi_generic['s'] = StandardCharCode.s; + ansi_generic['t'] = StandardCharCode.t; + ansi_generic['u'] = StandardCharCode.u; + ansi_generic['v'] = StandardCharCode.v; + ansi_generic['w'] = StandardCharCode.w; + ansi_generic['x'] = StandardCharCode.x; + ansi_generic['y'] = StandardCharCode.y; + ansi_generic['z'] = StandardCharCode.z; + ansi_generic['{'] = StandardCharCode.braceleft; + ansi_generic['|'] = StandardCharCode.bar; + ansi_generic['}'] = StandardCharCode.braceright; + ansi_generic['~'] = StandardCharCode.asciitilde; + ansi_generic[0xa0] = StandardCharCode.nobrkspace; + ansi_generic[0xa1] = StandardCharCode.exclamdown; + ansi_generic[0xa2] = StandardCharCode.cent; + ansi_generic[0xa3] = StandardCharCode.sterling; + ansi_generic[0xa4] = StandardCharCode.currency; + ansi_generic[0xa5] = StandardCharCode.yen; + ansi_generic[0xa6] = StandardCharCode.brokenbar; + ansi_generic[0xa7] = StandardCharCode.section; + ansi_generic[0xa8] = StandardCharCode.dieresis; + ansi_generic[0xa9] = StandardCharCode.copyright; + ansi_generic[0xaa] = StandardCharCode.ordfeminine; + ansi_generic[0xab] = StandardCharCode.guillemotleft; + ansi_generic[0xac] = StandardCharCode.logicalnot; + ansi_generic[0xad] = StandardCharCode.opthyphen; + ansi_generic[0xae] = StandardCharCode.registered; + ansi_generic[0xaf] = StandardCharCode.macron; + ansi_generic[0xb0] = StandardCharCode.degree; + ansi_generic[0xb1] = StandardCharCode.plusminus; + ansi_generic[0xb2] = StandardCharCode.twosuperior; + ansi_generic[0xb3] = StandardCharCode.threesuperior; + ansi_generic[0xb4] = StandardCharCode.acute; + ansi_generic[0xb5] = StandardCharCode.mu; + ansi_generic[0xb6] = StandardCharCode.paragraph; + ansi_generic[0xb7] = StandardCharCode.periodcentered; + ansi_generic[0xb8] = StandardCharCode.cedilla; + ansi_generic[0xb9] = StandardCharCode.onesuperior; + ansi_generic[0xba] = StandardCharCode.ordmasculine; + ansi_generic[0xbb] = StandardCharCode.guillemotright; + ansi_generic[0xbc] = StandardCharCode.onequarter; + ansi_generic[0xbd] = StandardCharCode.onehalf; + ansi_generic[0xbe] = StandardCharCode.threequarters; + ansi_generic[0xbf] = StandardCharCode.questiondown; + ansi_generic[0xc0] = StandardCharCode.Agrave; + ansi_generic[0xc1] = StandardCharCode.Aacute; + ansi_generic[0xc2] = StandardCharCode.Acircumflex; + ansi_generic[0xc3] = StandardCharCode.Atilde; + ansi_generic[0xc4] = StandardCharCode.Adieresis; + ansi_generic[0xc5] = StandardCharCode.Aring; + ansi_generic[0xc6] = StandardCharCode.AE; + ansi_generic[0xc7] = StandardCharCode.Ccedilla; + ansi_generic[0xc8] = StandardCharCode.Egrave; + ansi_generic[0xc9] = StandardCharCode.Eacute; + ansi_generic[0xca] = StandardCharCode.Ecircumflex; + ansi_generic[0xcb] = StandardCharCode.Edieresis; + ansi_generic[0xcc] = StandardCharCode.Igrave; + ansi_generic[0xcd] = StandardCharCode.Iacute; + ansi_generic[0xce] = StandardCharCode.Icircumflex; + ansi_generic[0xcf] = StandardCharCode.Idieresis; + ansi_generic[0xd0] = StandardCharCode.Eth; + ansi_generic[0xd1] = StandardCharCode.Ntilde; + ansi_generic[0xd2] = StandardCharCode.Ograve; + ansi_generic[0xd3] = StandardCharCode.Oacute; + ansi_generic[0xd4] = StandardCharCode.Ocircumflex; + ansi_generic[0xd5] = StandardCharCode.Otilde; + ansi_generic[0xd6] = StandardCharCode.Odieresis; + ansi_generic[0xd7] = StandardCharCode.multiply; + ansi_generic[0xd8] = StandardCharCode.Oslash; + ansi_generic[0xd9] = StandardCharCode.Ugrave; + ansi_generic[0xda] = StandardCharCode.Uacute; + ansi_generic[0xdb] = StandardCharCode.Ucircumflex; + ansi_generic[0xdc] = StandardCharCode.Udieresis; + ansi_generic[0xdd] = StandardCharCode.Yacute; + ansi_generic[0xde] = StandardCharCode.Thorn; + ansi_generic[0xdf] = StandardCharCode.germandbls; + ansi_generic[0xe0] = StandardCharCode.agrave; + ansi_generic[0xe1] = StandardCharCode.aacute; + ansi_generic[0xe2] = StandardCharCode.acircumflex; + ansi_generic[0xe3] = StandardCharCode.atilde; + ansi_generic[0xe4] = StandardCharCode.adieresis; + ansi_generic[0xe5] = StandardCharCode.aring; + ansi_generic[0xe6] = StandardCharCode.ae; + ansi_generic[0xe7] = StandardCharCode.ccedilla; + ansi_generic[0xe8] = StandardCharCode.egrave; + ansi_generic[0xe9] = StandardCharCode.eacute; + ansi_generic[0xea] = StandardCharCode.ecircumflex; + ansi_generic[0xeb] = StandardCharCode.edieresis; + ansi_generic[0xec] = StandardCharCode.igrave; + ansi_generic[0xed] = StandardCharCode.iacute; + ansi_generic[0xee] = StandardCharCode.icircumflex; + ansi_generic[0xef] = StandardCharCode.idieresis; + ansi_generic[0xf0] = StandardCharCode.eth; + ansi_generic[0xf1] = StandardCharCode.ntilde; + ansi_generic[0xf2] = StandardCharCode.ograve; + ansi_generic[0xf3] = StandardCharCode.oacute; + ansi_generic[0xf4] = StandardCharCode.ocircumflex; + ansi_generic[0xf5] = StandardCharCode.otilde; + ansi_generic[0xf6] = StandardCharCode.odieresis; + ansi_generic[0xf7] = StandardCharCode.divide; + ansi_generic[0xf8] = StandardCharCode.oslash; + ansi_generic[0xf9] = StandardCharCode.ugrave; + ansi_generic[0xfa] = StandardCharCode.uacute; + ansi_generic[0xfb] = StandardCharCode.ucircumflex; + ansi_generic[0xfc] = StandardCharCode.udieresis; + ansi_generic[0xfd] = StandardCharCode.yacute; + ansi_generic[0xfe] = StandardCharCode.thorn; + ansi_generic[0xff] = StandardCharCode.ydieresis; + + return ansi_generic; + } + } + + public static Charcode AnsiSymbol { + get { + Charcode code = new Charcode(256); + + code[0x06] = StandardCharCode.formula; + code[0x1e] = StandardCharCode.nobrkhyphen; + code[0x1f] = StandardCharCode.opthyphen; + code[' '] = StandardCharCode.space; + code['!'] = StandardCharCode.exclam; + code['"'] = StandardCharCode.universal; + code['#'] = StandardCharCode.mathnumbersign; + code['$'] = StandardCharCode.existential; + code['%'] = StandardCharCode.percent; + code['&'] = StandardCharCode.ampersand; + code['\\'] = StandardCharCode.suchthat; + code['('] = StandardCharCode.parenleft; + code[')'] = StandardCharCode.parenright; + code['*'] = StandardCharCode.mathasterisk; + code['+'] = StandardCharCode.mathplus; + code[','] = StandardCharCode.comma; + code['-'] = StandardCharCode.mathminus; + code['.'] = StandardCharCode.period; + code['/'] = StandardCharCode.slash; + code['0'] = StandardCharCode.zero; + code['1'] = StandardCharCode.one; + code['2'] = StandardCharCode.two; + code['3'] = StandardCharCode.three; + code['4'] = StandardCharCode.four; + code['5'] = StandardCharCode.five; + code['6'] = StandardCharCode.six; + code['7'] = StandardCharCode.seven; + code['8'] = StandardCharCode.eight; + code['9'] = StandardCharCode.nine; + code[':'] = StandardCharCode.colon; + code[';'] = StandardCharCode.semicolon; + code['<'] = StandardCharCode.less; + code['='] = StandardCharCode.mathequal; + code['>'] = StandardCharCode.greater; + code['?'] = StandardCharCode.question; + code['@'] = StandardCharCode.congruent; + code['A'] = StandardCharCode.Alpha; + code['B'] = StandardCharCode.Beta; + code['C'] = StandardCharCode.Chi; + code['D'] = StandardCharCode.Delta; + code['E'] = StandardCharCode.Epsilon; + code['F'] = StandardCharCode.Phi; + code['G'] = StandardCharCode.Gamma; + code['H'] = StandardCharCode.Eta; + code['I'] = StandardCharCode.Iota; + code['K'] = StandardCharCode.Kappa; + code['L'] = StandardCharCode.Lambda; + code['M'] = StandardCharCode.Mu; + code['N'] = StandardCharCode.Nu; + code['O'] = StandardCharCode.Omicron; + code['P'] = StandardCharCode.Pi; + code['Q'] = StandardCharCode.Theta; + code['R'] = StandardCharCode.Rho; + code['S'] = StandardCharCode.Sigma; + code['T'] = StandardCharCode.Tau; + code['U'] = StandardCharCode.Upsilon; + code['V'] = StandardCharCode.varsigma; + code['W'] = StandardCharCode.Omega; + code['X'] = StandardCharCode.Xi; + code['Y'] = StandardCharCode.Psi; + code['Z'] = StandardCharCode.Zeta; + code['['] = StandardCharCode.bracketleft; + code['\\'] = StandardCharCode.backslash; + code[']'] = StandardCharCode.bracketright; + code['^'] = StandardCharCode.asciicircum; + code['_'] = StandardCharCode.underscore; + code['`'] = StandardCharCode.quoteleft; + code['a'] = StandardCharCode.alpha; + code['b'] = StandardCharCode.beta; + code['c'] = StandardCharCode.chi; + code['d'] = StandardCharCode.delta; + code['e'] = StandardCharCode.epsilon; + code['f'] = StandardCharCode.phi; + code['g'] = StandardCharCode.gamma; + code['h'] = StandardCharCode.eta; + code['i'] = StandardCharCode.iota; + code['k'] = StandardCharCode.kappa; + code['l'] = StandardCharCode.lambda; + code['m'] = StandardCharCode.mu; + code['n'] = StandardCharCode.nu; + code['o'] = StandardCharCode.omicron; + code['p'] = StandardCharCode.pi; + code['q'] = StandardCharCode.theta; + code['r'] = StandardCharCode.rho; + code['s'] = StandardCharCode.sigma; + code['t'] = StandardCharCode.tau; + code['u'] = StandardCharCode.upsilon; + code['w'] = StandardCharCode.omega; + code['x'] = StandardCharCode.xi; + code['y'] = StandardCharCode.psi; + code['z'] = StandardCharCode.zeta; + code['{'] = StandardCharCode.braceleft; + code['|'] = StandardCharCode.bar; + code['}'] = StandardCharCode.braceright; + code['~'] = StandardCharCode.mathtilde; + + return code; + } + } + #endregion // Public Static Methods + } +} diff --git a/source/ShiftUI/RTF/Charset.cs b/source/ShiftUI/RTF/Charset.cs new file mode 100644 index 0000000..37dc4db --- /dev/null +++ b/source/ShiftUI/RTF/Charset.cs @@ -0,0 +1,157 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +using System; + +// COMPLETE + +namespace ShiftUI.RTF { + +#if RTF_LIB + public +#else + internal +#endif + class Charset { + #region Local Variables + private CharsetType id; + private CharsetFlags flags; + private Charcode code; + private string file; + #endregion // Local Variables + + #region Public Constructors + public Charset() { + flags = CharsetFlags.Read | CharsetFlags.Switch; + id = CharsetType.General; + file = string.Empty; + this.ReadMap(); + } + #endregion // Public Constructors + + #region Public Instance Properties + public Charcode Code { + get { + return code; + } + + set { + code = value; + } + } + + public CharsetFlags Flags { + get { + return flags; + } + + set { + flags = value; + } + } + + public CharsetType ID { + get { + return id; + } + + set { + switch(value) { + case CharsetType.Symbol: { + id = CharsetType.Symbol; + return; + } + + default: + case CharsetType.General: { + id = CharsetType.General; + return; + } + } + } + } + + public string File { + get { + return file; + } + + set { + if (file != value) { + file = value; + } + } + } + + public StandardCharCode this[int c] { + get { + return code[c]; + } + } + + #endregion // Public Instance Properties + + #region Public Instance Methods + public bool ReadMap() { + switch (id) { + case CharsetType.General: { + if (file == string.Empty) { + code = Charcode.AnsiGeneric; + return true; + } + // FIXME - implement reading charmap from file... + return true; + } + + case CharsetType.Symbol: { + if (file == string.Empty) { + code = Charcode.AnsiSymbol; + return true; + } + + // FIXME - implement reading charmap from file... + return true; + } + + default: { + return false; + } + } + } + + public char StdCharCode(string name) { + // FIXME - finish this + return ' '; + + } + + public string StdCharName(char code) { + // FIXME - finish this + return String.Empty; + } + #endregion // Public Instance Methods + } +} diff --git a/source/ShiftUI/RTF/CharsetFlags.cs b/source/ShiftUI/RTF/CharsetFlags.cs new file mode 100644 index 0000000..bf6dd90 --- /dev/null +++ b/source/ShiftUI/RTF/CharsetFlags.cs @@ -0,0 +1,42 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE +using System; + +namespace ShiftUI.RTF { + [Flags] +#if RTF_LIB + public +#else + internal +#endif + enum CharsetFlags { + None = 0x00, + Read = 0x01, + Switch = 0x02 + } +} diff --git a/source/ShiftUI/RTF/CharsetType.cs b/source/ShiftUI/RTF/CharsetType.cs new file mode 100644 index 0000000..8ffd8ab --- /dev/null +++ b/source/ShiftUI/RTF/CharsetType.cs @@ -0,0 +1,40 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +namespace ShiftUI.RTF { + +#if RTF_LIB + public +#else + internal +#endif + enum CharsetType { + General = 0, + Symbol = 1, + } +} diff --git a/source/ShiftUI/RTF/ClassDelegate.cs b/source/ShiftUI/RTF/ClassDelegate.cs new file mode 100644 index 0000000..fc3eebc --- /dev/null +++ b/source/ShiftUI/RTF/ClassDelegate.cs @@ -0,0 +1,61 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE +using System; + +namespace ShiftUI.RTF { + +#if RTF_LIB + public +#else + internal +#endif + delegate void ClassDelegate(RTF sender); + +#if RTF_LIB + public +#else + internal +#endif + class ClassCallback { + ClassDelegate[] callbacks; + + public ClassCallback() { + callbacks = new ClassDelegate[Enum.GetValues(typeof(Major)).Length]; + } + + public ClassDelegate this[TokenClass c] { + get { + return callbacks[(int)c]; + } + + set { + callbacks[(int)c] = value; + } + } + } +} diff --git a/source/ShiftUI/RTF/Color.cs b/source/ShiftUI/RTF/Color.cs new file mode 100644 index 0000000..943b960 --- /dev/null +++ b/source/ShiftUI/RTF/Color.cs @@ -0,0 +1,133 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +namespace ShiftUI.RTF { + +#if RTF_LIB + public +#else + internal +#endif + class Color { + #region Local Variables + private int red; + private int green; + private int blue; + private int num; + private Color next; + #endregion // Local Variables + + #region Constructors + public Color(RTF rtf) { + red = -1; + green = -1; + blue = -1; + num = -1; + + lock (rtf) { + if (rtf.Colors == null) { + rtf.Colors = this; + } else { + Color c = rtf.Colors; + while (c.next != null) + c = c.next; + c.next = this; + } + } + } + #endregion // Constructors + + #region Properties + public int Red { + get { + return red; + } + + set { + red = value; + } + } + + public int Green { + get { + return green; + } + + set { + green = value; + } + } + + public int Blue { + get { + return blue; + } + + set { + blue = value; + } + } + + public int Num { + get { + return num; + } + + set { + num = value; + } + } + #endregion // Properties + + #region Methods + static public Color GetColor(RTF rtf, int color_number) { + Color c; + + lock (rtf) { + c = GetColor(rtf.Colors, color_number); + } + return c; + } + + static private Color GetColor(Color start, int color_number) { + Color c; + + if (color_number == -1) { + return start; + } + + c = start; + + while ((c != null) && (c.num != color_number)) { + c = c.next; + } + return c; + } + #endregion // Methods + } +} diff --git a/source/ShiftUI/RTF/DestinationDelegate.cs b/source/ShiftUI/RTF/DestinationDelegate.cs new file mode 100644 index 0000000..80fa0b3 --- /dev/null +++ b/source/ShiftUI/RTF/DestinationDelegate.cs @@ -0,0 +1,61 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE +using System; + +namespace ShiftUI.RTF { + +#if RTF_LIB + public +#else + internal +#endif + delegate void DestinationDelegate(RTF Sender); + +#if RTF_LIB + public +#else + internal +#endif + class DestinationCallback { + DestinationDelegate[] callbacks; + + public DestinationCallback() { + callbacks = new DestinationDelegate[Enum.GetValues(typeof(Minor)).Length]; + } + + public DestinationDelegate this[Minor c] { + get { + return callbacks[(int)c]; + } + + set { + callbacks[(int)c] = value; + } + } + } +} diff --git a/source/ShiftUI/RTF/Font.cs b/source/ShiftUI/RTF/Font.cs new file mode 100644 index 0000000..52b29e5 --- /dev/null +++ b/source/ShiftUI/RTF/Font.cs @@ -0,0 +1,209 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE +using System; + +namespace ShiftUI.RTF { + +#if RTF_LIB + public +#else + internal +#endif + class Font { + #region Local Variables + private string name; + private string alt_name; + private int num; + private int family; + private CharsetType charset; + private int pitch; + private int type; + private int codepage; + private Font next; + private RTF rtf; + #endregion // Local Variables + + #region Constructors + public Font(RTF rtf) { + this.rtf = rtf; + num = -1; + name = String.Empty; + + lock (rtf) { + if (rtf.Fonts == null) + rtf.Fonts = this; + else { + Font f = rtf.Fonts; + while (f.next != null) + f = f.next; + f.next = this; + } + } + } + #endregion // Constructors + + #region Properties + public string Name { + get { + return name; + } + + set { + name = value; + } + } + + public string AltName { + get { + return alt_name; + } + + set { + alt_name = value; + } + } + + public int Num { + get { + return num; + } + + set { + // Whack any previous font with the same number + DeleteFont(rtf, value); + num = value; + } + } + + public int Family { + get { + return family; + } + + set { + family = value; + } + } + + public CharsetType Charset { + get { + return charset; + } + + set { + charset = value; + } + } + + + public int Pitch { + get { + return pitch; + } + + set { + pitch = value; + } + } + + public int Type { + get { + return type; + } + + set { + type = value; + } + } + + public int Codepage { + get { + return codepage; + } + + set { + codepage = value; + } + } + #endregion // Properties + + #region Methods + static public bool DeleteFont(RTF rtf, int font_number) { + Font f; + Font prev; + + lock (rtf) { + f = rtf.Fonts; + prev = null; + while ((f != null) && (f.num != font_number)) { + prev = f; + f = f.next; + } + + if (f != null) { + if (f == rtf.Fonts) { + rtf.Fonts = f.next; + } else { + if (prev != null) { + prev.next = f.next; + } else { + rtf.Fonts = f.next; + } + } + return true; + } + } + return false; + } + + static public Font GetFont(RTF rtf, int font_number) { + Font f; + + lock (rtf) { + f = GetFont(rtf.Fonts, font_number); + } + return f; + } + + static public Font GetFont(Font start, int font_number) { + Font f; + + if (font_number == -1) { + return start; + } + + f = start; + + while ((f != null) && (f.num != font_number)) { + f = f.next; + } + return f; + } + #endregion // Methods + } +} diff --git a/source/ShiftUI/RTF/KeyStruct.cs b/source/ShiftUI/RTF/KeyStruct.cs new file mode 100644 index 0000000..6c4120c --- /dev/null +++ b/source/ShiftUI/RTF/KeyStruct.cs @@ -0,0 +1,46 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +namespace ShiftUI.RTF { + +#if RTF_LIB + public +#else + internal +#endif + struct KeyStruct { + public KeyStruct(Major major, Minor minor, string symbol) { + Major = major; + Minor = minor; + Symbol = symbol; + } + public Major Major; + public Minor Minor; + public string Symbol; + } +} diff --git a/source/ShiftUI/RTF/KeysInit.cs b/source/ShiftUI/RTF/KeysInit.cs new file mode 100644 index 0000000..49daf1e --- /dev/null +++ b/source/ShiftUI/RTF/KeysInit.cs @@ -0,0 +1,720 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +namespace ShiftUI.RTF { + internal class KeysInit { + public static KeyStruct[] Init() { + return new KeyStruct[] { + new KeyStruct(Major.SpecialChar, Minor.IIntVersion, "vern"), + new KeyStruct(Major.SpecialChar, Minor.ICreateTime, "creatim"), + new KeyStruct(Major.SpecialChar, Minor.IRevisionTime, "revtim"), + new KeyStruct(Major.SpecialChar, Minor.IPrintTime, "printim"), + new KeyStruct(Major.SpecialChar, Minor.IBackupTime, "buptim"), + new KeyStruct(Major.SpecialChar, Minor.IEditTime, "edmins"), + new KeyStruct(Major.SpecialChar, Minor.IYear, "yr"), + new KeyStruct(Major.SpecialChar, Minor.IMonth, "mo"), + new KeyStruct(Major.SpecialChar, Minor.IDay, "dy"), + new KeyStruct(Major.SpecialChar, Minor.IHour, "hr"), + new KeyStruct(Major.SpecialChar, Minor.IMinute, "min"), + new KeyStruct(Major.SpecialChar, Minor.ISecond, "sec"), + new KeyStruct(Major.SpecialChar, Minor.INPages, "nofpages"), + new KeyStruct(Major.SpecialChar, Minor.INWords, "nofwords"), + new KeyStruct(Major.SpecialChar, Minor.INChars, "nofchars"), + new KeyStruct(Major.SpecialChar, Minor.IIntID, "id"), + new KeyStruct(Major.SpecialChar, Minor.CurHeadDate, "chdate"), + new KeyStruct(Major.SpecialChar, Minor.CurHeadDateLong, "chdpl"), + new KeyStruct(Major.SpecialChar, Minor.CurHeadDateAbbrev, "chdpa"), + new KeyStruct(Major.SpecialChar, Minor.CurHeadTime, "chtime"), + new KeyStruct(Major.SpecialChar, Minor.CurHeadPage, "chpgn"), + new KeyStruct(Major.SpecialChar, Minor.SectNum, "sectnum"), + new KeyStruct(Major.SpecialChar, Minor.CurFNote, "chftn"), + new KeyStruct(Major.SpecialChar, Minor.CurAnnotRef, "chatn"), + new KeyStruct(Major.SpecialChar, Minor.FNoteSep, "chftnsep"), + new KeyStruct(Major.SpecialChar, Minor.FNoteCont, "chftnsepc"), + new KeyStruct(Major.SpecialChar, Minor.Cell, "cell"), + new KeyStruct(Major.SpecialChar, Minor.Row, "row"), + new KeyStruct(Major.SpecialChar, Minor.Par, "par"), + new KeyStruct(Major.SpecialChar, Minor.Par, "\n"), + new KeyStruct(Major.SpecialChar, Minor.Par, "\r"), + new KeyStruct(Major.SpecialChar, Minor.Sect, "sect"), + new KeyStruct(Major.SpecialChar, Minor.Page, "page"), + new KeyStruct(Major.SpecialChar, Minor.Column, "column"), + new KeyStruct(Major.SpecialChar, Minor.Line, "line"), + new KeyStruct(Major.SpecialChar, Minor.SoftPage, "softpage"), + new KeyStruct(Major.SpecialChar, Minor.SoftColumn, "softcol"), + new KeyStruct(Major.SpecialChar, Minor.SoftLine, "softline"), + new KeyStruct(Major.SpecialChar, Minor.SoftLineHt, "softlheight"), + new KeyStruct(Major.SpecialChar, Minor.Tab, "tab"), + new KeyStruct(Major.SpecialChar, Minor.EmDash, "emdash"), + new KeyStruct(Major.SpecialChar, Minor.EnDash, "endash"), + new KeyStruct(Major.SpecialChar, Minor.EmSpace, "emspace"), + new KeyStruct(Major.SpecialChar, Minor.EnSpace, "enspace"), + new KeyStruct(Major.SpecialChar, Minor.Bullet, "bullet"), + new KeyStruct(Major.SpecialChar, Minor.LQuote, "lquote"), + new KeyStruct(Major.SpecialChar, Minor.RQuote, "rquote"), + new KeyStruct(Major.SpecialChar, Minor.LDblQuote, "ldblquote"), + new KeyStruct(Major.SpecialChar, Minor.RDblQuote, "rdblquote"), + new KeyStruct(Major.SpecialChar, Minor.Formula, "|"), + new KeyStruct(Major.SpecialChar, Minor.NoBrkSpace, "~"), + new KeyStruct(Major.SpecialChar, Minor.NoReqHyphen, "-"), + new KeyStruct(Major.SpecialChar, Minor.NoBrkHyphen, "_"), + new KeyStruct(Major.SpecialChar, Minor.LTRMark, "ltrmark"), + new KeyStruct(Major.SpecialChar, Minor.RTLMark, "rtlmark"), + new KeyStruct(Major.SpecialChar, Minor.NoWidthJoiner, "zwj"), + new KeyStruct(Major.SpecialChar, Minor.NoWidthNonJoiner, "zwnj"), + new KeyStruct(Major.SpecialChar, Minor.CurHeadPict, "chpict"), + new KeyStruct(Major.CharAttr, Minor.Plain, "plain"), + new KeyStruct(Major.CharAttr, Minor.Bold, "b"), + new KeyStruct(Major.CharAttr, Minor.AllCaps, "caps"), + new KeyStruct(Major.CharAttr, Minor.Deleted, "deleted"), + new KeyStruct(Major.CharAttr, Minor.SubScript, "dn"), + new KeyStruct(Major.CharAttr, Minor.SubScrShrink, "sub"), + new KeyStruct(Major.CharAttr, Minor.NoSuperSub, "nosupersub"), + new KeyStruct(Major.CharAttr, Minor.Expand, "expnd"), + new KeyStruct(Major.CharAttr, Minor.ExpandTwips, "expndtw"), + new KeyStruct(Major.CharAttr, Minor.Kerning, "kerning"), + new KeyStruct(Major.CharAttr, Minor.FontNum, "f"), + new KeyStruct(Major.CharAttr, Minor.FontSize, "fs"), + new KeyStruct(Major.CharAttr, Minor.Italic, "i"), + new KeyStruct(Major.CharAttr, Minor.Outline, "outl"), + new KeyStruct(Major.CharAttr, Minor.Revised, "revised"), + new KeyStruct(Major.CharAttr, Minor.RevAuthor, "revauth"), + new KeyStruct(Major.CharAttr, Minor.RevDTTM, "revdttm"), + new KeyStruct(Major.CharAttr, Minor.SmallCaps, "scaps"), + new KeyStruct(Major.CharAttr, Minor.Shadow, "shad"), + new KeyStruct(Major.CharAttr, Minor.StrikeThru, "strike"), + new KeyStruct(Major.CharAttr, Minor.Underline, "ul"), + new KeyStruct(Major.CharAttr, Minor.DotUnderline, "uld"), + new KeyStruct(Major.CharAttr, Minor.DbUnderline, "uldb"), + new KeyStruct(Major.CharAttr, Minor.NoUnderline, "ulnone"), + new KeyStruct(Major.CharAttr, Minor.WordUnderline, "ulw"), + new KeyStruct(Major.CharAttr, Minor.SuperScript, "up"), + new KeyStruct(Major.CharAttr, Minor.SuperScrShrink, "super"), + new KeyStruct(Major.CharAttr, Minor.Invisible, "v"), + new KeyStruct(Major.CharAttr, Minor.ForeColor, "cf"), + new KeyStruct(Major.CharAttr, Minor.BackColor, "cb"), + new KeyStruct(Major.CharAttr, Minor.RTLChar, "rtlch"), + new KeyStruct(Major.CharAttr, Minor.LTRChar, "ltrch"), + new KeyStruct(Major.CharAttr, Minor.CharStyleNum, "cs"), + new KeyStruct(Major.CharAttr, Minor.CharCharSet, "cchs"), + new KeyStruct(Major.CharAttr, Minor.Language, "lang"), + new KeyStruct(Major.CharAttr, Minor.Gray, "gray"), + new KeyStruct(Major.ParAttr, Minor.ParDef, "pard"), + new KeyStruct(Major.ParAttr, Minor.StyleNum, "s"), + new KeyStruct(Major.ParAttr, Minor.Hyphenate, "hyphpar"), + new KeyStruct(Major.ParAttr, Minor.InTable, "intbl"), + new KeyStruct(Major.ParAttr, Minor.Keep, "keep"), + new KeyStruct(Major.ParAttr, Minor.NoWidowControl, "nowidctlpar"), + new KeyStruct(Major.ParAttr, Minor.KeepNext, "keepn"), + new KeyStruct(Major.ParAttr, Minor.OutlineLevel, "level"), + new KeyStruct(Major.ParAttr, Minor.NoLineNum, "noline"), + new KeyStruct(Major.ParAttr, Minor.PBBefore, "pagebb"), + new KeyStruct(Major.ParAttr, Minor.SideBySide, "sbys"), + new KeyStruct(Major.ParAttr, Minor.QuadLeft, "ql"), + new KeyStruct(Major.ParAttr, Minor.QuadRight, "qr"), + new KeyStruct(Major.ParAttr, Minor.QuadJust, "qj"), + new KeyStruct(Major.ParAttr, Minor.QuadCenter, "qc"), + new KeyStruct(Major.ParAttr, Minor.FirstIndent, "fi"), + new KeyStruct(Major.ParAttr, Minor.LeftIndent, "li"), + new KeyStruct(Major.ParAttr, Minor.RightIndent, "ri"), + new KeyStruct(Major.ParAttr, Minor.SpaceBefore, "sb"), + new KeyStruct(Major.ParAttr, Minor.SpaceAfter, "sa"), + new KeyStruct(Major.ParAttr, Minor.SpaceBetween, "sl"), + new KeyStruct(Major.ParAttr, Minor.SpaceMultiply, "slmult"), + new KeyStruct(Major.ParAttr, Minor.SubDocument, "subdocument"), + new KeyStruct(Major.ParAttr, Minor.RTLPar, "rtlpar"), + new KeyStruct(Major.ParAttr, Minor.LTRPar, "ltrpar"), + new KeyStruct(Major.ParAttr, Minor.TabPos, "tx"), + new KeyStruct(Major.ParAttr, Minor.TabLeft, "tql"), + new KeyStruct(Major.ParAttr, Minor.TabRight, "tqr"), + new KeyStruct(Major.ParAttr, Minor.TabCenter, "tqc"), + new KeyStruct(Major.ParAttr, Minor.TabDecimal, "tqdec"), + new KeyStruct(Major.ParAttr, Minor.TabBar, "tb"), + new KeyStruct(Major.ParAttr, Minor.LeaderDot, "tldot"), + new KeyStruct(Major.ParAttr, Minor.LeaderHyphen, "tlhyph"), + new KeyStruct(Major.ParAttr, Minor.LeaderUnder, "tlul"), + new KeyStruct(Major.ParAttr, Minor.LeaderThick, "tlth"), + new KeyStruct(Major.ParAttr, Minor.LeaderEqual, "tleq"), + new KeyStruct(Major.ParAttr, Minor.ParLevel, "pnlvl"), + new KeyStruct(Major.ParAttr, Minor.ParBullet, "pnlvlblt"), + new KeyStruct(Major.ParAttr, Minor.ParSimple, "pnlvlbody"), + new KeyStruct(Major.ParAttr, Minor.ParNumCont, "pnlvlcont"), + new KeyStruct(Major.ParAttr, Minor.ParNumOnce, "pnnumonce"), + new KeyStruct(Major.ParAttr, Minor.ParNumAcross, "pnacross"), + new KeyStruct(Major.ParAttr, Minor.ParHangIndent, "pnhang"), + new KeyStruct(Major.ParAttr, Minor.ParNumRestart, "pnrestart"), + new KeyStruct(Major.ParAttr, Minor.ParNumCardinal, "pncard"), + new KeyStruct(Major.ParAttr, Minor.ParNumDecimal, "pndec"), + new KeyStruct(Major.ParAttr, Minor.ParNumULetter, "pnucltr"), + new KeyStruct(Major.ParAttr, Minor.ParNumURoman, "pnucrm"), + new KeyStruct(Major.ParAttr, Minor.ParNumLLetter, "pnlcltr"), + new KeyStruct(Major.ParAttr, Minor.ParNumLRoman, "pnlcrm"), + new KeyStruct(Major.ParAttr, Minor.ParNumOrdinal, "pnord"), + new KeyStruct(Major.ParAttr, Minor.ParNumOrdinalText, "pnordt"), + new KeyStruct(Major.ParAttr, Minor.ParNumBold, "pnb"), + new KeyStruct(Major.ParAttr, Minor.ParNumItalic, "pni"), + new KeyStruct(Major.ParAttr, Minor.ParNumAllCaps, "pncaps"), + new KeyStruct(Major.ParAttr, Minor.ParNumSmallCaps, "pnscaps"), + new KeyStruct(Major.ParAttr, Minor.ParNumUnder, "pnul"), + new KeyStruct(Major.ParAttr, Minor.ParNumDotUnder, "pnuld"), + new KeyStruct(Major.ParAttr, Minor.ParNumDbUnder, "pnuldb"), + new KeyStruct(Major.ParAttr, Minor.ParNumNoUnder, "pnulnone"), + new KeyStruct(Major.ParAttr, Minor.ParNumWordUnder, "pnulw"), + new KeyStruct(Major.ParAttr, Minor.ParNumStrikethru, "pnstrike"), + new KeyStruct(Major.ParAttr, Minor.ParNumForeColor, "pncf"), + new KeyStruct(Major.ParAttr, Minor.ParNumFont, "pnf"), + new KeyStruct(Major.ParAttr, Minor.ParNumFontSize, "pnfs"), + new KeyStruct(Major.ParAttr, Minor.ParNumIndent, "pnindent"), + new KeyStruct(Major.ParAttr, Minor.ParNumSpacing, "pnsp"), + new KeyStruct(Major.ParAttr, Minor.ParNumInclPrev, "pnprev"), + new KeyStruct(Major.ParAttr, Minor.ParNumCenter, "pnqc"), + new KeyStruct(Major.ParAttr, Minor.ParNumLeft, "pnql"), + new KeyStruct(Major.ParAttr, Minor.ParNumRight, "pnqr"), + new KeyStruct(Major.ParAttr, Minor.ParNumStartAt, "pnstart"), + new KeyStruct(Major.ParAttr, Minor.BorderTop, "brdrt"), + new KeyStruct(Major.ParAttr, Minor.BorderBottom, "brdrb"), + new KeyStruct(Major.ParAttr, Minor.BorderLeft, "brdrl"), + new KeyStruct(Major.ParAttr, Minor.BorderRight, "brdrr"), + new KeyStruct(Major.ParAttr, Minor.BorderBetween, "brdrbtw"), + new KeyStruct(Major.ParAttr, Minor.BorderBar, "brdrbar"), + new KeyStruct(Major.ParAttr, Minor.BorderBox, "box"), + new KeyStruct(Major.ParAttr, Minor.BorderSingle, "brdrs"), + new KeyStruct(Major.ParAttr, Minor.BorderThick, "brdrth"), + new KeyStruct(Major.ParAttr, Minor.BorderShadow, "brdrsh"), + new KeyStruct(Major.ParAttr, Minor.BorderDouble, "brdrdb"), + new KeyStruct(Major.ParAttr, Minor.BorderDot, "brdrdot"), + new KeyStruct(Major.ParAttr, Minor.BorderDot, "brdrdash"), + new KeyStruct(Major.ParAttr, Minor.BorderHair, "brdrhair"), + new KeyStruct(Major.ParAttr, Minor.BorderWidth, "brdrw"), + new KeyStruct(Major.ParAttr, Minor.BorderColor, "brdrcf"), + new KeyStruct(Major.ParAttr, Minor.BorderSpace, "brsp"), + new KeyStruct(Major.ParAttr, Minor.Shading, "shading"), + new KeyStruct(Major.ParAttr, Minor.BgPatH, "bghoriz"), + new KeyStruct(Major.ParAttr, Minor.BgPatV, "bgvert"), + new KeyStruct(Major.ParAttr, Minor.FwdDiagBgPat, "bgfdiag"), + new KeyStruct(Major.ParAttr, Minor.BwdDiagBgPat, "bgbdiag"), + new KeyStruct(Major.ParAttr, Minor.HatchBgPat, "bgcross"), + new KeyStruct(Major.ParAttr, Minor.DiagHatchBgPat, "bgdcross"), + new KeyStruct(Major.ParAttr, Minor.DarkBgPatH, "bgdkhoriz"), + new KeyStruct(Major.ParAttr, Minor.DarkBgPatV, "bgdkvert"), + new KeyStruct(Major.ParAttr, Minor.FwdDarkBgPat, "bgdkfdiag"), + new KeyStruct(Major.ParAttr, Minor.BwdDarkBgPat, "bgdkbdiag"), + new KeyStruct(Major.ParAttr, Minor.DarkHatchBgPat, "bgdkcross"), + new KeyStruct(Major.ParAttr, Minor.DarkDiagHatchBgPat, "bgdkdcross"), + new KeyStruct(Major.ParAttr, Minor.BgPatLineColor, "cfpat"), + new KeyStruct(Major.ParAttr, Minor.BgPatColor, "cbpat"), + new KeyStruct(Major.SectAttr, Minor.SectDef, "sectd"), + new KeyStruct(Major.SectAttr, Minor.ENoteHere, "endnhere"), + new KeyStruct(Major.SectAttr, Minor.PrtBinFirst, "binfsxn"), + new KeyStruct(Major.SectAttr, Minor.PrtBin, "binsxn"), + new KeyStruct(Major.SectAttr, Minor.SectStyleNum, "ds"), + new KeyStruct(Major.SectAttr, Minor.NoBreak, "sbknone"), + new KeyStruct(Major.SectAttr, Minor.ColBreak, "sbkcol"), + new KeyStruct(Major.SectAttr, Minor.PageBreak, "sbkpage"), + new KeyStruct(Major.SectAttr, Minor.EvenBreak, "sbkeven"), + new KeyStruct(Major.SectAttr, Minor.OddBreak, "sbkodd"), + new KeyStruct(Major.SectAttr, Minor.Columns, "cols"), + new KeyStruct(Major.SectAttr, Minor.ColumnSpace, "colsx"), + new KeyStruct(Major.SectAttr, Minor.ColumnNumber, "colno"), + new KeyStruct(Major.SectAttr, Minor.ColumnSpRight, "colsr"), + new KeyStruct(Major.SectAttr, Minor.ColumnWidth, "colw"), + new KeyStruct(Major.SectAttr, Minor.ColumnLine, "linebetcol"), + new KeyStruct(Major.SectAttr, Minor.LineModulus, "linemod"), + new KeyStruct(Major.SectAttr, Minor.LineDist, "linex"), + new KeyStruct(Major.SectAttr, Minor.LineStarts, "linestarts"), + new KeyStruct(Major.SectAttr, Minor.LineRestart, "linerestart"), + new KeyStruct(Major.SectAttr, Minor.LineRestartPg, "lineppage"), + new KeyStruct(Major.SectAttr, Minor.LineCont, "linecont"), + new KeyStruct(Major.SectAttr, Minor.SectPageWid, "pgwsxn"), + new KeyStruct(Major.SectAttr, Minor.SectPageHt, "pghsxn"), + new KeyStruct(Major.SectAttr, Minor.SectMarginLeft, "marglsxn"), + new KeyStruct(Major.SectAttr, Minor.SectMarginRight, "margrsxn"), + new KeyStruct(Major.SectAttr, Minor.SectMarginTop, "margtsxn"), + new KeyStruct(Major.SectAttr, Minor.SectMarginBottom, "margbsxn"), + new KeyStruct(Major.SectAttr, Minor.SectMarginGutter, "guttersxn"), + new KeyStruct(Major.SectAttr, Minor.SectLandscape, "lndscpsxn"), + new KeyStruct(Major.SectAttr, Minor.TitleSpecial, "titlepg"), + new KeyStruct(Major.SectAttr, Minor.HeaderY, "headery"), + new KeyStruct(Major.SectAttr, Minor.FooterY, "footery"), + new KeyStruct(Major.SectAttr, Minor.PageStarts, "pgnstarts"), + new KeyStruct(Major.SectAttr, Minor.PageCont, "pgncont"), + new KeyStruct(Major.SectAttr, Minor.PageRestart, "pgnrestart"), + new KeyStruct(Major.SectAttr, Minor.PageNumRight, "pgnx"), + new KeyStruct(Major.SectAttr, Minor.PageNumTop, "pgny"), + new KeyStruct(Major.SectAttr, Minor.PageDecimal, "pgndec"), + new KeyStruct(Major.SectAttr, Minor.PageURoman, "pgnucrm"), + new KeyStruct(Major.SectAttr, Minor.PageLRoman, "pgnlcrm"), + new KeyStruct(Major.SectAttr, Minor.PageULetter, "pgnucltr"), + new KeyStruct(Major.SectAttr, Minor.PageLLetter, "pgnlcltr"), + new KeyStruct(Major.SectAttr, Minor.PageNumHyphSep, "pgnhnsh"), + new KeyStruct(Major.SectAttr, Minor.PageNumSpaceSep, "pgnhnsp"), + new KeyStruct(Major.SectAttr, Minor.PageNumColonSep, "pgnhnsc"), + new KeyStruct(Major.SectAttr, Minor.PageNumEmdashSep, "pgnhnsm"), + new KeyStruct(Major.SectAttr, Minor.PageNumEndashSep, "pgnhnsn"), + new KeyStruct(Major.SectAttr, Minor.TopVAlign, "vertalt"), + new KeyStruct(Major.SectAttr, Minor.BottomVAlign, "vertalb"), + new KeyStruct(Major.SectAttr, Minor.CenterVAlign, "vertalc"), + new KeyStruct(Major.SectAttr, Minor.JustVAlign, "vertalj"), + new KeyStruct(Major.SectAttr, Minor.RTLSect, "rtlsect"), + new KeyStruct(Major.SectAttr, Minor.LTRSect, "ltrsect"), + new KeyStruct(Major.DocAttr, Minor.DefTab, "deftab"), + new KeyStruct(Major.DocAttr, Minor.HyphHotZone, "hyphhotz"), + new KeyStruct(Major.DocAttr, Minor.HyphConsecLines, "hyphconsec"), + new KeyStruct(Major.DocAttr, Minor.HyphCaps, "hyphcaps"), + new KeyStruct(Major.DocAttr, Minor.HyphAuto, "hyphauto"), + new KeyStruct(Major.DocAttr, Minor.LineStart, "linestart"), + new KeyStruct(Major.DocAttr, Minor.FracWidth, "fracwidth"), + new KeyStruct(Major.DocAttr, Minor.MakeBackup, "makeback"), + new KeyStruct(Major.DocAttr, Minor.MakeBackup, "makebackup"), + new KeyStruct(Major.DocAttr, Minor.RTFDefault, "defformat"), + new KeyStruct(Major.DocAttr, Minor.PSOverlay, "psover"), + new KeyStruct(Major.DocAttr, Minor.DocTemplate, "doctemp"), + new KeyStruct(Major.DocAttr, Minor.DefLanguage, "deflang"), + new KeyStruct(Major.DocAttr, Minor.FENoteType, "fet"), + new KeyStruct(Major.DocAttr, Minor.FNoteEndSect, "endnotes"), + new KeyStruct(Major.DocAttr, Minor.FNoteEndDoc, "enddoc"), + new KeyStruct(Major.DocAttr, Minor.FNoteText, "ftntj"), + new KeyStruct(Major.DocAttr, Minor.FNoteBottom, "ftnbj"), + new KeyStruct(Major.DocAttr, Minor.ENoteEndSect, "aendnotes"), + new KeyStruct(Major.DocAttr, Minor.ENoteEndDoc, "aenddoc"), + new KeyStruct(Major.DocAttr, Minor.ENoteText, "aftntj"), + new KeyStruct(Major.DocAttr, Minor.ENoteBottom, "aftnbj"), + new KeyStruct(Major.DocAttr, Minor.FNoteStart, "ftnstart"), + new KeyStruct(Major.DocAttr, Minor.ENoteStart, "aftnstart"), + new KeyStruct(Major.DocAttr, Minor.FNoteRestartPage, "ftnrstpg"), + new KeyStruct(Major.DocAttr, Minor.FNoteRestart, "ftnrestart"), + new KeyStruct(Major.DocAttr, Minor.FNoteRestartCont, "ftnrstcont"), + new KeyStruct(Major.DocAttr, Minor.ENoteRestart, "aftnrestart"), + new KeyStruct(Major.DocAttr, Minor.ENoteRestartCont, "aftnrstcont"), + new KeyStruct(Major.DocAttr, Minor.FNoteNumArabic, "ftnnar"), + new KeyStruct(Major.DocAttr, Minor.FNoteNumLLetter, "ftnnalc"), + new KeyStruct(Major.DocAttr, Minor.FNoteNumULetter, "ftnnauc"), + new KeyStruct(Major.DocAttr, Minor.FNoteNumLRoman, "ftnnrlc"), + new KeyStruct(Major.DocAttr, Minor.FNoteNumURoman, "ftnnruc"), + new KeyStruct(Major.DocAttr, Minor.FNoteNumChicago, "ftnnchi"), + new KeyStruct(Major.DocAttr, Minor.ENoteNumArabic, "aftnnar"), + new KeyStruct(Major.DocAttr, Minor.ENoteNumLLetter, "aftnnalc"), + new KeyStruct(Major.DocAttr, Minor.ENoteNumULetter, "aftnnauc"), + new KeyStruct(Major.DocAttr, Minor.ENoteNumLRoman, "aftnnrlc"), + new KeyStruct(Major.DocAttr, Minor.ENoteNumURoman, "aftnnruc"), + new KeyStruct(Major.DocAttr, Minor.ENoteNumChicago, "aftnnchi"), + new KeyStruct(Major.DocAttr, Minor.PaperWidth, "paperw"), + new KeyStruct(Major.DocAttr, Minor.PaperHeight, "paperh"), + new KeyStruct(Major.DocAttr, Minor.PaperSize, "psz"), + new KeyStruct(Major.DocAttr, Minor.LeftMargin, "margl"), + new KeyStruct(Major.DocAttr, Minor.RightMargin, "margr"), + new KeyStruct(Major.DocAttr, Minor.TopMargin, "margt"), + new KeyStruct(Major.DocAttr, Minor.BottomMargin, "margb"), + new KeyStruct(Major.DocAttr, Minor.FacingPage, "facingp"), + new KeyStruct(Major.DocAttr, Minor.GutterWid, "gutter"), + new KeyStruct(Major.DocAttr, Minor.MirrorMargin, "margmirror"), + new KeyStruct(Major.DocAttr, Minor.Landscape, "landscape"), + new KeyStruct(Major.DocAttr, Minor.PageStart, "pgnstart"), + new KeyStruct(Major.DocAttr, Minor.WidowCtrl, "widowctrl"), + new KeyStruct(Major.DocAttr, Minor.LinkStyles, "linkstyles"), + new KeyStruct(Major.DocAttr, Minor.NoAutoTabIndent, "notabind"), + new KeyStruct(Major.DocAttr, Minor.WrapSpaces, "wraptrsp"), + new KeyStruct(Major.DocAttr, Minor.PrintColorsBlack, "prcolbl"), + new KeyStruct(Major.DocAttr, Minor.NoExtraSpaceRL, "noextrasprl"), + new KeyStruct(Major.DocAttr, Minor.NoColumnBalance, "nocolbal"), + new KeyStruct(Major.DocAttr, Minor.CvtMailMergeQuote, "cvmme"), + new KeyStruct(Major.DocAttr, Minor.SuppressTopSpace, "sprstsp"), + new KeyStruct(Major.DocAttr, Minor.SuppressPreParSpace, "sprsspbf"), + new KeyStruct(Major.DocAttr, Minor.CombineTblBorders, "otblrul"), + new KeyStruct(Major.DocAttr, Minor.TranspMetafiles, "transmf"), + new KeyStruct(Major.DocAttr, Minor.SwapBorders, "swpbdr"), + new KeyStruct(Major.DocAttr, Minor.ShowHardBreaks, "brkfrm"), + new KeyStruct(Major.DocAttr, Minor.FormProtected, "formprot"), + new KeyStruct(Major.DocAttr, Minor.AllProtected, "allprot"), + new KeyStruct(Major.DocAttr, Minor.FormShading, "formshade"), + new KeyStruct(Major.DocAttr, Minor.FormDisplay, "formdisp"), + new KeyStruct(Major.DocAttr, Minor.PrintData, "printdata"), + new KeyStruct(Major.DocAttr, Minor.RevProtected, "revprot"), + new KeyStruct(Major.DocAttr, Minor.Revisions, "revisions"), + new KeyStruct(Major.DocAttr, Minor.RevDisplay, "revprop"), + new KeyStruct(Major.DocAttr, Minor.RevBar, "revbar"), + new KeyStruct(Major.DocAttr, Minor.AnnotProtected, "annotprot"), + new KeyStruct(Major.DocAttr, Minor.RTLDoc, "rtldoc"), + new KeyStruct(Major.DocAttr, Minor.LTRDoc, "ltrdoc"), + new KeyStruct(Major.StyleAttr, Minor.Additive, "additive"), + new KeyStruct(Major.StyleAttr, Minor.BasedOn, "sbasedon"), + new KeyStruct(Major.StyleAttr, Minor.Next, "snext"), + new KeyStruct(Major.PictAttr, Minor.MacQD, "macpict"), + new KeyStruct(Major.PictAttr, Minor.PMMetafile, "pmmetafile"), + new KeyStruct(Major.PictAttr, Minor.WinMetafile, "wmetafile"), + new KeyStruct(Major.PictAttr, Minor.DevIndBitmap, "dibitmap"), + new KeyStruct(Major.PictAttr, Minor.WinBitmap, "wbitmap"), + new KeyStruct(Major.PictAttr, Minor.PngBlip, "pngblip"), + new KeyStruct(Major.PictAttr, Minor.PixelBits, "wbmbitspixel"), + new KeyStruct(Major.PictAttr, Minor.BitmapPlanes, "wbmplanes"), + new KeyStruct(Major.PictAttr, Minor.BitmapWid, "wbmwidthbytes"), + new KeyStruct(Major.PictAttr, Minor.PicWid, "picw"), + new KeyStruct(Major.PictAttr, Minor.PicHt, "pich"), + new KeyStruct(Major.PictAttr, Minor.PicGoalWid, "picwgoal"), + new KeyStruct(Major.PictAttr, Minor.PicGoalHt, "pichgoal"), + new KeyStruct(Major.PictAttr, Minor.PicGoalWid, "picwGoal"), + new KeyStruct(Major.PictAttr, Minor.PicGoalHt, "pichGoal"), + new KeyStruct(Major.PictAttr, Minor.PicScaleX, "picscalex"), + new KeyStruct(Major.PictAttr, Minor.PicScaleY, "picscaley"), + new KeyStruct(Major.PictAttr, Minor.PicScaled, "picscaled"), + new KeyStruct(Major.PictAttr, Minor.PicCropTop, "piccropt"), + new KeyStruct(Major.PictAttr, Minor.PicCropBottom, "piccropb"), + new KeyStruct(Major.PictAttr, Minor.PicCropLeft, "piccropl"), + new KeyStruct(Major.PictAttr, Minor.PicCropRight, "piccropr"), + new KeyStruct(Major.PictAttr, Minor.PicMFHasBitmap, "picbmp"), + new KeyStruct(Major.PictAttr, Minor.PicMFBitsPerPixel, "picbpp"), + new KeyStruct(Major.PictAttr, Minor.PicBinary, "bin"), + new KeyStruct(Major.NeXTGrAttr, Minor.NeXTGWidth, "width"), + new KeyStruct(Major.NeXTGrAttr, Minor.NeXTGHeight, "height"), + new KeyStruct(Major.Destination, Minor.OptDest, "*"), + new KeyStruct(Major.Destination, Minor.FontTbl, "fonttbl"), + new KeyStruct(Major.Destination, Minor.FontAltName, "falt"), + new KeyStruct(Major.Destination, Minor.EmbeddedFont, "fonteb"), + new KeyStruct(Major.Destination, Minor.FontFile, "fontfile"), + new KeyStruct(Major.Destination, Minor.FileTbl, "filetbl"), + new KeyStruct(Major.Destination, Minor.FileInfo, "file"), + new KeyStruct(Major.Destination, Minor.ColorTbl, "colortbl"), + new KeyStruct(Major.Destination, Minor.StyleSheet, "stylesheet"), + new KeyStruct(Major.Destination, Minor.KeyCode, "keycode"), + new KeyStruct(Major.Destination, Minor.RevisionTbl, "revtbl"), + new KeyStruct(Major.Destination, Minor.Info, "info"), + new KeyStruct(Major.Destination, Minor.ITitle, "title"), + new KeyStruct(Major.Destination, Minor.ISubject, "subject"), + new KeyStruct(Major.Destination, Minor.IAuthor, "author"), + new KeyStruct(Major.Destination, Minor.IOperator, "operator"), + new KeyStruct(Major.Destination, Minor.IKeywords, "keywords"), + new KeyStruct(Major.Destination, Minor.IComment, "comment"), + new KeyStruct(Major.Destination, Minor.IVersion, "version"), + new KeyStruct(Major.Destination, Minor.IDoccomm, "doccomm"), + new KeyStruct(Major.Destination, Minor.IVerscomm, "verscomm"), + new KeyStruct(Major.Destination, Minor.NextFile, "nextfile"), + new KeyStruct(Major.Destination, Minor.Template, "template"), + new KeyStruct(Major.Destination, Minor.FNSep, "ftnsep"), + new KeyStruct(Major.Destination, Minor.FNContSep, "ftnsepc"), + new KeyStruct(Major.Destination, Minor.FNContNotice, "ftncn"), + new KeyStruct(Major.Destination, Minor.ENSep, "aftnsep"), + new KeyStruct(Major.Destination, Minor.ENContSep, "aftnsepc"), + new KeyStruct(Major.Destination, Minor.ENContNotice, "aftncn"), + new KeyStruct(Major.Destination, Minor.PageNumLevel, "pgnhn"), + new KeyStruct(Major.Destination, Minor.ParNumLevelStyle, "pnseclvl"), + new KeyStruct(Major.Destination, Minor.Header, "header"), + new KeyStruct(Major.Destination, Minor.Footer, "footer"), + new KeyStruct(Major.Destination, Minor.HeaderLeft, "headerl"), + new KeyStruct(Major.Destination, Minor.HeaderRight, "headerr"), + new KeyStruct(Major.Destination, Minor.HeaderFirst, "headerf"), + new KeyStruct(Major.Destination, Minor.FooterLeft, "footerl"), + new KeyStruct(Major.Destination, Minor.FooterRight, "footerr"), + new KeyStruct(Major.Destination, Minor.FooterFirst, "footerf"), + new KeyStruct(Major.Destination, Minor.ParNumText, "pntext"), + new KeyStruct(Major.Destination, Minor.ParNumbering, "pn"), + new KeyStruct(Major.Destination, Minor.ParNumTextAfter, "pntexta"), + new KeyStruct(Major.Destination, Minor.ParNumTextBefore, "pntextb"), + new KeyStruct(Major.Destination, Minor.BookmarkStart, "bkmkstart"), + new KeyStruct(Major.Destination, Minor.BookmarkEnd, "bkmkend"), + new KeyStruct(Major.Destination, Minor.Pict, "pict"), + new KeyStruct(Major.Destination, Minor.Object, "object"), + new KeyStruct(Major.Destination, Minor.ObjClass, "objclass"), + new KeyStruct(Major.Destination, Minor.ObjName, "objname"), + new KeyStruct(Major.ObjAttr, Minor.ObjTime, "objtime"), + new KeyStruct(Major.Destination, Minor.ObjData, "objdata"), + new KeyStruct(Major.Destination, Minor.ObjAlias, "objalias"), + new KeyStruct(Major.Destination, Minor.ObjSection, "objsect"), + new KeyStruct(Major.Destination, Minor.ObjItem, "objitem"), + new KeyStruct(Major.Destination, Minor.ObjTopic, "objtopic"), + new KeyStruct(Major.Destination, Minor.ObjResult, "result"), + new KeyStruct(Major.Destination, Minor.DrawObject, "do"), + new KeyStruct(Major.Destination, Minor.Footnote, "footnote"), + new KeyStruct(Major.Destination, Minor.AnnotRefStart, "atrfstart"), + new KeyStruct(Major.Destination, Minor.AnnotRefEnd, "atrfend"), + new KeyStruct(Major.Destination, Minor.AnnotID, "atnid"), + new KeyStruct(Major.Destination, Minor.AnnotAuthor, "atnauthor"), + new KeyStruct(Major.Destination, Minor.Annotation, "annotation"), + new KeyStruct(Major.Destination, Minor.AnnotRef, "atnref"), + new KeyStruct(Major.Destination, Minor.AnnotTime, "atntime"), + new KeyStruct(Major.Destination, Minor.AnnotIcon, "atnicn"), + new KeyStruct(Major.Destination, Minor.Field, "field"), + new KeyStruct(Major.Destination, Minor.FieldInst, "fldinst"), + new KeyStruct(Major.Destination, Minor.FieldResult, "fldrslt"), + new KeyStruct(Major.Destination, Minor.DataField, "datafield"), + new KeyStruct(Major.Destination, Minor.Index, "xe"), + new KeyStruct(Major.Destination, Minor.IndexText, "txe"), + new KeyStruct(Major.Destination, Minor.IndexRange, "rxe"), + new KeyStruct(Major.Destination, Minor.TOC, "tc"), + new KeyStruct(Major.Destination, Minor.NeXTGraphic, "NeXTGraphic"), + new KeyStruct(Major.FontFamily, Minor.FFNil, "fnil"), + new KeyStruct(Major.FontFamily, Minor.FFRoman, "froman"), + new KeyStruct(Major.FontFamily, Minor.FFSwiss, "fswiss"), + new KeyStruct(Major.FontFamily, Minor.FFModern, "fmodern"), + new KeyStruct(Major.FontFamily, Minor.FFScript, "fscript"), + new KeyStruct(Major.FontFamily, Minor.FFDecor, "fdecor"), + new KeyStruct(Major.FontFamily, Minor.FFTech, "ftech"), + new KeyStruct(Major.FontFamily, Minor.FFBidirectional, "fbidi"), + new KeyStruct(Major.FontAttr, Minor.FontCharSet, "fcharset"), + new KeyStruct(Major.FontAttr, Minor.FontPitch, "fprq"), + new KeyStruct(Major.FontAttr, Minor.FontCodePage, "cpg"), + new KeyStruct(Major.FontAttr, Minor.FTypeNil, "ftnil"), + new KeyStruct(Major.FontAttr, Minor.FTypeTrueType, "fttruetype"), + new KeyStruct(Major.FileAttr, Minor.FileNum, "fid"), + new KeyStruct(Major.FileAttr, Minor.FileRelPath, "frelative"), + new KeyStruct(Major.FileAttr, Minor.FileOSNum, "fosnum"), + new KeyStruct(Major.FileSource, Minor.SrcMacintosh, "fvalidmac"), + new KeyStruct(Major.FileSource, Minor.SrcDOS, "fvaliddos"), + new KeyStruct(Major.FileSource, Minor.SrcNTFS, "fvalidntfs"), + new KeyStruct(Major.FileSource, Minor.SrcHPFS, "fvalidhpfs"), + new KeyStruct(Major.FileSource, Minor.SrcNetwork, "fnetwork"), + new KeyStruct(Major.ColorName, Minor.Red, "red"), + new KeyStruct(Major.ColorName, Minor.Green, "green"), + new KeyStruct(Major.ColorName, Minor.Blue, "blue"), + new KeyStruct(Major.CharSet, Minor.MacCharSet, "mac"), + new KeyStruct(Major.CharSet, Minor.AnsiCharSet, "ansi"), + new KeyStruct(Major.CharSet, Minor.PcCharSet, "pc"), + new KeyStruct(Major.CharSet, Minor.PcaCharSet, "pca"), + new KeyStruct(Major.TblAttr, Minor.RowDef, "trowd"), + new KeyStruct(Major.TblAttr, Minor.RowGapH, "trgaph"), + new KeyStruct(Major.TblAttr, Minor.CellPos, "cellx"), + new KeyStruct(Major.TblAttr, Minor.MergeRngFirst, "clmgf"), + new KeyStruct(Major.TblAttr, Minor.MergePrevious, "clmrg"), + new KeyStruct(Major.TblAttr, Minor.RowLeft, "trql"), + new KeyStruct(Major.TblAttr, Minor.RowRight, "trqr"), + new KeyStruct(Major.TblAttr, Minor.RowCenter, "trqc"), + new KeyStruct(Major.TblAttr, Minor.RowLeftEdge, "trleft"), + new KeyStruct(Major.TblAttr, Minor.RowHt, "trrh"), + new KeyStruct(Major.TblAttr, Minor.RowHeader, "trhdr"), + new KeyStruct(Major.TblAttr, Minor.RowKeep, "trkeep"), + new KeyStruct(Major.TblAttr, Minor.RTLRow, "rtlrow"), + new KeyStruct(Major.TblAttr, Minor.LTRRow, "ltrrow"), + new KeyStruct(Major.TblAttr, Minor.RowBordTop, "trbrdrt"), + new KeyStruct(Major.TblAttr, Minor.RowBordLeft, "trbrdrl"), + new KeyStruct(Major.TblAttr, Minor.RowBordBottom, "trbrdrb"), + new KeyStruct(Major.TblAttr, Minor.RowBordRight, "trbrdrr"), + new KeyStruct(Major.TblAttr, Minor.RowBordHoriz, "trbrdrh"), + new KeyStruct(Major.TblAttr, Minor.RowBordVert, "trbrdrv"), + new KeyStruct(Major.TblAttr, Minor.CellBordBottom, "clbrdrb"), + new KeyStruct(Major.TblAttr, Minor.CellBordTop, "clbrdrt"), + new KeyStruct(Major.TblAttr, Minor.CellBordLeft, "clbrdrl"), + new KeyStruct(Major.TblAttr, Minor.CellBordRight, "clbrdrr"), + new KeyStruct(Major.TblAttr, Minor.CellShading, "clshdng"), + new KeyStruct(Major.TblAttr, Minor.CellBgPatH, "clbghoriz"), + new KeyStruct(Major.TblAttr, Minor.CellBgPatV, "clbgvert"), + new KeyStruct(Major.TblAttr, Minor.CellFwdDiagBgPat, "clbgfdiag"), + new KeyStruct(Major.TblAttr, Minor.CellBwdDiagBgPat, "clbgbdiag"), + new KeyStruct(Major.TblAttr, Minor.CellHatchBgPat, "clbgcross"), + new KeyStruct(Major.TblAttr, Minor.CellDiagHatchBgPat, "clbgdcross"), + new KeyStruct(Major.TblAttr, Minor.CellDarkBgPatH, "clbgdkhoriz"), + new KeyStruct(Major.TblAttr, Minor.CellDarkBgPatH, "clbgdkhor"), + new KeyStruct(Major.TblAttr, Minor.CellDarkBgPatV, "clbgdkvert"), + new KeyStruct(Major.TblAttr, Minor.CellFwdDarkBgPat, "clbgdkfdiag"), + new KeyStruct(Major.TblAttr, Minor.CellBwdDarkBgPat, "clbgdkbdiag"), + new KeyStruct(Major.TblAttr, Minor.CellDarkHatchBgPat, "clbgdkcross"), + new KeyStruct(Major.TblAttr, Minor.CellDarkDiagHatchBgPat, "clbgdkdcross"), + new KeyStruct(Major.TblAttr, Minor.CellBgPatLineColor, "clcfpat"), + new KeyStruct(Major.TblAttr, Minor.CellBgPatColor, "clcbpat"), + new KeyStruct(Major.FieldAttr, Minor.FieldDirty, "flddirty"), + new KeyStruct(Major.FieldAttr, Minor.FieldEdited, "fldedit"), + new KeyStruct(Major.FieldAttr, Minor.FieldLocked, "fldlock"), + new KeyStruct(Major.FieldAttr, Minor.FieldPrivate, "fldpriv"), + new KeyStruct(Major.FieldAttr, Minor.FieldAlt, "fldalt"), + new KeyStruct(Major.PosAttr, Minor.AbsWid, "absw"), + new KeyStruct(Major.PosAttr, Minor.AbsHt, "absh"), + new KeyStruct(Major.PosAttr, Minor.RPosMargH, "phmrg"), + new KeyStruct(Major.PosAttr, Minor.RPosPageH, "phpg"), + new KeyStruct(Major.PosAttr, Minor.RPosColH, "phcol"), + new KeyStruct(Major.PosAttr, Minor.PosX, "posx"), + new KeyStruct(Major.PosAttr, Minor.PosNegX, "posnegx"), + new KeyStruct(Major.PosAttr, Minor.PosXCenter, "posxc"), + new KeyStruct(Major.PosAttr, Minor.PosXInside, "posxi"), + new KeyStruct(Major.PosAttr, Minor.PosXOutSide, "posxo"), + new KeyStruct(Major.PosAttr, Minor.PosXRight, "posxr"), + new KeyStruct(Major.PosAttr, Minor.PosXLeft, "posxl"), + new KeyStruct(Major.PosAttr, Minor.RPosMargV, "pvmrg"), + new KeyStruct(Major.PosAttr, Minor.RPosPageV, "pvpg"), + new KeyStruct(Major.PosAttr, Minor.RPosParaV, "pvpara"), + new KeyStruct(Major.PosAttr, Minor.PosY, "posy"), + new KeyStruct(Major.PosAttr, Minor.PosNegY, "posnegy"), + new KeyStruct(Major.PosAttr, Minor.PosYInline, "posyil"), + new KeyStruct(Major.PosAttr, Minor.PosYTop, "posyt"), + new KeyStruct(Major.PosAttr, Minor.PosYCenter, "posyc"), + new KeyStruct(Major.PosAttr, Minor.PosYBottom, "posyb"), + new KeyStruct(Major.PosAttr, Minor.NoWrap, "nowrap"), + new KeyStruct(Major.PosAttr, Minor.DistFromTextAll, "dxfrtext"), + new KeyStruct(Major.PosAttr, Minor.DistFromTextX, "dfrmtxtx"), + new KeyStruct(Major.PosAttr, Minor.DistFromTextY, "dfrmtxty"), + new KeyStruct(Major.PosAttr, Minor.TextDistY, "dyfrtext"), + new KeyStruct(Major.PosAttr, Minor.DropCapLines, "dropcapli"), + new KeyStruct(Major.PosAttr, Minor.DropCapType, "dropcapt"), + new KeyStruct(Major.ObjAttr, Minor.ObjEmb, "objemb"), + new KeyStruct(Major.ObjAttr, Minor.ObjLink, "objlink"), + new KeyStruct(Major.ObjAttr, Minor.ObjAutoLink, "objautlink"), + new KeyStruct(Major.ObjAttr, Minor.ObjSubscriber, "objsub"), + new KeyStruct(Major.ObjAttr, Minor.ObjPublisher, "objpub"), + new KeyStruct(Major.ObjAttr, Minor.ObjICEmb, "objicemb"), + new KeyStruct(Major.ObjAttr, Minor.ObjLinkSelf, "linkself"), + new KeyStruct(Major.ObjAttr, Minor.ObjLock, "objupdate"), + new KeyStruct(Major.ObjAttr, Minor.ObjUpdate, "objlock"), + new KeyStruct(Major.ObjAttr, Minor.ObjHt, "objh"), + new KeyStruct(Major.ObjAttr, Minor.ObjWid, "objw"), + new KeyStruct(Major.ObjAttr, Minor.ObjSetSize, "objsetsize"), + new KeyStruct(Major.ObjAttr, Minor.ObjAlign, "objalign"), + new KeyStruct(Major.ObjAttr, Minor.ObjTransposeY, "objtransy"), + new KeyStruct(Major.ObjAttr, Minor.ObjCropTop, "objcropt"), + new KeyStruct(Major.ObjAttr, Minor.ObjCropBottom, "objcropb"), + new KeyStruct(Major.ObjAttr, Minor.ObjCropLeft, "objcropl"), + new KeyStruct(Major.ObjAttr, Minor.ObjCropRight, "objcropr"), + new KeyStruct(Major.ObjAttr, Minor.ObjScaleX, "objscalex"), + new KeyStruct(Major.ObjAttr, Minor.ObjScaleY, "objscaley"), + new KeyStruct(Major.ObjAttr, Minor.ObjResRTF, "rsltrtf"), + new KeyStruct(Major.ObjAttr, Minor.ObjResPict, "rsltpict"), + new KeyStruct(Major.ObjAttr, Minor.ObjResBitmap, "rsltbmp"), + new KeyStruct(Major.ObjAttr, Minor.ObjResText, "rslttxt"), + new KeyStruct(Major.ObjAttr, Minor.ObjResMerge, "rsltmerge"), + new KeyStruct(Major.ObjAttr, Minor.ObjBookmarkPubObj, "bkmkpub"), + new KeyStruct(Major.ObjAttr, Minor.ObjPubAutoUpdate, "pubauto"), + new KeyStruct(Major.ACharAttr, Minor.ACBold, "ab"), + new KeyStruct(Major.ACharAttr, Minor.ACAllCaps, "caps"), + new KeyStruct(Major.ACharAttr, Minor.ACForeColor, "acf"), + new KeyStruct(Major.ACharAttr, Minor.ACSubScript, "adn"), + new KeyStruct(Major.ACharAttr, Minor.ACExpand, "aexpnd"), + new KeyStruct(Major.ACharAttr, Minor.ACFontNum, "af"), + new KeyStruct(Major.ACharAttr, Minor.ACFontSize, "afs"), + new KeyStruct(Major.ACharAttr, Minor.ACItalic, "ai"), + new KeyStruct(Major.ACharAttr, Minor.ACLanguage, "alang"), + new KeyStruct(Major.ACharAttr, Minor.ACOutline, "aoutl"), + new KeyStruct(Major.ACharAttr, Minor.ACSmallCaps, "ascaps"), + new KeyStruct(Major.ACharAttr, Minor.ACShadow, "ashad"), + new KeyStruct(Major.ACharAttr, Minor.ACStrikeThru, "astrike"), + new KeyStruct(Major.ACharAttr, Minor.ACUnderline, "aul"), + new KeyStruct(Major.ACharAttr, Minor.ACDotUnderline, "auld"), + new KeyStruct(Major.ACharAttr, Minor.ACDbUnderline, "auldb"), + new KeyStruct(Major.ACharAttr, Minor.ACNoUnderline, "aulnone"), + new KeyStruct(Major.ACharAttr, Minor.ACWordUnderline, "aulw"), + new KeyStruct(Major.ACharAttr, Minor.ACSuperScript, "aup"), + new KeyStruct(Major.FNoteAttr, Minor.FNAlt, "ftnalt"), + new KeyStruct(Major.KeyCodeAttr, Minor.AltKey, "alt"), + new KeyStruct(Major.KeyCodeAttr, Minor.ShiftKey, "shift"), + new KeyStruct(Major.KeyCodeAttr, Minor.ControlKey, "ctrl"), + new KeyStruct(Major.KeyCodeAttr, Minor.FunctionKey, "fn"), + new KeyStruct(Major.BookmarkAttr, Minor.BookmarkFirstCol, "bkmkcolf"), + new KeyStruct(Major.BookmarkAttr, Minor.BookmarkLastCol, "bkmkcoll"), + new KeyStruct(Major.IndexAttr, Minor.IndexNumber, "xef"), + new KeyStruct(Major.IndexAttr, Minor.IndexBold, "bxe"), + new KeyStruct(Major.IndexAttr, Minor.IndexItalic, "ixe"), + new KeyStruct(Major.TOCAttr, Minor.TOCType, "tcf"), + new KeyStruct(Major.TOCAttr, Minor.TOCLevel, "tcl"), + new KeyStruct(Major.DrawAttr, Minor.DrawLock, "dolock"), + new KeyStruct(Major.DrawAttr, Minor.DrawPageRelX, "doxpage"), + new KeyStruct(Major.DrawAttr, Minor.DrawColumnRelX, "dobxcolumn"), + new KeyStruct(Major.DrawAttr, Minor.DrawMarginRelX, "dobxmargin"), + new KeyStruct(Major.DrawAttr, Minor.DrawPageRelY, "dobypage"), + new KeyStruct(Major.DrawAttr, Minor.DrawColumnRelY, "dobycolumn"), + new KeyStruct(Major.DrawAttr, Minor.DrawMarginRelY, "dobymargin"), + new KeyStruct(Major.DrawAttr, Minor.DrawHeight, "dobhgt"), + new KeyStruct(Major.DrawAttr, Minor.DrawBeginGroup, "dpgroup"), + new KeyStruct(Major.DrawAttr, Minor.DrawGroupCount, "dpcount"), + new KeyStruct(Major.DrawAttr, Minor.DrawEndGroup, "dpendgroup"), + new KeyStruct(Major.DrawAttr, Minor.DrawArc, "dparc"), + new KeyStruct(Major.DrawAttr, Minor.DrawCallout, "dpcallout"), + new KeyStruct(Major.DrawAttr, Minor.DrawEllipse, "dpellipse"), + new KeyStruct(Major.DrawAttr, Minor.DrawLine, "dpline"), + new KeyStruct(Major.DrawAttr, Minor.DrawPolygon, "dppolygon"), + new KeyStruct(Major.DrawAttr, Minor.DrawPolyLine, "dppolyline"), + new KeyStruct(Major.DrawAttr, Minor.DrawRect, "dprect"), + new KeyStruct(Major.DrawAttr, Minor.DrawTextBox, "dptxbx"), + new KeyStruct(Major.DrawAttr, Minor.DrawOffsetX, "dpx"), + new KeyStruct(Major.DrawAttr, Minor.DrawSizeX, "dpxsize"), + new KeyStruct(Major.DrawAttr, Minor.DrawOffsetY, "dpy"), + new KeyStruct(Major.DrawAttr, Minor.DrawSizeY, "dpysize"), + new KeyStruct(Major.DrawAttr, Minor.COAngle, "dpcoa"), + new KeyStruct(Major.DrawAttr, Minor.COAccentBar, "dpcoaccent"), + new KeyStruct(Major.DrawAttr, Minor.COBestFit, "dpcobestfit"), + new KeyStruct(Major.DrawAttr, Minor.COBorder, "dpcoborder"), + new KeyStruct(Major.DrawAttr, Minor.COAttachAbsDist, "dpcodabs"), + new KeyStruct(Major.DrawAttr, Minor.COAttachBottom, "dpcodbottom"), + new KeyStruct(Major.DrawAttr, Minor.COAttachCenter, "dpcodcenter"), + new KeyStruct(Major.DrawAttr, Minor.COAttachTop, "dpcodtop"), + new KeyStruct(Major.DrawAttr, Minor.COLength, "dpcolength"), + new KeyStruct(Major.DrawAttr, Minor.CONegXQuadrant, "dpcominusx"), + new KeyStruct(Major.DrawAttr, Minor.CONegYQuadrant, "dpcominusy"), + new KeyStruct(Major.DrawAttr, Minor.COOffset, "dpcooffset"), + new KeyStruct(Major.DrawAttr, Minor.COAttachSmart, "dpcosmarta"), + new KeyStruct(Major.DrawAttr, Minor.CODoubleLine, "dpcotdouble"), + new KeyStruct(Major.DrawAttr, Minor.CORightAngle, "dpcotright"), + new KeyStruct(Major.DrawAttr, Minor.COSingleLine, "dpcotsingle"), + new KeyStruct(Major.DrawAttr, Minor.COTripleLine, "dpcottriple"), + new KeyStruct(Major.DrawAttr, Minor.DrawTextBoxMargin, "dptxbxmar"), + new KeyStruct(Major.DrawAttr, Minor.DrawTextBoxText, "dptxbxtext"), + new KeyStruct(Major.DrawAttr, Minor.DrawRoundRect, "dproundr"), + new KeyStruct(Major.DrawAttr, Minor.DrawPointX, "dpptx"), + new KeyStruct(Major.DrawAttr, Minor.DrawPointY, "dppty"), + new KeyStruct(Major.DrawAttr, Minor.DrawPolyCount, "dppolycount"), + new KeyStruct(Major.DrawAttr, Minor.DrawArcFlipX, "dparcflipx"), + new KeyStruct(Major.DrawAttr, Minor.DrawArcFlipY, "dparcflipy"), + new KeyStruct(Major.DrawAttr, Minor.DrawLineBlue, "dplinecob"), + new KeyStruct(Major.DrawAttr, Minor.DrawLineGreen, "dplinecog"), + new KeyStruct(Major.DrawAttr, Minor.DrawLineRed, "dplinecor"), + new KeyStruct(Major.DrawAttr, Minor.DrawLinePalette, "dplinepal"), + new KeyStruct(Major.DrawAttr, Minor.DrawLineDashDot, "dplinedado"), + new KeyStruct(Major.DrawAttr, Minor.DrawLineDashDotDot, "dplinedadodo"), + new KeyStruct(Major.DrawAttr, Minor.DrawLineDash, "dplinedash"), + new KeyStruct(Major.DrawAttr, Minor.DrawLineDot, "dplinedot"), + new KeyStruct(Major.DrawAttr, Minor.DrawLineGray, "dplinegray"), + new KeyStruct(Major.DrawAttr, Minor.DrawLineHollow, "dplinehollow"), + new KeyStruct(Major.DrawAttr, Minor.DrawLineSolid, "dplinesolid"), + new KeyStruct(Major.DrawAttr, Minor.DrawLineWidth, "dplinew"), + new KeyStruct(Major.DrawAttr, Minor.DrawHollowEndArrow, "dpaendhol"), + new KeyStruct(Major.DrawAttr, Minor.DrawEndArrowLength, "dpaendl"), + new KeyStruct(Major.DrawAttr, Minor.DrawSolidEndArrow, "dpaendsol"), + new KeyStruct(Major.DrawAttr, Minor.DrawEndArrowWidth, "dpaendw"), + new KeyStruct(Major.DrawAttr, Minor.DrawHollowStartArrow,"dpastarthol"), + new KeyStruct(Major.DrawAttr, Minor.DrawStartArrowLength,"dpastartl"), + new KeyStruct(Major.DrawAttr, Minor.DrawSolidStartArrow, "dpastartsol"), + new KeyStruct(Major.DrawAttr, Minor.DrawStartArrowWidth, "dpastartw"), + new KeyStruct(Major.DrawAttr, Minor.DrawBgFillBlue, "dpfillbgcb"), + new KeyStruct(Major.DrawAttr, Minor.DrawBgFillGreen, "dpfillbgcg"), + new KeyStruct(Major.DrawAttr, Minor.DrawBgFillRed, "dpfillbgcr"), + new KeyStruct(Major.DrawAttr, Minor.DrawBgFillPalette, "dpfillbgpal"), + new KeyStruct(Major.DrawAttr, Minor.DrawBgFillGray, "dpfillbggray"), + new KeyStruct(Major.DrawAttr, Minor.DrawFgFillBlue, "dpfillfgcb"), + new KeyStruct(Major.DrawAttr, Minor.DrawFgFillGreen, "dpfillfgcg"), + new KeyStruct(Major.DrawAttr, Minor.DrawFgFillRed, "dpfillfgcr"), + new KeyStruct(Major.DrawAttr, Minor.DrawFgFillPalette, "dpfillfgpal"), + new KeyStruct(Major.DrawAttr, Minor.DrawFgFillGray, "dpfillfggray"), + new KeyStruct(Major.DrawAttr, Minor.DrawFillPatIndex, "dpfillpat"), + new KeyStruct(Major.DrawAttr, Minor.DrawShadow, "dpshadow"), + new KeyStruct(Major.DrawAttr, Minor.DrawShadowXOffset, "dpshadx"), + new KeyStruct(Major.DrawAttr, Minor.DrawShadowYOffset, "dpshady"), + new KeyStruct(Major.Version, Minor.Undefined, "rtf"), + new KeyStruct(Major.DefFont, Minor.Undefined, "deff"), + new KeyStruct(Major.Unicode, Minor.UnicodeCharBytes, "uc"), + new KeyStruct(Major.Unicode, Minor.UnicodeChar, "u"), + new KeyStruct(Major.Unicode, Minor.UnicodeDestination, "ud"), + new KeyStruct(Major.Unicode, Minor.UnicodeDualDestination, "upr"), + new KeyStruct(Major.Unicode, Minor.UnicodeAnsiCodepage, "ansicpg"), + }; + } + } +} diff --git a/source/ShiftUI/RTF/Major.cs b/source/ShiftUI/RTF/Major.cs new file mode 100644 index 0000000..bbd11b5 --- /dev/null +++ b/source/ShiftUI/RTF/Major.cs @@ -0,0 +1,73 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +namespace ShiftUI.RTF { + +#if RTF_LIB + public +#else + internal +#endif + enum Major { + // Group class + BeginGroup, + EndGroup, + + // Widget + Version, + DefFont, + CharSet, + + Destination, + FontFamily, + ColorName, + SpecialChar, + StyleAttr, + DocAttr, + SectAttr, + TblAttr, + ParAttr, + CharAttr, + PictAttr, + BookmarkAttr, + NeXTGrAttr, + FieldAttr, + TOCAttr, + PosAttr, + ObjAttr, + FNoteAttr, + KeyCodeAttr, + ACharAttr, + FontAttr, + FileAttr, + FileSource, + DrawAttr, + IndexAttr, + Unicode + } +} diff --git a/source/ShiftUI/RTF/Minor.cs b/source/ShiftUI/RTF/Minor.cs new file mode 100644 index 0000000..75f5047 --- /dev/null +++ b/source/ShiftUI/RTF/Minor.cs @@ -0,0 +1,769 @@ +// Permission is hereby , free of , to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without , including +// without limitation the rights to , , , , , +// , , and/or sell copies of the , and to +// permit persons to whom the Software is furnished to do , subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY , +// EXPRESS OR , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// , FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY , DAMAGES OR OTHER , WHETHER IN AN ACTION +// OF , TORT OR , ARISING , OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 , Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +namespace ShiftUI.RTF { + + internal enum Minor { + Undefined, + + Skip, + + // Major.CharSet + AnsiCharSet, + MacCharSet, + PcCharSet, + PcaCharSet, + + // Major.Destinan + FontTbl, + FontAltName, + EmbeddedFont, + FontFile, + FileTbl, + FileInfo, + ColorTbl, + StyleSheet, + KeyCode, + RevisionTbl, + Info, + ITitle, + ISubject, + IAuthor, + IOperator, + IKeywords, + IComment, + IVersion, + IDoccomm, + IVerscomm, + NextFile, + Template, + FNSep, + FNContSep, + FNContNotice, + ENSep, + ENContSep, + ENContNotice, + PageNumLevel, + ParNumLevelStyle, + Header, + Footer, + HeaderLeft, + HeaderRight, + HeaderFirst, + FooterLeft, + FooterRight, + FooterFirst, + ParNumText, + ParNumbering, + ParNumTextAfter, + ParNumTextBefore, + BookmarkStart, + BookmarkEnd, + Pict, + Object, + ObjClass, + ObjName, + ObjTime, + ObjData, + ObjAlias, + ObjSection, + ObjResult, + ObjItem, + ObjTopic, + DrawObject, + Footnote, + AnnotRefStart, + AnnotRefEnd, + AnnotID, + AnnotAuthor, + Annotation, + AnnotRef, + AnnotTime, + AnnotIcon, + Field, + FieldInst, + FieldResult, + DataField, + Index, + IndexText, + IndexRange, + TOC, + NeXTGraphic, + MaxDestination, + + // Major.FontFamily + FFNil, + FFRoman, + FFSwiss, + FFModern, + FFScript, + FFDecor, + FFTech, + FFBidirectional, + + // Major.ColorName + Red, + Green, + Blue, + + // Major.SpecialChar + IIntVersion, + ICreateTime, + IRevisionTime, + IPrintTime, + IBackupTime, + IEditTime, + IYear, + IMonth, + IDay, + IHour, + IMinute, + ISecond, + INPages, + INWords, + INChars, + IIntID, + CurHeadDate, + CurHeadDateLong, + CurHeadDateAbbrev, + CurHeadTime, + CurHeadPage, + SectNum, + CurFNote, + CurAnnotRef, + FNoteSep, + FNoteCont, + Cell, + Row, + Par, + Sect, + Page, + Column, + Line, + SoftPage, + SoftColumn, + SoftLine, + SoftLineHt, + Tab, + EmDash, + EnDash, + EmSpace, + EnSpace, + Bullet, + LQuote, + RQuote, + LDblQuote, + RDblQuote, + Formula, + NoBrkSpace, + NoReqHyphen, + NoBrkHyphen, + OptDest, + LTRMark, + RTLMark, + NoWidthJoiner, + NoWidthNonJoiner, + CurHeadPict, + + // Major.StyleAttr + Additive, + BasedOn, + Next, + + // Major.DocAttr + DefTab, + HyphHotZone, + HyphConsecLines, + HyphCaps, + HyphAuto, + LineStart, + FracWidth, + MakeBackup, + RTFDefault, + PSOverlay, + DocTemplate, + DefLanguage, + FENoteType, + FNoteEndSect, + FNoteEndDoc, + FNoteText, + FNoteBottom, + ENoteEndSect, + ENoteEndDoc, + ENoteText, + ENoteBottom, + FNoteStart, + ENoteStart, + FNoteRestartPage, + FNoteRestart, + FNoteRestartCont, + ENoteRestart, + ENoteRestartCont, + FNoteNumArabic, + FNoteNumLLetter, + FNoteNumULetter, + FNoteNumLRoman, + FNoteNumURoman, + FNoteNumChicago, + ENoteNumArabic, + ENoteNumLLetter, + ENoteNumULetter, + ENoteNumLRoman, + ENoteNumURoman, + ENoteNumChicago, + PaperWidth, + PaperHeight, + PaperSize, + LeftMargin, + RightMargin, + TopMargin, + BottomMargin, + FacingPage, + GutterWid, + MirrorMargin, + Landscape, + PageStart, + WidowCtrl, + LinkStyles, + NoAutoTabIndent, + WrapSpaces, + PrintColorsBlack, + NoExtraSpaceRL, + NoColumnBalance, + CvtMailMergeQuote, + SuppressTopSpace, + SuppressPreParSpace, + CombineTblBorders, + TranspMetafiles, + SwapBorders, + ShowHardBreaks, + FormProtected, + AllProtected, + FormShading, + FormDisplay, + PrintData, + RevProtected, + Revisions, + RevDisplay, + RevBar, + AnnotProtected, + RTLDoc, + LTRDoc, + + // Major.SectAttr + + SectDef, + ENoteHere, + PrtBinFirst, + PrtBin, + SectStyleNum, + NoBreak, + ColBreak, + PageBreak, + EvenBreak, + OddBreak, + Columns, + ColumnSpace, + ColumnNumber, + ColumnSpRight, + ColumnWidth, + ColumnLine, + LineModulus, + LineDist, + LineStarts, + LineRestart, + LineRestartPg, + LineCont, + SectPageWid, + SectPageHt, + SectMarginLeft, + SectMarginRight, + SectMarginTop, + SectMarginBottom, + SectMarginGutter, + SectLandscape, + TitleSpecial, + HeaderY, + FooterY, + PageStarts, + PageCont, + PageRestart, + PageNumRight, + PageNumTop, + PageDecimal, + PageURoman, + PageLRoman, + PageULetter, + PageLLetter, + PageNumHyphSep, + PageNumSpaceSep, + PageNumColonSep, + PageNumEmdashSep, + PageNumEndashSep, + TopVAlign, + BottomVAlign, + CenterVAlign, + JustVAlign, + RTLSect, + LTRSect, + + // Major.TblAttr + RowDef, + RowGapH, + CellPos, + MergeRngFirst, + MergePrevious, + RowLeft, + RowRight, + RowCenter, + RowLeftEdge, + RowHt, + RowHeader, + RowKeep, + RTLRow, + LTRRow, + RowBordTop, + RowBordLeft, + RowBordBottom, + RowBordRight, + RowBordHoriz, + RowBordVert, + CellBordBottom, + CellBordTop, + CellBordLeft, + CellBordRight, + CellShading, + CellBgPatH, + CellBgPatV, + CellFwdDiagBgPat, + CellBwdDiagBgPat, + CellHatchBgPat, + CellDiagHatchBgPat, + CellDarkBgPatH, + CellDarkBgPatV, + CellFwdDarkBgPat, + CellBwdDarkBgPat, + CellDarkHatchBgPat, + CellDarkDiagHatchBgPat, + CellBgPatLineColor, + CellBgPatColor, + + // Major.ParAttr + ParDef, + StyleNum, + Hyphenate, + InTable, + Keep, + NoWidowControl, + KeepNext, + OutlineLevel, + NoLineNum, + PBBefore, + SideBySide, + QuadLeft, + QuadRight, + QuadJust, + QuadCenter, + FirstIndent, + LeftIndent, + RightIndent, + SpaceBefore, + SpaceAfter, + SpaceBetween, + SpaceMultiply, + SubDocument, + RTLPar, + LTRPar, + TabPos, + TabLeft, + TabRight, + TabCenter, + TabDecimal, + TabBar, + LeaderDot, + LeaderHyphen, + LeaderUnder, + LeaderThick, + LeaderEqual, + ParLevel, + ParBullet, + ParSimple, + ParNumCont, + ParNumOnce, + ParNumAcross, + ParHangIndent, + ParNumRestart, + ParNumCardinal, + ParNumDecimal, + ParNumULetter, + ParNumURoman, + ParNumLLetter, + ParNumLRoman, + ParNumOrdinal, + ParNumOrdinalText, + ParNumBold, + ParNumItalic, + ParNumAllCaps, + ParNumSmallCaps, + ParNumUnder, + ParNumDotUnder, + ParNumDbUnder, + ParNumNoUnder, + ParNumWordUnder, + ParNumStrikethru, + ParNumForeColor, + ParNumFont, + ParNumFontSize, + ParNumIndent, + ParNumSpacing, + ParNumInclPrev, + ParNumCenter, + ParNumLeft, + ParNumRight, + ParNumStartAt, + BorderTop, + BorderBottom, + BorderLeft, + BorderRight, + BorderBetween, + BorderBar, + BorderBox, + BorderSingle, + BorderThick, + BorderShadow, + BorderDouble, + BorderDot, + BorderDash, + BorderHair, + BorderWidth, + BorderColor, + BorderSpace, + Shading, + BgPatH, + BgPatV, + FwdDiagBgPat, + BwdDiagBgPat, + HatchBgPat, + DiagHatchBgPat, + DarkBgPatH, + DarkBgPatV, + FwdDarkBgPat, + BwdDarkBgPat, + DarkHatchBgPat, + DarkDiagHatchBgPat, + BgPatLineColor, + BgPatColor, + + // Major.CharAttr + Plain, + Bold, + AllCaps, + Deleted, + SubScript, + SubScrShrink, + NoSuperSub, + Expand, + ExpandTwips, + Kerning, + FontNum, + FontSize, + Italic, + Outline, + Revised, + RevAuthor, + RevDTTM, + SmallCaps, + Shadow, + StrikeThru, + Underline, + DotUnderline, + DbUnderline, + NoUnderline, + WordUnderline, + SuperScript, + SuperScrShrink, + Invisible, + ForeColor, + BackColor, + RTLChar, + LTRChar, + CharStyleNum, + CharCharSet, + Language, + Gray, + + // Major.PictAttr + MacQD, + PMMetafile, + WinMetafile, + DevIndBitmap, + WinBitmap, + PngBlip, + PixelBits, + BitmapPlanes, + BitmapWid, + PicWid, + PicHt, + PicGoalWid, + PicGoalHt, + PicScaleX, + PicScaleY, + PicScaled, + PicCropTop, + PicCropBottom, + PicCropLeft, + PicCropRight, + PicMFHasBitmap, + PicMFBitsPerPixel, + PicBinary, + + // Major.BookmarkAttr + BookmarkFirstCol, + BookmarkLastCol , + + // Major.NeXTGrAttr + NeXTGWidth, + NeXTGHeight, + + // Major.FieldAttr + FieldDirty, + FieldEdited, + FieldLocked, + FieldPrivate, + FieldAlt, + + // Major.TOCAttr + TOCType, + TOCLevel, + + // Major.PosAttr + AbsWid, + AbsHt, + RPosMargH, + RPosPageH, + RPosColH, + PosX, + PosNegX, + PosXCenter, + PosXInside, + PosXOutSide, + PosXRight, + PosXLeft, + RPosMargV, + RPosPageV, + RPosParaV, + PosY, + PosNegY, + PosYInline, + PosYTop, + PosYCenter, + PosYBottom, + NoWrap, + DistFromTextAll, + DistFromTextX, + DistFromTextY, + TextDistY, + DropCapLines, + DropCapType, + + // Major.ObjAttr + ObjEmb, + ObjLink, + ObjAutoLink, + ObjSubscriber, + ObjPublisher, + ObjICEmb, + ObjLinkSelf, + ObjLock, + ObjUpdate, + ObjHt, + ObjWid, + ObjSetSize, + ObjAlign, + ObjTransposeY, + ObjCropTop, + ObjCropBottom, + ObjCropLeft, + ObjCropRight, + ObjScaleX, + ObjScaleY, + ObjResRTF, + ObjResPict, + ObjResBitmap, + ObjResText, + ObjResMerge, + ObjBookmarkPubObj, + ObjPubAutoUpdate, + + // Major.FNoteAttr + FNAlt, + + // Major.KeyCodeAttr + AltKey, + ShiftKey, + ControlKey, + FunctionKey, + + // Major.ACharAttr + ACBold, + ACAllCaps, + ACForeColor, + ACSubScript, + ACExpand, + ACFontNum, + ACFontSize, + ACItalic, + ACLanguage, + ACOutline, + ACSmallCaps, + ACShadow, + ACStrikeThru, + ACUnderline, + ACDotUnderline, + ACDbUnderline, + ACNoUnderline, + ACWordUnderline, + ACSuperScript, + + // Major.FontAttr + FontCharSet, + FontPitch, + FontCodePage, + FTypeNil, + FTypeTrueType, + + // Major.FileAttr + FileNum, + FileRelPath, + FileOSNum, + + // Major.FileSource + SrcMacintosh, + SrcDOS, + SrcNTFS, + SrcHPFS, + SrcNetwork, + + // Major.DrawAttr + DrawLock, + DrawPageRelX, + DrawColumnRelX, + DrawMarginRelX, + DrawPageRelY, + DrawColumnRelY, + DrawMarginRelY, + DrawHeight, + DrawBeginGroup, + DrawGroupCount, + DrawEndGroup, + DrawArc, + DrawCallout, + DrawEllipse, + DrawLine, + DrawPolygon, + DrawPolyLine, + DrawRect, + DrawTextBox, + DrawOffsetX, + DrawSizeX, + DrawOffsetY, + DrawSizeY, + COAngle, + COAccentBar, + COBestFit, + COBorder, + COAttachAbsDist, + COAttachBottom, + COAttachCenter, + COAttachTop, + COLength, + CONegXQuadrant, + CONegYQuadrant, + COOffset, + COAttachSmart, + CODoubleLine, + CORightAngle, + COSingleLine, + COTripleLine, + DrawTextBoxMargin, + DrawTextBoxText, + DrawRoundRect, + DrawPointX, + DrawPointY, + DrawPolyCount, + DrawArcFlipX, + DrawArcFlipY, + DrawLineBlue, + DrawLineGreen, + DrawLineRed, + DrawLinePalette, + DrawLineDashDot, + DrawLineDashDotDot, + DrawLineDash, + DrawLineDot, + DrawLineGray, + DrawLineHollow, + DrawLineSolid, + DrawLineWidth, + DrawHollowEndArrow, + DrawEndArrowLength, + DrawSolidEndArrow, + DrawEndArrowWidth, + DrawHollowStartArrow, + DrawStartArrowLength, + DrawSolidStartArrow, + DrawStartArrowWidth, + DrawBgFillBlue, + DrawBgFillGreen, + DrawBgFillRed, + DrawBgFillPalette, + DrawBgFillGray, + DrawFgFillBlue, + DrawFgFillGreen, + DrawFgFillRed, + DrawFgFillPalette, + DrawFgFillGray, + DrawFillPatIndex, + DrawShadow, + DrawShadowXOffset, + DrawShadowYOffset, + + // Major.IndexAttr + IndexNumber, + IndexBold, + IndexItalic, + + // Major.Unicode + UnicodeCharBytes, + UnicodeChar, + UnicodeDestination, + UnicodeDualDestination, + UnicodeAnsiCodepage + + } +} diff --git a/source/ShiftUI/RTF/Picture.cs b/source/ShiftUI/RTF/Picture.cs new file mode 100644 index 0000000..55d1cc6 --- /dev/null +++ b/source/ShiftUI/RTF/Picture.cs @@ -0,0 +1,149 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// + + +using System; +using System.IO; +using System.Drawing; + +namespace ShiftUI.RTF { + + internal class Picture { + + private Minor image_type; + private Image image; + private MemoryStream data; + private float width = -1; + private float height = -1; + + private readonly static float dpix; + + static Picture () + { + dpix = TextRenderer.GetDpi ().Width; + } + + public Picture () + { + + } + + public Minor ImageType { + get { return image_type; } + set { image_type = value; } + } + + public MemoryStream Data { + get { + if (data == null) + data = new MemoryStream (); + return data; + } + } + + public float Width { + get { + float w = width; + if (w == -1) { + if (image == null) + image = ToImage (); + w = image.Width; + } + return w; + + } + } + + public float Height { + get { + float h = height; + if (h == -1) { + if (image == null) + image = ToImage (); + h = image.Height; + } + return h; + } + } + + public SizeF Size { + get { + return new SizeF (Width, Height); + } + } + + public void SetWidthFromTwips (int twips) + { + width = (int) (((float) twips / 1440.0F) * dpix + 0.5F); + } + + public void SetHeightFromTwips (int twips) + { + height = (int) (((float) twips / 1440.0F) * dpix + 0.5F); + } + + // + // Makes sure that we got enough information to actually use the image + // + public bool IsValid () + { + if (data == null) + return false; + switch (image_type) { + case Minor.PngBlip: + case Minor.WinMetafile: + break; + default: + return false; + } + + return true; + } + + public void DrawImage (Graphics dc, float x, float y, bool selected) + { + if (image == null) + image = ToImage (); + + float height = this.height; + float width = this.width; + + if (height == -1) + height = image.Height; + if (width == -1) + width = image.Width; + dc.DrawImage (image, x, y, width, height); + } + + public Image ToImage () + { + // Reset the data stream position to the beginning + data.Position = 0; + return Image.FromStream (data); + } + } + +} + diff --git a/source/ShiftUI/RTF/README b/source/ShiftUI/RTF/README new file mode 100644 index 0000000..ccfb3fa --- /dev/null +++ b/source/ShiftUI/RTF/README @@ -0,0 +1,7 @@ +This RTF parser was originally based on a C-based RTF parser written +by Paul DuBois (dubois@primate.wisc.edu). It came with the following license: + + * This software may be redistributed without restriction and used for + * any purpose whatsoever. + +and was part of the code found in the 'rewind' project. diff --git a/source/ShiftUI/RTF/RTF.cs b/source/ShiftUI/RTF/RTF.cs new file mode 100644 index 0000000..dd67fe6 --- /dev/null +++ b/source/ShiftUI/RTF/RTF.cs @@ -0,0 +1,1056 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// + +// COMPLETE + +#undef RTF_DEBUG + +using System; +using System.Collections; +using System.IO; +using System.Text; + +namespace ShiftUI.RTF { + internal class RTF { + #region Local Variables + internal const char EOF = unchecked((char)-1); + internal const int NoParam = -1000000; + internal const int DefaultEncodingCodePage = 1252; + + private TokenClass rtf_class; + private Major major; + private Minor minor; + private int param; + private string encoded_text; + private Encoding encoding; + private int encoding_code_page = DefaultEncodingCodePage; + private StringBuilder text_buffer; + private Picture picture; + private int line_num; + private int line_pos; + + private char pushed_char; + //private StringBuilder pushed_text_buffer; + private TokenClass pushed_class; + private Major pushed_major; + private Minor pushed_minor; + private int pushed_param; + + private char prev_char; + private bool bump_line; + + private Font font_list; + + private Charset cur_charset; + private Stack charset_stack; + + private Style styles; + private Color colors; + private Font fonts; + + private StreamReader source; + + private static Hashtable key_table; + private static KeyStruct[] Keys = KeysInit.Init(); + + private DestinationCallback destination_callbacks; + private ClassCallback class_callbacks; + #endregion // Local Variables + + #region Constructors + static RTF() { + key_table = new Hashtable(Keys.Length); + for (int i = 0; i < Keys.Length; i++) { + key_table[Keys[i].Symbol] = Keys[i]; + } + } + + public RTF(Stream stream) { + source = new StreamReader(stream); + + text_buffer = new StringBuilder(1024); + //pushed_text_buffer = new StringBuilder(1024); + + rtf_class = TokenClass.None; + pushed_class = TokenClass.None; + pushed_char = unchecked((char)-1); + + line_num = 0; + line_pos = 0; + prev_char = unchecked((char)-1); + bump_line = false; + font_list = null; + charset_stack = null; + + cur_charset = new Charset(); + + destination_callbacks = new DestinationCallback(); + class_callbacks = new ClassCallback(); + + destination_callbacks [Minor.OptDest] = new DestinationDelegate (HandleOptDest); + destination_callbacks[Minor.FontTbl] = new DestinationDelegate(ReadFontTbl); + destination_callbacks[Minor.ColorTbl] = new DestinationDelegate(ReadColorTbl); + destination_callbacks[Minor.StyleSheet] = new DestinationDelegate(ReadStyleSheet); + destination_callbacks[Minor.Info] = new DestinationDelegate(ReadInfoGroup); + destination_callbacks[Minor.Pict] = new DestinationDelegate(ReadPictGroup); + destination_callbacks[Minor.Object] = new DestinationDelegate(ReadObjGroup); + } + #endregion // Constructors + + #region Properties + public TokenClass TokenClass { + get { + return this.rtf_class; + } + + set { + this.rtf_class = value; + } + } + + public Major Major { + get { + return this.major; + } + + set { + this.major = value; + } + } + + public Minor Minor { + get { + return this.minor; + } + + set { + this.minor = value; + } + } + + public int Param { + get { + return this.param; + } + + set { + this.param = value; + } + } + + public string Text { + get { + return this.text_buffer.ToString(); + } + + set { + if (value == null) { + this.text_buffer.Length = 0; + } else { + this.text_buffer = new StringBuilder(value); + } + } + } + + public string EncodedText { + get { return encoded_text; } + } + + public Picture Picture { + get { return picture; } + set { picture = value; } + } + + public Color Colors { + get { + return colors; + } + + set { + colors = value; + } + } + + public Style Styles { + get { + return styles; + } + + set { + styles = value; + } + } + + public Font Fonts { + get { + return fonts; + } + + set { + fonts = value; + } + } + + public ClassCallback ClassCallback { + get { + return class_callbacks; + } + + set { + class_callbacks = value; + } + } + + public DestinationCallback DestinationCallback { + get { + return destination_callbacks; + } + + set { + destination_callbacks = value; + } + } + + public int LineNumber { + get { + return line_num; + } + } + + public int LinePos { + get { + return line_pos; + } + } + #endregion // Properties + + #region Methods + /// Set the default font for documents without font table + public void DefaultFont(string name) { + Font font; + + font = new Font(this); + font.Num = 0; + font.Name = name; + } + + /// Read the next character from the input - skip any crlf + private char GetChar () + { + return GetChar (true); + } + + /// Read the next character from the input + private char GetChar(bool skipCrLf) + { + int c; + bool old_bump_line; + +SkipCRLF: + if ((c = source.Read()) != -1) { + this.text_buffer.Append((char) c); + } + + if (this.prev_char == EOF) { + this.bump_line = true; + } + + old_bump_line = bump_line; + bump_line = false; + + if (skipCrLf) { + if (c == '\r') { + bump_line = true; + text_buffer.Length--; + goto SkipCRLF; + } else if (c == '\n') { + bump_line = true; + if (this.prev_char == '\r') { + old_bump_line = false; + } + + text_buffer.Length--; + goto SkipCRLF; + } + } + + this.line_pos ++; + if (old_bump_line) { + this.line_num++; + this.line_pos = 1; + } + + this.prev_char = (char) c; + return (char) c; + } + + /// Parse the RTF stream + public void Read() { + while (GetToken() != TokenClass.EOF) { + RouteToken(); + } + } + + /// Route a token + public void RouteToken() { + + if (CheckCM(TokenClass.Widget, Major.Destination)) { + DestinationDelegate d; + + d = destination_callbacks[minor]; + if (d != null) { + d(this); + } + } + + // Invoke class callback if there is one + ClassDelegate c; + + c = class_callbacks[rtf_class]; + if (c != null) { + c(this); + } + + } + + /// Skip to the end of the next group to start or current group we are in + public void SkipGroup() { + int level; + + level = 1; + + while (GetToken() != TokenClass.EOF) { + if (rtf_class == TokenClass.Group) { + if (this.major == Major.BeginGroup) { + level++; + } else if (this.major == Major.EndGroup) { + level--; + if (level < 1) { + break; + } + } + } + } + } + + /// Return the next token in the stream + public TokenClass GetToken() { + if (pushed_class != TokenClass.None) { + this.rtf_class = this.pushed_class; + this.major = this.pushed_major; + this.minor = this.pushed_minor; + this.param = this.pushed_param; + this.pushed_class = TokenClass.None; + return this.rtf_class; + } + + GetToken2(); + + if (this.rtf_class == TokenClass.Text) { + this.minor = (Minor)this.cur_charset[(int)this.major]; + if (encoding == null) { + encoding = Encoding.GetEncoding (encoding_code_page); + } + encoded_text = new String (encoding.GetChars (new byte [] { (byte) this.major })); + } + + if (this.cur_charset.Flags == CharsetFlags.None) { + return this.rtf_class; + } + + if (CheckCMM (TokenClass.Widget, Major.Unicode, Minor.UnicodeAnsiCodepage)) { + encoding_code_page = param; + + // fallback to the default one in case we have an invalid value + if (encoding_code_page < 0 || encoding_code_page > 65535) + encoding_code_page = DefaultEncodingCodePage; + } + + if (((this.cur_charset.Flags & CharsetFlags.Read) != 0) && CheckCM(TokenClass.Widget, Major.CharSet)) { + this.cur_charset.ReadMap(); + } else if (((this.cur_charset.Flags & CharsetFlags.Switch) != 0) && CheckCMM(TokenClass.Widget, Major.CharAttr, Minor.FontNum)) { + Font fp; + + fp = Font.GetFont(this.font_list, this.param); + + if (fp != null) { + if (fp.Name.StartsWith("Symbol")) { + this.cur_charset.ID = CharsetType.Symbol; + } else { + this.cur_charset.ID = CharsetType.General; + } + } else if (((this.cur_charset.Flags & CharsetFlags.Switch) != 0) && (this.rtf_class == TokenClass.Group)) { + switch(this.major) { + case Major.BeginGroup: { + this.charset_stack.Push(this.cur_charset); + break; + } + + case Major.EndGroup: { + this.cur_charset = (Charset)this.charset_stack.Pop(); + break; + } + } + } + } + + return this.rtf_class; + } + + private void GetToken2() { + char c; + int sign; + + this.rtf_class = TokenClass.Unknown; + this.param = NoParam; + + this.text_buffer.Length = 0; + + if (this.pushed_char != EOF) { + c = this.pushed_char; + this.text_buffer.Append(c); + this.pushed_char = EOF; + } else if ((c = GetChar()) == EOF) { + this.rtf_class = TokenClass.EOF; + return; + } + + if (c == '{') { + this.rtf_class = TokenClass.Group; + this.major = Major.BeginGroup; + return; + } + + if (c == '}') { + this.rtf_class = TokenClass.Group; + this.major = Major.EndGroup; + return; + } + + if (c != '\\') { + if (c != '\t') { + this.rtf_class = TokenClass.Text; + this.major = (Major)c; // FIXME - typing? + return; + } else { + this.rtf_class = TokenClass.Widget; + this.major = Major.SpecialChar; + this.minor = Minor.Tab; + return; + } + } + + if ((c = GetChar()) == EOF) { + // Not so good + return; + } + + if (!Char.IsLetter(c)) { + if (c == '\'') { + char c2; + + if ((c = GetChar()) == EOF) { + return; + } + + if ((c2 = GetChar()) == EOF) { + return; + } + + this.rtf_class = TokenClass.Text; + this.major = (Major)((Char)((Convert.ToByte(c.ToString(), 16) * 16 + Convert.ToByte(c2.ToString(), 16)))); + return; + } + + // Escaped char + if (c == ':' || c == '{' || c == '}' || c == '\\') { + this.rtf_class = TokenClass.Text; + this.major = (Major)c; + return; + } + + Lookup(this.text_buffer.ToString()); + return; + } + + while (Char.IsLetter(c)) { + if ((c = GetChar(false)) == EOF) { + break; + } + } + + if (c != EOF) { + this.text_buffer.Length--; + } + + Lookup(this.text_buffer.ToString()); + + if (c != EOF) { + this.text_buffer.Append(c); + } + + sign = 1; + if (c == '-') { + sign = -1; + c = GetChar(); + } + + if (c != EOF && Char.IsDigit(c) && minor != Minor.PngBlip) { + this.param = 0; + while (Char.IsDigit(c)) { + this.param = this.param * 10 + Convert.ToByte(c) - 48; + if ((c = GetChar()) == EOF) { + break; + } + } + this.param *= sign; + } + + if (c != EOF) { + if (c != ' ' && c != '\r' && c != '\n') { + this.pushed_char = c; + } + this.text_buffer.Length--; + } + } + + public void SetToken(TokenClass cl, Major maj, Minor min, int par, string text) { + this.rtf_class = cl; + this.major = maj; + this.minor = min; + this.param = par; + if (par == NoParam) { + this.text_buffer = new StringBuilder(text); + } else { + this.text_buffer = new StringBuilder(text + par.ToString()); + } + } + + public void UngetToken() { + if (this.pushed_class != TokenClass.None) { + throw new RTFException(this, "Cannot unget more than one token"); + } + + if (this.rtf_class == TokenClass.None) { + throw new RTFException(this, "No token to unget"); + } + + this.pushed_class = this.rtf_class; + this.pushed_major = this.major; + this.pushed_minor = this.minor; + this.pushed_param = this.param; + //this.pushed_text_buffer = new StringBuilder(this.text_buffer.ToString()); + } + + public TokenClass PeekToken() { + GetToken(); + UngetToken(); + return rtf_class; + } + + public void Lookup(string token) { + Object obj; + KeyStruct key; + + obj = key_table[token.Substring(1)]; + if (obj == null) { + rtf_class = TokenClass.Unknown; + major = (Major) -1; + minor = (Minor) -1; + return; + } + + key = (KeyStruct)obj; + this.rtf_class = TokenClass.Widget; + this.major = key.Major; + this.minor = key.Minor; + } + + public bool CheckCM(TokenClass rtf_class, Major major) { + if ((this.rtf_class == rtf_class) && (this.major == major)) { + return true; + } + + return false; + } + + public bool CheckCMM(TokenClass rtf_class, Major major, Minor minor) { + if ((this.rtf_class == rtf_class) && (this.major == major) && (this.minor == minor)) { + return true; + } + + return false; + } + + public bool CheckMM(Major major, Minor minor) { + if ((this.major == major) && (this.minor == minor)) { + return true; + } + + return false; + } + #endregion // Methods + + #region Default Delegates + + private void HandleOptDest (RTF rtf) + { + int group_levels = 1; + + while (true) { + GetToken (); + + // Here is where we should handle recognised optional + // destinations. + // + // Handle a picture group + // + if (rtf.CheckCMM (TokenClass.Widget, Major.Destination, Minor.Pict)) { + ReadPictGroup (rtf); + return; + } + + if (rtf.CheckCM (TokenClass.Group, Major.EndGroup)) { + if ((--group_levels) == 0) { + break; + } + } + + if (rtf.CheckCM (TokenClass.Group, Major.BeginGroup)) { + group_levels++; + } + } + } + + private void ReadFontTbl(RTF rtf) { + int old; + Font font; + + old = -1; + font = null; + + while (true) { + rtf.GetToken(); + + if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) { + break; + } + + if (old < 0) { + if (rtf.CheckCMM(TokenClass.Widget, Major.CharAttr, Minor.FontNum)) { + old = 1; + } else if (rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) { + old = 0; + } else { + throw new RTFException(rtf, "Cannot determine format"); + } + } + + if (old == 0) { + if (!rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) { + throw new RTFException(rtf, "missing \"{\""); + } + rtf.GetToken(); + } + + font = new Font(rtf); + + while ((rtf.rtf_class != TokenClass.EOF) && (!rtf.CheckCM(TokenClass.Text, (Major)';')) && (!rtf.CheckCM(TokenClass.Group, Major.EndGroup))) { + if (rtf.rtf_class == TokenClass.Widget) { + switch(rtf.major) { + case Major.FontFamily: { + font.Family = (int)rtf.minor; + break; + } + + case Major.CharAttr: { + switch(rtf.minor) { + case Minor.FontNum: { + font.Num = rtf.param; + break; + } + + default: { + #if RTF_DEBUG + Console.WriteLine("Got unhandled Widget.CharAttr.Minor: " + rtf.minor); + #endif + break; + } + } + break; + } + + case Major.FontAttr: { + switch (rtf.minor) { + case Minor.FontCharSet: { + font.Charset = (CharsetType)rtf.param; + break; + } + + case Minor.FontPitch: { + font.Pitch = rtf.param; + break; + } + + case Minor.FontCodePage: { + font.Codepage = rtf.param; + break; + } + + case Minor.FTypeNil: + case Minor.FTypeTrueType: { + font.Type = rtf.param; + break; + } + default: { + #if RTF_DEBUG + Console.WriteLine("Got unhandled Widget.FontAttr.Minor: " + rtf.minor); + #endif + break; + } + } + break; + } + + default: { + #if RTF_DEBUG + Console.WriteLine("ReadFontTbl: Unknown Widget token " + rtf.major); + #endif + break; + } + } + } else if (rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) { + rtf.SkipGroup(); + } else if (rtf.rtf_class == TokenClass.Text) { + StringBuilder sb; + + sb = new StringBuilder(); + + while ((rtf.rtf_class != TokenClass.EOF) && (!rtf.CheckCM(TokenClass.Text, (Major)';')) && (!rtf.CheckCM(TokenClass.Group, Major.EndGroup)) && (!rtf.CheckCM(TokenClass.Group, Major.BeginGroup))) { + sb.Append((char)rtf.major); + rtf.GetToken(); + } + + if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) { + rtf.UngetToken(); + } + + font.Name = sb.ToString(); + continue; +#if RTF_DEBUG + } else { + Console.WriteLine("ReadFontTbl: Unknown token " + rtf.text_buffer); +#endif + } + + rtf.GetToken(); + } + + if (old == 0) { + rtf.GetToken(); + + if (!rtf.CheckCM(TokenClass.Group, Major.EndGroup)) { + throw new RTFException(rtf, "Missing \"}\""); + } + } + } + + if (font == null) { + throw new RTFException(rtf, "No font created"); + } + + if (font.Num == -1) { + throw new RTFException(rtf, "Missing font number"); + } + + rtf.RouteToken(); + } + + private void ReadColorTbl(RTF rtf) { + Color color; + int num; + + num = 0; + + while (true) { + rtf.GetToken(); + + if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) { + break; + } + + color = new Color(rtf); + color.Num = num++; + + while (rtf.CheckCM(TokenClass.Widget, Major.ColorName)) { + switch (rtf.minor) { + case Minor.Red: { + color.Red = rtf.param; + break; + } + + case Minor.Green: { + color.Green = rtf.param; + break; + } + + case Minor.Blue: { + color.Blue = rtf.param; + break; + } + } + + rtf.GetToken(); + } + if (!rtf.CheckCM(TokenClass.Text, (Major)';')) { + throw new RTFException(rtf, "Malformed color entry"); + } + } + rtf.RouteToken(); + } + + private void ReadStyleSheet(RTF rtf) { + Style style; + StringBuilder sb; + + sb = new StringBuilder(); + + while (true) { + rtf.GetToken(); + + if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) { + break; + } + + style = new Style(rtf); + + if (!rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) { + throw new RTFException(rtf, "Missing \"{\""); + } + + while (true) { + rtf.GetToken(); + + if ((rtf.rtf_class == TokenClass.EOF) || rtf.CheckCM(TokenClass.Text, (Major)';')) { + break; + } + + if (rtf.rtf_class == TokenClass.Widget) { + if (rtf.CheckMM(Major.ParAttr, Minor.StyleNum)) { + style.Num = rtf.param; + style.Type = StyleType.Paragraph; + continue; + } + if (rtf.CheckMM(Major.CharAttr, Minor.CharStyleNum)) { + style.Num = rtf.param; + style.Type = StyleType.Character; + continue; + } + if (rtf.CheckMM(Major.StyleAttr, Minor.SectStyleNum)) { + style.Num = rtf.param; + style.Type = StyleType.Section; + continue; + } + if (rtf.CheckMM(Major.StyleAttr, Minor.BasedOn)) { + style.BasedOn = rtf.param; + continue; + } + if (rtf.CheckMM(Major.StyleAttr, Minor.Additive)) { + style.Additive = true; + continue; + } + if (rtf.CheckMM(Major.StyleAttr, Minor.Next)) { + style.NextPar = rtf.param; + continue; + } + + new StyleElement(style, rtf.rtf_class, rtf.major, rtf.minor, rtf.param, rtf.text_buffer.ToString()); + } else if (rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) { + // This passes over "{\*\keycode ... }, among other things + rtf.SkipGroup(); + } else if (rtf.rtf_class == TokenClass.Text) { + while (rtf.rtf_class == TokenClass.Text) { + if (rtf.major == (Major)';') { + rtf.UngetToken(); + break; + } + + sb.Append((char)rtf.major); + rtf.GetToken(); + } + + style.Name = sb.ToString(); +#if RTF_DEBUG + } else { + Console.WriteLine("ReadStyleSheet: Ignored token " + rtf.text_buffer); +#endif + } + } + rtf.GetToken(); + + if (!rtf.CheckCM(TokenClass.Group, Major.EndGroup)) { + throw new RTFException(rtf, "Missing EndGroup (\"}\""); + } + + // Sanity checks + if (style.Name == null) { + throw new RTFException(rtf, "Style must have name"); + } + + if (style.Num < 0) { + if (!sb.ToString().StartsWith("Normal") && !sb.ToString().StartsWith("Standard")) { + throw new RTFException(rtf, "Missing style number"); + } + + style.Num = Style.NormalStyleNum; + } + + if (style.NextPar == -1) { + style.NextPar = style.Num; + } + } + + rtf.RouteToken(); + } + + private void ReadInfoGroup(RTF rtf) { + rtf.SkipGroup(); + rtf.RouteToken(); + } + + private void ReadPictGroup(RTF rtf) + { + bool read_image_data = false; + + Picture picture = new Picture (); + while (true) { + rtf.GetToken (); + + if (rtf.CheckCM (TokenClass.Group, Major.EndGroup)) + break; + + switch (minor) { + case Minor.PngBlip: + picture.ImageType = minor; + read_image_data = true; + break; + case Minor.WinMetafile: + picture.ImageType = minor; + read_image_data = true; + continue; + case Minor.PicWid: + continue; + case Minor.PicHt: + continue; + case Minor.PicGoalWid: + picture.SetWidthFromTwips (param); + continue; + case Minor.PicGoalHt: + picture.SetHeightFromTwips (param); + continue; + } + + if (read_image_data && rtf.rtf_class == TokenClass.Text) { + + picture.Data.Seek (0, SeekOrigin.Begin); + + //char c = (char) rtf.major; + + uint digitValue1; + uint digitValue2; + char hexDigit1 = (char) rtf.major; + char hexDigit2; + + while (true) { + + while (hexDigit1 == '\n' || hexDigit1 == '\r') { + hexDigit1 = (char) source.Peek (); + if (hexDigit1 == '}') + break; + hexDigit1 = (char) source.Read (); + } + + hexDigit2 = (char) source.Peek (); + if (hexDigit2 == '}') + break; + hexDigit2 = (char) source.Read (); + while (hexDigit2 == '\n' || hexDigit2 == '\r') { + hexDigit2 = (char) source.Peek (); + if (hexDigit2 == '}') + break; + hexDigit2 = (char) source.Read (); + } + + if (Char.IsDigit (hexDigit1)) + digitValue1 = (uint) (hexDigit1 - '0'); + else if (Char.IsLower (hexDigit1)) + digitValue1 = (uint) (hexDigit1 - 'a' + 10); + else if (Char.IsUpper (hexDigit1)) + digitValue1 = (uint) (hexDigit1 - 'A' + 10); + else if (hexDigit1 == '\n' || hexDigit1 == '\r') + continue; + else + break; + + if (Char.IsDigit (hexDigit2)) + digitValue2 = (uint) (hexDigit2 - '0'); + else if (Char.IsLower (hexDigit2)) + digitValue2 = (uint) (hexDigit2 - 'a' + 10); + else if (Char.IsUpper (hexDigit2)) + digitValue2 = (uint) (hexDigit2 - 'A' + 10); + else if (hexDigit2 == '\n' || hexDigit2 == '\r') + continue; + else + break; + + picture.Data.WriteByte ((byte) checked (digitValue1 * 16 + digitValue2)); + + // We get the first hex digit at the end, since in the very first + // iteration we use rtf.major as the first hex digit + hexDigit1 = (char) source.Peek (); + if (hexDigit1 == '}') + break; + hexDigit1 = (char) source.Read (); + } + + + read_image_data = false; + break; + } + } + + if (picture.ImageType != Minor.Undefined && !read_image_data) { + this.picture = picture; + SetToken (TokenClass.Widget, Major.PictAttr, picture.ImageType, 0, String.Empty); + } + } + + private void ReadObjGroup(RTF rtf) { + rtf.SkipGroup(); + rtf.RouteToken(); + } + #endregion // Default Delegates + } +} diff --git a/source/ShiftUI/RTF/RTFException.cs b/source/ShiftUI/RTF/RTFException.cs new file mode 100644 index 0000000..adaa16c --- /dev/null +++ b/source/ShiftUI/RTF/RTFException.cs @@ -0,0 +1,87 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +using System; +using System.Text; + +namespace ShiftUI.RTF { + +#if RTF_LIB + public +#else + internal +#endif + class RTFException : ApplicationException { + #region Local Variables + private int pos; + private int line; + private TokenClass token_class; + private Major major; + private Minor minor; + private int param; + private string text; + private string error_message; + #endregion // Local Variables + + #region Constructors + public RTFException(RTF rtf, string error_message) { + this.pos = rtf.LinePos; + this.line = rtf.LineNumber; + this.token_class = rtf.TokenClass; + this.major = rtf.Major; + this.minor = rtf.Minor; + this.param = rtf.Param; + this.text = rtf.Text; + this.error_message = error_message; + } + #endregion // Constructors + + #region Properties + public override string Message { + get { + StringBuilder sb; + + sb = new StringBuilder(); + sb.Append(error_message); + sb.Append("\n"); + + sb.Append("RTF Stream Info: Pos:" + pos + " Line:" + line); + sb.Append("\n"); + + sb.Append("TokenClass:" + token_class + ", "); + sb.Append("Major:" + String.Format("{0}", (int)major) + ", "); + sb.Append("Minor:" + String.Format("{0}", (int)minor) + ", "); + sb.Append("Param:" + String.Format("{0}", param) + ", "); + sb.Append("Text:" + text); + + return sb.ToString(); + } + } + #endregion // Properties + } +} diff --git a/source/ShiftUI/RTF/StandardCharCode.cs b/source/ShiftUI/RTF/StandardCharCode.cs new file mode 100644 index 0000000..bfa8ab1 --- /dev/null +++ b/source/ShiftUI/RTF/StandardCharCode.cs @@ -0,0 +1,392 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +namespace ShiftUI.RTF { + +#if RTF_LIB + public +#else + internal +#endif + enum StandardCharCode { + nothing = 0, + space = 1, + exclam = 2, + quotedbl = 3, + numbersign = 4, + dollar = 5, + percent = 6, + ampersand = 7, + quoteright = 8, + parenleft = 9, + parenright = 10, + asterisk = 11, + plus = 12, + comma = 13, + hyphen = 14, + period = 15, + slash = 16, + zero = 17, + one = 18, + two = 19, + three = 20, + four = 21, + five = 22, + six = 23, + seven = 24, + eight = 25, + nine = 26, + colon = 27, + semicolon = 28, + less = 29, + equal = 30, + greater = 31, + question = 32, + at = 33, + A = 34, + B = 35, + C = 36, + D = 37, + E = 38, + F = 39, + G = 40, + H = 41, + I = 42, + J = 43, + K = 44, + L = 45, + M = 46, + N = 47, + O = 48, + P = 49, + Q = 50, + R = 51, + S = 52, + T = 53, + U = 54, + V = 55, + W = 56, + X = 57, + Y = 58, + Z = 59, + bracketleft = 60, + backslash = 61, + bracketright = 62, + asciicircum = 63, + underscore = 64, + quoteleft = 65, + a = 66, + b = 67, + c = 68, + d = 69, + e = 70, + f = 71, + g = 72, + h = 73, + i = 74, + j = 75, + k = 76, + l = 77, + m = 78, + n = 79, + o = 80, + p = 81, + q = 82, + r = 83, + s = 84, + t = 85, + u = 86, + v = 87, + w = 88, + x = 89, + y = 90, + z = 91, + braceleft = 92, + bar = 93, + braceright = 94, + asciitilde = 95, + exclamdown = 96, + cent = 97, + sterling = 98, + fraction = 99, + yen = 100, + florin = 101, + section = 102, + currency = 103, + quotedblleft = 104, + guillemotleft = 105, + guilsinglleft = 106, + guilsinglright = 107, + fi = 108, + fl = 109, + endash = 110, + dagger = 111, + daggerdbl = 112, + periodcentered = 113, + paragraph = 114, + bullet = 115, + quotesinglbase = 116, + quotedblbase = 117, + quotedblright = 118, + guillemotright = 119, + ellipsis = 120, + perthousand = 121, + questiondown = 122, + grave = 123, + acute = 124, + circumflex = 125, + tilde = 126, + macron = 127, + breve = 128, + dotaccent = 129, + dieresis = 130, + ring = 131, + cedilla = 132, + hungarumlaut = 133, + ogonek = 134, + caron = 135, + emdash = 136, + AE = 137, + ordfeminine = 138, + Lslash = 139, + Oslash = 140, + OE = 141, + ordmasculine = 142, + ae = 143, + dotlessi = 144, + lslash = 145, + oslash = 146, + oe = 147, + germandbls = 148, + Aacute = 149, + Acircumflex = 150, + Adieresis = 151, + Agrave = 152, + Aring = 153, + Atilde = 154, + Ccedilla = 155, + Eacute = 156, + Ecircumflex = 157, + Edieresis = 158, + Egrave = 159, + Eth = 160, + Iacute = 161, + Icircumflex = 162, + Idieresis = 163, + Igrave = 164, + Ntilde = 165, + Oacute = 166, + Ocircumflex = 167, + Odieresis = 168, + Ograve = 169, + Otilde = 170, + Scaron = 171, + Thorn = 172, + Uacute = 173, + Ucircumflex = 174, + Udieresis = 175, + Ugrave = 176, + Yacute = 177, + Ydieresis = 178, + aacute = 179, + acircumflex = 180, + adieresis = 181, + agrave = 182, + aring = 183, + atilde = 184, + brokenbar = 185, + ccedilla = 186, + copyright = 187, + degree = 188, + divide = 189, + eacute = 190, + ecircumflex = 191, + edieresis = 192, + egrave = 193, + eth = 194, + iacute = 195, + icircumflex = 196, + idieresis = 197, + igrave = 198, + logicalnot = 199, + minus = 200, + multiply = 201, + ntilde = 202, + oacute = 203, + ocircumflex = 204, + odieresis = 205, + ograve = 206, + onehalf = 207, + onequarter = 208, + onesuperior = 209, + otilde = 210, + plusminus = 211, + registered = 212, + thorn = 213, + threequarters = 214, + threesuperior = 215, + trademark = 216, + twosuperior = 217, + uacute = 218, + ucircumflex = 219, + udieresis = 220, + ugrave = 221, + yacute = 222, + ydieresis = 223, + Alpha = 224, + Beta = 225, + Chi = 226, + Delta = 227, + Epsilon = 228, + Phi = 229, + Gamma = 230, + Eta = 231, + Iota = 232, + Kappa = 233, + Lambda = 234, + Mu = 235, + Nu = 236, + Omicron = 237, + Pi = 238, + Theta = 239, + Rho = 240, + Sigma = 241, + Tau = 242, + Upsilon = 243, + varUpsilon = 244, + Omega = 245, + Xi = 246, + Psi = 247, + Zeta = 248, + alpha = 249, + beta = 250, + chi = 251, + delta = 252, + epsilon = 253, + phi = 254, + varphi = 255, + gamma = 256, + eta = 257, + iota = 258, + kappa = 259, + lambda = 260, + mu = 261, + nu = 262, + omicron = 263, + pi = 264, + varpi = 265, + theta = 266, + vartheta = 267, + rho = 268, + sigma = 269, + varsigma = 270, + tau = 271, + upsilon = 272, + omega = 273, + xi = 274, + psi = 275, + zeta = 276, + nobrkspace = 277, + nobrkhyphen = 278, + lessequal = 279, + greaterequal = 280, + infinity = 281, + integral = 282, + notequal = 283, + radical = 284, + radicalex = 285, + approxequal = 286, + apple = 287, + partialdiff = 288, + opthyphen = 289, + formula = 290, + lozenge = 291, + universal = 292, + existential = 293, + suchthat = 294, + congruent = 295, + therefore = 296, + perpendicular = 297, + minute = 298, + club = 299, + diamond = 300, + heart = 301, + spade = 302, + arrowboth = 303, + arrowleft = 304, + arrowup = 305, + arrowright = 306, + arrowdown = 307, + second = 308, + proportional = 309, + equivalence = 310, + arrowvertex = 311, + arrowhorizex = 312, + carriagereturn = 313, + aleph = 314, + Ifraktur = 315, + Rfraktur = 316, + weierstrass = 317, + circlemultiply = 318, + circleplus = 319, + emptyset = 320, + intersection = 321, + union = 322, + propersuperset = 323, + reflexsuperset = 324, + notsubset = 325, + propersubset = 326, + reflexsubset = 327, + element = 328, + notelement = 329, + angle = 330, + gradient = 331, + product = 332, + logicaland = 333, + logicalor = 334, + arrowdblboth = 335, + arrowdblleft = 336, + arrowdblup = 337, + arrowdblright = 338, + arrowdbldown = 339, + angleleft = 340, + registersans = 341, + copyrightsans = 342, + trademarksans = 343, + angleright = 344, + mathplus = 345, + mathminus = 346, + mathasterisk = 347, + mathnumbersign = 348, + dotmath = 349, + mathequal = 350, + mathtilde = 351, + + MaxChar = 352 + } +} diff --git a/source/ShiftUI/RTF/StandardCharName.cs b/source/ShiftUI/RTF/StandardCharName.cs new file mode 100644 index 0000000..0ddcf4b --- /dev/null +++ b/source/ShiftUI/RTF/StandardCharName.cs @@ -0,0 +1,411 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +namespace ShiftUI.RTF { + +#if RTF_LIB + public +#else + internal +#endif + class StandardCharName { + public static string[] Names = { + "nothing", + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quoteright", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", + "bracketright", + "asciicircum", + "underscore", + "quoteleft", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", + "braceright", + "asciitilde", + "exclamdown", + "cent", + "sterling", + "fraction", + "yen", + "florin", + "section", + "currency", + "quotedblleft", + "guillemotleft", + "guilsinglleft", + "guilsinglright", + "fi", + "fl", + "endash", + "dagger", + "daggerdbl", + "periodcentered", + "paragraph", + "bullet", + "quotesinglbase", + "quotedblbase", + "quotedblright", + "guillemotright", + "ellipsis", + "perthousand", + "questiondown", + "grave", + "acute", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "dieresis", + "ring", + "cedilla", + "hungarumlaut", + "ogonek", + "caron", + "emdash", + "AE", + "ordfeminine", + "Lslash", + "Oslash", + "OE", + "ordmasculine", + "ae", + "dotlessi", + "lslash", + "oslash", + "oe", + "germandbls", + "Aacute", + "Acircumflex", + "Adieresis", + "Agrave", + "Aring", + "Atilde", + "Ccedilla", + "Eacute", + "Ecircumflex", + "Edieresis", + "Egrave", + "Eth", + "Iacute", + "Icircumflex", + "Idieresis", + "Igrave", + "Ntilde", + "Oacute", + "Ocircumflex", + "Odieresis", + "Ograve", + "Otilde", + "Scaron", + "Thorn", + "Uacute", + "Ucircumflex", + "Udieresis", + "Ugrave", + "Yacute", + "Ydieresis", + "aacute", + "acircumflex", + "adieresis", + "agrave", + "aring", + "atilde", + "brokenbar", + "ccedilla", + "copyright", + "degree", + "divide", + "eacute", + "ecircumflex", + "edieresis", + "egrave", + "eth", + "iacute", + "icircumflex", + "idieresis", + "igrave", + "logicalnot", + "minus", + "multiply", + "ntilde", + "oacute", + "ocircumflex", + "odieresis", + "ograve", + "onehalf", + "onequarter", + "onesuperior", + "otilde", + "plusminus", + "registered", + "thorn", + "threequarters", + "threesuperior", + "trademark", + "twosuperior", + "uacute", + "ucircumflex", + "udieresis", + "ugrave", + "yacute", + "ydieresis", + "Alpha", + "Beta", + "Chi", + "Delta", + "Epsilon", + "Phi", + "Gamma", + "Eta", + "Iota", + "Kappa", + "Lambda", + "Mu", + "Nu", + "Omicron", + "Pi", + "Theta", + "Rho", + "Sigma", + "Tau", + "Upsilon", + "varUpsilon", + "Omega", + "Xi", + "Psi", + "Zeta", + "alpha", + "beta", + "chi", + "delta", + "epsilon", + "phi", + "varphi", + "gamma", + "eta", + "iota", + "kappa", + "lambda", + "mu", + "nu", + "omicron", + "pi", + "varpi", + "theta", + "vartheta", + "rho", + "sigma", + "varsigma", + "tau", + "upsilon", + "omega", + "xi", + "psi", + "zeta", + "nobrkspace", + "nobrkhyphen", + "lessequal", + "greaterequal", + "infinity", + "integral", + "notequal", + "radical", + "radicalex", + "approxequal", + "apple", + "partialdiff", + "opthyphen", + "formula", + "lozenge", + "universal", + "existential", + "suchthat", + "congruent", + "therefore", + "perpendicular", + "minute", + "club", + "diamond", + "heart", + "spade", + "arrowboth", + "arrowleft", + "arrowup", + "arrowright", + "arrowdown", + "second", + "proportional", + "equivalence", + "arrowvertex", + "arrowhorizex", + "carriagereturn", + "aleph", + "Ifraktur", + "Rfraktur", + "weierstrass", + "circlemultiply", + "circleplus", + "emptyset", + "intersection", + "union", + "propersuperset", + "reflexsuperset", + "notsubset", + "propersubset", + "reflexsubset", + "element", + "notelement", + "angle", + "gradient", + "product", + "logicaland", + "logicalor", + "arrowdblboth", + "arrowdblleft", + "arrowdblup", + "arrowdblright", + "arrowdbldown", + "angleleft", + "registersans", + "copyrightsans", + "trademarksans", + "angleright", + "mathplus", + "mathminus", + "mathasterisk", + "mathnumbersign", + "dotmath", + "mathequal", + "mathtilde" + }; + + /// Lookup name by ID + public static string Name(int index) { + if ((index < 0) || (index >= Names.Length)) { + return string.Empty; + } + + return Names[index]; + } + + /// Lookup ID by name (e.g. mathtilde) + public static int ID(string name) { + for (int i=0; i < Names.Length; i++) { + if (name.Equals(Names[i])) { + return i; + } + } + return 0; + } + } +} diff --git a/source/ShiftUI/RTF/Style.cs b/source/ShiftUI/RTF/Style.cs new file mode 100644 index 0000000..db1182d --- /dev/null +++ b/source/ShiftUI/RTF/Style.cs @@ -0,0 +1,211 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE +using System; + +namespace ShiftUI.RTF { + +#if RTF_LIB + public +#else + internal +#endif + class Style { + #region Local Variables + public const int NoStyleNum = 222; + public const int NormalStyleNum = 0; + + private string name; + private StyleType type; + private bool additive; + private int num; + private int based_on; + private int next_par; + private bool expanding; + private StyleElement elements; + private Style next; + #endregion Local Variables + + #region Constructors + public Style(RTF rtf) { + num = -1; + type = StyleType.Paragraph; + based_on = NoStyleNum; + next_par = -1; + + lock (rtf) { + if (rtf.Styles == null) { + rtf.Styles = this; + } else { + Style s = rtf.Styles; + while (s.next != null) + s = s.next; + s.next = this; + } + } + } + #endregion // Constructors + + #region Properties + public string Name { + get { + return name; + } + + set { + name = value; + } + } + + public StyleType Type { + get { + return type; + } + + set { + type = value; + } + } + + public bool Additive { + get { + return additive; + } + + set { + additive = value; + } + } + + public int BasedOn { + get { + return based_on; + } + + set { + based_on = value; + } + } + + public StyleElement Elements { + get { + return elements; + } + + set { + elements = value; + } + } + + public bool Expanding { + get { + return expanding; + } + + set { + expanding = value; + } + } + + public int NextPar { + get { + return next_par; + } + + set { + next_par = value; + } + } + + public int Num { + get { + return num; + } + + set { + num = value; + } + } + #endregion // Properties + + #region Methods + public void Expand(RTF rtf) { + StyleElement se; + + if (num == -1) { + return; + } + + if (expanding) { + throw new Exception("Recursive style expansion"); + } + expanding = true; + + if (num != based_on) { + rtf.SetToken(TokenClass.Widget, Major.ParAttr, Minor.StyleNum, based_on, "\\s"); + rtf.RouteToken(); + } + + se = elements; + while (se != null) { + rtf.TokenClass = se.TokenClass; + rtf.Major = se.Major; + rtf.Minor = se.Minor; + rtf.Param = se.Param; + rtf.Text = se.Text; + rtf.RouteToken(); + } + + expanding = false; + } + + static public Style GetStyle(RTF rtf, int style_number) { + Style s; + + lock (rtf) { + s = GetStyle(rtf.Styles, style_number); + } + return s; + } + + static public Style GetStyle(Style start, int style_number) { + Style s; + + if (style_number == -1) { + return start; + } + + s = start; + + while ((s != null) && (s.num != style_number)) { + s = s.next; + } + return s; + } + #endregion // Methods + } +} diff --git a/source/ShiftUI/RTF/StyleElement.cs b/source/ShiftUI/RTF/StyleElement.cs new file mode 100644 index 0000000..7f80292 --- /dev/null +++ b/source/ShiftUI/RTF/StyleElement.cs @@ -0,0 +1,122 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +namespace ShiftUI.RTF { + +#if RTF_LIB + public +#else + internal +#endif + class StyleElement { + #region Local Variables + private TokenClass token_class; + private Major major; + private Minor minor; + private int param; + private string text; + private StyleElement next; + #endregion Local Variables + + #region Constructors + public StyleElement(Style s, TokenClass token_class, Major major, Minor minor, int param, string text) { + this.token_class = token_class; + this.major = major; + this.minor = minor; + this.param = param; + this.text = text; + + lock (s) { + if (s.Elements == null) { + s.Elements = this; + } else { + StyleElement se = s.Elements; + while (se.next != null) + se = se.next; + se.next = this; + } + } + } + #endregion // Constructors + + #region Properties + public TokenClass TokenClass { + get { + return token_class; + } + + set { + token_class = value; + } + } + + public Major Major { + get { + return major; + } + + set { + major = value; + } + } + + public Minor Minor { + get { + return minor; + } + + set { + minor = value; + } + } + + public int Param { + get { + return param; + } + + set { + param = value; + } + } + + public string Text { + get { + return text; + } + + set { + text = value; + } + } + #endregion // Properties + + #region Methods + #endregion // Methods + } +} diff --git a/source/ShiftUI/RTF/StyleType.cs b/source/ShiftUI/RTF/StyleType.cs new file mode 100644 index 0000000..76dd663 --- /dev/null +++ b/source/ShiftUI/RTF/StyleType.cs @@ -0,0 +1,41 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +namespace ShiftUI.RTF { + +#if RTF_LIB + public +#else + internal +#endif + enum StyleType { + Paragraph = 0, + Character = 1, + Section = 2 + } +} diff --git a/source/ShiftUI/RTF/TextMap.cs b/source/ShiftUI/RTF/TextMap.cs new file mode 100644 index 0000000..8c0a7b0 --- /dev/null +++ b/source/ShiftUI/RTF/TextMap.cs @@ -0,0 +1,440 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// This map is for convencience only, any app can create/use it's own +// StdCharCode -> table + +using System.Collections; + +namespace ShiftUI.RTF { + +#if RTF_LIB + public +#else + internal +#endif + class TextMap { + #region Local Variables + private string[] table; + #endregion // Local Variables + + #region Public Constructors + public TextMap() { + table = new string[(int)StandardCharCode.MaxChar]; + + for (int i = 0; i < (int)StandardCharCode.MaxChar; i++) { + table[i] = string.Empty; + } + } + #endregion // Public Constructors + + #region Public Instance Properties + internal string this[StandardCharCode c] { // FIXME - this should be public, if the whole namespace was public (ie standalone RTF parser) + get { + return table[(int)c]; + } + + set { + table[(int)c] = value; + } + } + + public string[] Table { + get { + return table; + } + } + #endregion // Public Instance Properties + + #region Public Static Methods + public static void SetupStandardTable(string[] table) + { + /* + table[(int)StandardCharCode.space] = " "; + table[(int)StandardCharCode.exclam] = "!"; + table[(int)StandardCharCode.quotedbl] = "\""; + table[(int)StandardCharCode.numbersign] = "#"; + table[(int)StandardCharCode.dollar] = "$"; + table[(int)StandardCharCode.percent] = "%"; + table[(int)StandardCharCode.ampersand] = "&"; + table[(int)StandardCharCode.quoteright] = "'"; + table[(int)StandardCharCode.parenleft] = "("; + table[(int)StandardCharCode.parenright] = ")"; + table[(int)StandardCharCode.asterisk] = "*"; + table[(int)StandardCharCode.plus] = "+"; + table[(int)StandardCharCode.comma] = ","; + table[(int)StandardCharCode.hyphen] = "-"; + table[(int)StandardCharCode.period] = "."; + table[(int)StandardCharCode.slash] = "/"; + table[(int)StandardCharCode.zero] = "0"; + table[(int)StandardCharCode.one] = "1"; + table[(int)StandardCharCode.two] = "2"; + table[(int)StandardCharCode.three] = "3"; + table[(int)StandardCharCode.four] = "4"; + table[(int)StandardCharCode.five] = "5"; + table[(int)StandardCharCode.six] = "6"; + table[(int)StandardCharCode.seven] = "7"; + table[(int)StandardCharCode.eight] = "8"; + table[(int)StandardCharCode.nine] = "9"; + table[(int)StandardCharCode.colon] = ":"; + table[(int)StandardCharCode.semicolon] = ";"; + table[(int)StandardCharCode.less] = "<"; + table[(int)StandardCharCode.equal] = "="; + table[(int)StandardCharCode.greater] = ">"; + table[(int)StandardCharCode.question] = "?"; + table[(int)StandardCharCode.at] = "@"; + table[(int)StandardCharCode.A] = "A"; + table[(int)StandardCharCode.B] = "B"; + table[(int)StandardCharCode.C] = "C"; + table[(int)StandardCharCode.D] = "D"; + table[(int)StandardCharCode.E] = "E"; + table[(int)StandardCharCode.F] = "F"; + table[(int)StandardCharCode.G] = "G"; + table[(int)StandardCharCode.H] = "H"; + table[(int)StandardCharCode.I] = "I"; + table[(int)StandardCharCode.J] = "J"; + table[(int)StandardCharCode.K] = "K"; + table[(int)StandardCharCode.L] = "L"; + table[(int)StandardCharCode.M] = "M"; + table[(int)StandardCharCode.N] = "N"; + table[(int)StandardCharCode.O] = "O"; + table[(int)StandardCharCode.P] = "P"; + table[(int)StandardCharCode.Q] = "Q"; + table[(int)StandardCharCode.R] = "R"; + table[(int)StandardCharCode.S] = "S"; + table[(int)StandardCharCode.T] = "T"; + table[(int)StandardCharCode.U] = "U"; + table[(int)StandardCharCode.V] = "V"; + table[(int)StandardCharCode.W] = "W"; + table[(int)StandardCharCode.X] = "X"; + table[(int)StandardCharCode.Y] = "Y"; + table[(int)StandardCharCode.Z] = "Z"; + table[(int)StandardCharCode.bracketleft] = "["; + table[(int)StandardCharCode.backslash] = "\\"; + table[(int)StandardCharCode.bracketright] = "]"; + table[(int)StandardCharCode.asciicircum] = "^"; + table[(int)StandardCharCode.underscore] = "_"; + table[(int)StandardCharCode.quoteleft] = "`"; + table[(int)StandardCharCode.a] = "a"; + table[(int)StandardCharCode.b] = "b"; + table[(int)StandardCharCode.c] = "c"; + table[(int)StandardCharCode.d] = "d"; + table[(int)StandardCharCode.e] = "e"; + table[(int)StandardCharCode.f] = "f"; + table[(int)StandardCharCode.g] = "g"; + table[(int)StandardCharCode.h] = "h"; + table[(int)StandardCharCode.i] = "i"; + table[(int)StandardCharCode.j] = "j"; + table[(int)StandardCharCode.k] = "k"; + table[(int)StandardCharCode.l] = "l"; + table[(int)StandardCharCode.m] = "m"; + table[(int)StandardCharCode.n] = "n"; + table[(int)StandardCharCode.o] = "o"; + table[(int)StandardCharCode.p] = "p"; + table[(int)StandardCharCode.q] = "q"; + table[(int)StandardCharCode.r] = "r"; + table[(int)StandardCharCode.s] = "s"; + table[(int)StandardCharCode.t] = "t"; + table[(int)StandardCharCode.u] = "u"; + table[(int)StandardCharCode.v] = "v"; + table[(int)StandardCharCode.w] = "w"; + table[(int)StandardCharCode.x] = "x"; + table[(int)StandardCharCode.y] = "y"; + table[(int)StandardCharCode.z] = "z"; + table[(int)StandardCharCode.braceleft] = "{"; + table[(int)StandardCharCode.bar] = "|"; + table[(int)StandardCharCode.braceright] = "}"; + table[(int)StandardCharCode.asciitilde] = "~"; + table[(int)StandardCharCode.AE] = "AE"; + table[(int)StandardCharCode.OE] = "OE"; + table[(int)StandardCharCode.acute] = "'"; + table[(int)StandardCharCode.ae] = "ae"; + table[(int)StandardCharCode.angleleft] = "<"; + table[(int)StandardCharCode.angleright] = ">"; + table[(int)StandardCharCode.arrowboth] = "<->"; + table[(int)StandardCharCode.arrowdblboth] = "<=>"; + table[(int)StandardCharCode.arrowdblleft] = "<="; + table[(int)StandardCharCode.arrowdblright] = "=>"; + table[(int)StandardCharCode.arrowleft] = "<-"; + table[(int)StandardCharCode.arrowright] = "->"; + table[(int)StandardCharCode.bullet] = "o"; + table[(int)StandardCharCode.cent] = "cent"; + table[(int)StandardCharCode.circumflex] = "^"; + table[(int)StandardCharCode.copyright] = "(c)"; + table[(int)StandardCharCode.copyrightsans] = "(c)"; + table[(int)StandardCharCode.degree] = "deg."; + table[(int)StandardCharCode.divide] = "/"; + table[(int)StandardCharCode.dotlessi] = "i"; + table[(int)StandardCharCode.ellipsis] = "..."; + table[(int)StandardCharCode.emdash] = "--"; + table[(int)StandardCharCode.endash] = "-"; + table[(int)StandardCharCode.fi] = "fi"; + table[(int)StandardCharCode.fl] = "fl"; + table[(int)StandardCharCode.fraction] = "/"; + table[(int)StandardCharCode.germandbls] = "ss"; + table[(int)StandardCharCode.grave] = "`"; + table[(int)StandardCharCode.greaterequal] = ">="; + table[(int)StandardCharCode.guillemotleft] = "<<"; + table[(int)StandardCharCode.guillemotright] = ">>"; + table[(int)StandardCharCode.guilsinglleft] = "<"; + table[(int)StandardCharCode.guilsinglright] = ">"; + table[(int)StandardCharCode.lessequal] = "<="; + table[(int)StandardCharCode.logicalnot] = "~"; + table[(int)StandardCharCode.mathasterisk] = "*"; + table[(int)StandardCharCode.mathequal] = "="; + table[(int)StandardCharCode.mathminus] = "-"; + table[(int)StandardCharCode.mathnumbersign] = "#"; + table[(int)StandardCharCode.mathplus] = "+"; + table[(int)StandardCharCode.mathtilde] = "~"; + table[(int)StandardCharCode.minus] = "-"; + table[(int)StandardCharCode.mu] = "u"; + table[(int)StandardCharCode.multiply] = "x"; + table[(int)StandardCharCode.nobrkhyphen] = "-"; + table[(int)StandardCharCode.nobrkspace] = ""; + table[(int)StandardCharCode.notequal] = "!="; + table[(int)StandardCharCode.oe] = "oe"; + table[(int)StandardCharCode.onehalf] = "1/2"; + table[(int)StandardCharCode.onequarter] = "1/4"; + table[(int)StandardCharCode.periodcentered] = "."; + table[(int)StandardCharCode.plusminus] = "+/-"; + table[(int)StandardCharCode.quotedblbase] = ",,"; + table[(int)StandardCharCode.quotedblleft] = "\""; + table[(int)StandardCharCode.quotedblright] = "\""; + table[(int)StandardCharCode.quotesinglbase] = ","; + table[(int)StandardCharCode.registered] = "reg."; + table[(int)StandardCharCode.registersans] = "reg."; + table[(int)StandardCharCode.threequarters] = "3/4"; + table[(int)StandardCharCode.tilde] = "~"; + table[(int)StandardCharCode.trademark] = "(TM)"; + table[(int)StandardCharCode.trademarksans] = "(TM)"; + + table[(int)StandardCharCode.aacute] = "\xE0"; + table[(int)StandardCharCode.questiondown] = "\xBF"; + + table[(int)StandardCharCode.udieresis] = "\xFC"; + table[(int)StandardCharCode.Udieresis] = "\xDC"; + table[(int)StandardCharCode.odieresis] = "\xF6"; + table[(int)StandardCharCode.Odieresis] = "\xD6"; + */ + + table [(int) StandardCharCode.formula] = "\x6"; + table [(int) StandardCharCode.nobrkhyphen] = "\x1e"; + table [(int) StandardCharCode.opthyphen] = "\x1f"; + table [(int) StandardCharCode.space] = " "; + table [(int) StandardCharCode.exclam] = "!"; + table [(int) StandardCharCode.quotedbl] = "\""; + table [(int) StandardCharCode.numbersign] = "#"; + table [(int) StandardCharCode.dollar] = "$"; + table [(int) StandardCharCode.percent] = "%"; + table [(int) StandardCharCode.ampersand] = "&"; + table [(int) StandardCharCode.parenleft] = "("; + table [(int) StandardCharCode.parenright] = ")"; + table [(int) StandardCharCode.asterisk] = "*"; + table [(int) StandardCharCode.plus] = "+"; + table [(int) StandardCharCode.comma] = ","; + table [(int) StandardCharCode.hyphen] = "-"; + table [(int) StandardCharCode.period] = "."; + table [(int) StandardCharCode.slash] = "/"; + table [(int) StandardCharCode.zero] = "0"; + table [(int) StandardCharCode.one] = "1"; + table [(int) StandardCharCode.two] = "2"; + table [(int) StandardCharCode.three] = "3"; + table [(int) StandardCharCode.four] = "4"; + table [(int) StandardCharCode.five] = "5"; + table [(int) StandardCharCode.six] = "6"; + table [(int) StandardCharCode.seven] = "7"; + table [(int) StandardCharCode.eight] = "8"; + table [(int) StandardCharCode.nine] = "9"; + table [(int) StandardCharCode.colon] = ":"; + table [(int) StandardCharCode.semicolon] = ";"; + table [(int) StandardCharCode.less] = "<"; + table [(int) StandardCharCode.equal] = "="; + table [(int) StandardCharCode.greater] = ">"; + table [(int) StandardCharCode.question] = "?"; + table [(int) StandardCharCode.at] = "@"; + table [(int) StandardCharCode.A] = "A"; + table [(int) StandardCharCode.B] = "B"; + table [(int) StandardCharCode.C] = "C"; + table [(int) StandardCharCode.D] = "D"; + table [(int) StandardCharCode.E] = "E"; + table [(int) StandardCharCode.F] = "F"; + table [(int) StandardCharCode.G] = "G"; + table [(int) StandardCharCode.H] = "H"; + table [(int) StandardCharCode.I] = "I"; + table [(int) StandardCharCode.J] = "J"; + table [(int) StandardCharCode.K] = "K"; + table [(int) StandardCharCode.L] = "L"; + table [(int) StandardCharCode.M] = "M"; + table [(int) StandardCharCode.N] = "N"; + table [(int) StandardCharCode.O] = "O"; + table [(int) StandardCharCode.P] = "P"; + table [(int) StandardCharCode.Q] = "Q"; + table [(int) StandardCharCode.R] = "R"; + table [(int) StandardCharCode.S] = "S"; + table [(int) StandardCharCode.T] = "T"; + table [(int) StandardCharCode.U] = "U"; + table [(int) StandardCharCode.V] = "V"; + table [(int) StandardCharCode.W] = "W"; + table [(int) StandardCharCode.X] = "X"; + table [(int) StandardCharCode.Y] = "Y"; + table [(int) StandardCharCode.Z] = "Z"; + table [(int) StandardCharCode.bracketleft] = "["; + table [(int) StandardCharCode.backslash] = "\\"; + table [(int) StandardCharCode.bracketright] = "]"; + table [(int) StandardCharCode.asciicircum] = "^"; + table [(int) StandardCharCode.underscore] = "_"; + table [(int) StandardCharCode.quoteleft] = "`"; + table [(int) StandardCharCode.a] = "a"; + table [(int) StandardCharCode.b] = "b"; + table [(int) StandardCharCode.c] = "c"; + table [(int) StandardCharCode.d] = "d"; + table [(int) StandardCharCode.e] = "e"; + table [(int) StandardCharCode.f] = "f"; + table [(int) StandardCharCode.g] = "g"; + table [(int) StandardCharCode.h] = "h"; + table [(int) StandardCharCode.i] = "i"; + table [(int) StandardCharCode.j] = "j"; + table [(int) StandardCharCode.k] = "k"; + table [(int) StandardCharCode.l] = "l"; + table [(int) StandardCharCode.m] = "m"; + table [(int) StandardCharCode.n] = "n"; + table [(int) StandardCharCode.o] = "o"; + table [(int) StandardCharCode.p] = "p"; + table [(int) StandardCharCode.q] = "q"; + table [(int) StandardCharCode.r] = "r"; + table [(int) StandardCharCode.s] = "s"; + table [(int) StandardCharCode.t] = "t"; + table [(int) StandardCharCode.u] = "u"; + table [(int) StandardCharCode.v] = "v"; + table [(int) StandardCharCode.w] = "w"; + table [(int) StandardCharCode.x] = "x"; + table [(int) StandardCharCode.y] = "y"; + table [(int) StandardCharCode.z] = "z"; + table [(int) StandardCharCode.braceleft] = "{"; + table [(int) StandardCharCode.bar] = "|"; + table [(int) StandardCharCode.braceright] = "}"; + table [(int) StandardCharCode.asciitilde] = "~"; + table [(int) StandardCharCode.nobrkspace] = "\xa0"; + table [(int) StandardCharCode.exclamdown] = "\xa1"; + table [(int) StandardCharCode.cent] = "\xa2"; + table [(int) StandardCharCode.sterling] = "\xa3"; + table [(int) StandardCharCode.currency] = "\xa4"; + table [(int) StandardCharCode.yen] = "\xa5"; + table [(int) StandardCharCode.brokenbar] = "\xa6"; + table [(int) StandardCharCode.section] = "\xa7"; + table [(int) StandardCharCode.dieresis] = "\xa8"; + table [(int) StandardCharCode.copyright] = "\xa9"; + table [(int) StandardCharCode.ordfeminine] = "\xaa"; + table [(int) StandardCharCode.guillemotleft] = "\xab"; + table [(int) StandardCharCode.logicalnot] = "\xac"; + table [(int) StandardCharCode.opthyphen] = "\xad"; + table [(int) StandardCharCode.registered] = "\xae"; + table [(int) StandardCharCode.macron] = "\xaf"; + table [(int) StandardCharCode.degree] = "\xb0"; + table [(int) StandardCharCode.plusminus] = "\xb1"; + table [(int) StandardCharCode.twosuperior] = "\xb2"; + table [(int) StandardCharCode.threesuperior] = "\xb3"; + table [(int) StandardCharCode.acute] = "\xb4"; + table [(int) StandardCharCode.mu] = "\xb5"; + table [(int) StandardCharCode.paragraph] = "\xb6"; + table [(int) StandardCharCode.periodcentered] = "\xb7"; + table [(int) StandardCharCode.cedilla] = "\xb8"; + table [(int) StandardCharCode.onesuperior] = "\xb9"; + table [(int) StandardCharCode.ordmasculine] = "\xba"; + table [(int) StandardCharCode.guillemotright] = "\xbb"; + table [(int) StandardCharCode.onequarter] = "\xbc"; + table [(int) StandardCharCode.onehalf] = "\xbd"; + table [(int) StandardCharCode.threequarters] = "\xbe"; + table [(int) StandardCharCode.questiondown] = "\xbf"; + table [(int) StandardCharCode.Agrave] = "\xc0"; + table [(int) StandardCharCode.Aacute] = "\xc1"; + table [(int) StandardCharCode.Acircumflex] = "\xc2"; + table [(int) StandardCharCode.Atilde] = "\xc3"; + table [(int) StandardCharCode.Adieresis] = "\xc4"; + table [(int) StandardCharCode.Aring] = "\xc5"; + table [(int) StandardCharCode.AE] = "\xc6"; + table [(int) StandardCharCode.Ccedilla] = "\xc7"; + table [(int) StandardCharCode.Egrave] = "\xc8"; + table [(int) StandardCharCode.Eacute] = "\xc9"; + table [(int) StandardCharCode.Ecircumflex] = "\xca"; + table [(int) StandardCharCode.Edieresis] = "\xcb"; + table [(int) StandardCharCode.Igrave] = "\xcc"; + table [(int) StandardCharCode.Iacute] = "\xcd"; + table [(int) StandardCharCode.Icircumflex] = "\xce"; + table [(int) StandardCharCode.Idieresis] = "\xcf"; + table [(int) StandardCharCode.Eth] = "\xd0"; + table [(int) StandardCharCode.Ntilde] = "\xd1"; + table [(int) StandardCharCode.Ograve] = "\xd2"; + table [(int) StandardCharCode.Oacute] = "\xd3"; + table [(int) StandardCharCode.Ocircumflex] = "\xd4"; + table [(int) StandardCharCode.Otilde] = "\xd5"; + table [(int) StandardCharCode.Odieresis] = "\xd6"; + table [(int) StandardCharCode.multiply] = "\xd7"; + table [(int) StandardCharCode.Oslash] = "\xd8"; + table [(int) StandardCharCode.Ugrave] = "\xd9"; + table [(int) StandardCharCode.Uacute] = "\xda"; + table [(int) StandardCharCode.Ucircumflex] = "\xdb"; + table [(int) StandardCharCode.Udieresis] = "\xdc"; + table [(int) StandardCharCode.Yacute] = "\xdd"; + table [(int) StandardCharCode.Thorn] = "\xde"; + table [(int) StandardCharCode.germandbls] = "\xdf"; + table [(int) StandardCharCode.agrave] = "\xe0"; + table [(int) StandardCharCode.aacute] = "\xe1"; + table [(int) StandardCharCode.acircumflex] = "\xe2"; + table [(int) StandardCharCode.atilde] = "\xe3"; + table [(int) StandardCharCode.adieresis] = "\xe4"; + table [(int) StandardCharCode.aring] = "\xe5"; + table [(int) StandardCharCode.ae] = "\xe6"; + table [(int) StandardCharCode.ccedilla] = "\xe7"; + table [(int) StandardCharCode.egrave] = "\xe8"; + table [(int) StandardCharCode.eacute] = "\xe9"; + table [(int) StandardCharCode.ecircumflex] = "\xea"; + table [(int) StandardCharCode.edieresis] = "\xeb"; + table [(int) StandardCharCode.igrave] = "\xec"; + table [(int) StandardCharCode.iacute] = "\xed"; + table [(int) StandardCharCode.icircumflex] = "\xee"; + table [(int) StandardCharCode.idieresis] = "\xef"; + table [(int) StandardCharCode.eth] = "\xf0"; + table [(int) StandardCharCode.ntilde] = "\xf1"; + table [(int) StandardCharCode.ograve] = "\xf2"; + table [(int) StandardCharCode.oacute] = "\xf3"; + table [(int) StandardCharCode.ocircumflex] = "\xf4"; + table [(int) StandardCharCode.otilde] = "\xf5"; + table [(int) StandardCharCode.odieresis] = "\xf6"; + table [(int) StandardCharCode.divide] = "\xf7"; + table [(int) StandardCharCode.oslash] = "\xf8"; + table [(int) StandardCharCode.ugrave] = "\xf9"; + table [(int) StandardCharCode.uacute] = "\xfa"; + table [(int) StandardCharCode.ucircumflex] = "\xfb"; + table [(int) StandardCharCode.udieresis] = "\xfc"; + table [(int) StandardCharCode.yacute] = "\xfd"; + table [(int) StandardCharCode.thorn] = "\xfe"; + table [(int) StandardCharCode.ydieresis] = "\xff"; + + } + #endregion // Public Static Methods + } +} diff --git a/source/ShiftUI/RTF/TokenClass.cs b/source/ShiftUI/RTF/TokenClass.cs new file mode 100644 index 0000000..2a1014d --- /dev/null +++ b/source/ShiftUI/RTF/TokenClass.cs @@ -0,0 +1,45 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok (pbartok@novell.com) +// +// + +// COMPLETE + +namespace ShiftUI.RTF { + +#if RTF_LIB + public +#else + internal +#endif + enum TokenClass { + None = -1, + Unknown = 0, + Group = 1, + Text = 2, + Widget = 3, + EOF = 4, + MaxClass = 5 + } +} diff --git a/source/ShiftUI/RTF/rtf.csproj b/source/ShiftUI/RTF/rtf.csproj new file mode 100644 index 0000000..4cb3e58 --- /dev/null +++ b/source/ShiftUI/RTF/rtf.csproj @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/ShiftUI/RTF/test.cs b/source/ShiftUI/RTF/test.cs new file mode 100644 index 0000000..b8c0f3c --- /dev/null +++ b/source/ShiftUI/RTF/test.cs @@ -0,0 +1,285 @@ +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.Drawing.Text; +using ShiftUI; +using System.Text; +using System.Threading; +using ShiftUI.RTF; +using System.IO; + +namespace TextTestClass { + public class Test { + static Test test; + int skip_width; + int skip_count; + private string rtf_string = "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fnil\\fcharset0 Microsoft Sans Serif;}}\r\n\\viewkind4\\uc1\\pard\\f0\\fs17 testing 123testiong\\par\r\n}"; + private string rtf_string2 = "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fswiss\\fcharset0 Arial;}{\\f1\\fmodern\\fprq1\\fcharset0 Courier;}{\\f2\\fswiss\\fprq2\\fcharset0 Arial;}}\r\n" + + "{\\colortbl ;\\red255\\green0\\blue0;\\red0\\green0\\blue0;}\r\n" + + "{\\*\\generator Msftedit 5.41.15.1507;}\\viewkind4\\uc1\\pard\\f0\\fs20 I am in Arial 10pt\\par\r\n" + + "\\fs24 I am in Arial 12pt\\par\r\n" + + "\\f1 I am in Courier 12pt\\par\r\n" + + "\\cf1 I am in Courier 12pt Red\\par\r\n" + + "\\cf2\\f2\\fs20 I am in Arial 10pt\\par\r\n" + + "\\b I am in Arial 10pt Italic\\cf0\\b0\\f0\\par\r\n" + + "}"; + private string rtf_string3 = "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fswiss\\fcharset0 Arial;}{" + + "\\f1\\fmodern\\fprq1\\fcharset0 Courier;}{\\f2\\fswiss\\fprq2\\fcharset0 Arial;}{\\f3\\fni" + + "l\\fcharset0 Impact;}{\\f4\\fnil\\fcharset0 Arial Unicode MS;}{\\f5\\fnil\\fcharset136 Arial Unicode MS;}{\\f6\\fnil\\fcharset0 MS" + + " Shell Dlg;}}" + + "{\\colortbl ;\\red255\\green0\\blue0;\\red0\\green0\\blue0;}" + + "{\\*\\generator Msftedit 5.41.15.1507;}\\viewkind4\\uc1\\pard\\f0\\fs20 I am in Arial 1" + + "0pt\\par" + + "\\fs24 I am in Arial 12pt\\par" + + "\\f1 I am in Courier 12pt\\par" + + "\\cf1 I am in Courier 12pt Red\\par" + + "\\cf2\\f2\\fs20 I am in Arial 10pt\\par" + + "\\b I am in Arial 10pt Bold\\par" + + "\\i I am in Arial 10pt Bold Italic\\par" + + "\\ul I am in Arial 10pt Bold Italic Underline\\par" + + "\\ulnone\\b0\\i0\\strike I am in Arial 10pt Strikethrough\\par" + + "\\cf0\\strike0\\f3\\fs23 Some cyrilic character: \\u1034?\\par" + + "And 5 CJK characters: \\f4\\fs21\\u23854?\\u23854?\\u23854?\\u23854?\\u23854?\\f5\\fs17\\par" + + "Some special chars:\\par" + + "\\tab Tilde: ~\\par" + + "\\tab Questionmark:?\\par" + + "\\tab Yen: \\f5\\u165?\\f6\\fs17\\par" + + "\\tab Umlaut: \\'e4\\par" + + "\\f0\\fs20\\par" + + "}"; + + TextMap text; + + public Test() { + MemoryStream stream; + RTF rtf; + byte[] buffer; + + text = new TextMap(); + TextMap.SetupStandardTable(text.Table); + + buffer = new byte[rtf_string.Length]; + for (int i = 0; i < buffer.Length; i++) { + buffer[i] = (byte)rtf_string[i]; + } + stream = new MemoryStream(buffer); + rtf = new RTF(stream); + + skip_width = 0; + skip_count = 0; + + rtf.ClassCallback[TokenClass.Text] = new ClassDelegate(HandleText); + rtf.ClassCallback[TokenClass.Widget] = new ClassDelegate(HandleControl); + + rtf.Read(); + + stream.Close(); + } + + void HandleControl(RTF rtf) { + switch(rtf.Major) { + case Major.Unicode: { + switch(rtf.Minor) { + case Minor.UnicodeCharBytes: { + skip_width = rtf.Param; + break; + } + + case Minor.UnicodeChar: { + Console.Write("[Unicode {0:X4}]", rtf.Param); + skip_count += skip_width; + break; + } + } + break; + } + + case Major.Destination: { + Console.Write("[Got Destination control {0}]", rtf.Minor); + rtf.SkipGroup(); + break; + } + + case Major.CharAttr: { + switch(rtf.Minor) { + case Minor.ForeColor: { + ShiftUI.RTF.Color color; + + color = ShiftUI.RTF.Color.GetColor(rtf, rtf.Param); + if (color != null) { + if (color.Red == -1 && color.Green == -1 && color.Blue == -1) { + Console.Write("[Default Color]"); + } else { + Console.Write("[Color {0} [{1:X2}{2:X2}{3:X}]]", rtf.Param, color.Red, color.Green, color.Blue); + } + } + break; + } + + case Minor.FontSize: { + Console.Write("[Fontsize {0}]", rtf.Param); + break; + } + + case Minor.FontNum: { + ShiftUI.RTF.Font font; + + font = ShiftUI.RTF.Font.GetFont(rtf, rtf.Param); + if (font != null) { + Console.Write("[Font {0} [{1}]]", rtf.Param, font.Name); + } + break; + } + + case Minor.Plain: { + Console.Write("[Normal]"); + break; + } + + case Minor.Bold: { + if (rtf.Param == RTF.NoParam) { + Console.Write("[Bold]"); + } else { + Console.Write("[NoBold]"); + } + break; + } + + case Minor.Italic: { + if (rtf.Param == RTF.NoParam) { + Console.Write("[Italic]"); + } else { + Console.Write("[NoItalic]"); + } + break; + } + + case Minor.StrikeThru: { + if (rtf.Param == RTF.NoParam) { + Console.Write("[StrikeThru]"); + } else { + Console.Write("[NoStrikeThru]"); + } + break; + } + + case Minor.Underline: { + if (rtf.Param == RTF.NoParam) { + Console.Write("[Underline]"); + } else { + Console.Write("[NoUnderline]"); + } + break; + } + + case Minor.NoUnderline: { + Console.Write("[NoUnderline]"); + break; + } + } + break; + } + + case Major.SpecialChar: { + Console.Write("[Got SpecialChar control {0}]", rtf.Minor); + SpecialChar(rtf); + break; + } + } + } + + void SpecialChar(RTF rtf) { + switch(rtf.Minor) { + case Minor.Page: + case Minor.Sect: + case Minor.Row: + case Minor.Line: + case Minor.Par: { + Console.Write("\n"); + break; + } + + case Minor.Cell: { + Console.Write(" "); + break; + } + + case Minor.NoBrkSpace: { + Console.Write(" "); + break; + } + + case Minor.Tab: { + Console.Write("\t"); + break; + } + + case Minor.NoBrkHyphen: { + Console.Write("-"); + break; + } + + case Minor.Bullet: { + Console.Write("*"); + break; + } + + case Minor.EmDash: { + Console.Write("—"); + break; + } + + case Minor.EnDash: { + Console.Write("–"); + break; + } + + case Minor.LQuote: { + Console.Write("‘"); + break; + } + + case Minor.RQuote: { + Console.Write("’"); + break; + } + + case Minor.LDblQuote: { + Console.Write("“"); + break; + } + + case Minor.RDblQuote: { + Console.Write("”"); + break; + } + + default: { + rtf.SkipGroup(); + break; + } + } + } + + + void HandleText(RTF rtf) { + if (skip_count > 0) { + skip_count--; + return; + } + if ((StandardCharCode)rtf.Minor != StandardCharCode.nothing) { + Console.Write("{0}", text[(StandardCharCode)rtf.Minor]); + } else { + if ((int)rtf.Major > 31 && (int)rtf.Major < 128) { + Console.Write("{0}", (char)rtf.Major); + } else { + Console.Write("[Literal:0x{0:X2}]", (int)rtf.Major); + } + } + } + + public static void Main() { + test = new Test(); + } + } +} diff --git a/source/ShiftUI/Resources/DnDCopy.cur b/source/ShiftUI/Resources/DnDCopy.cur new file mode 100644 index 0000000..99b5574 Binary files /dev/null and b/source/ShiftUI/Resources/DnDCopy.cur differ diff --git a/source/ShiftUI/Resources/DnDLink.cur b/source/ShiftUI/Resources/DnDLink.cur new file mode 100644 index 0000000..3ba787a Binary files /dev/null and b/source/ShiftUI/Resources/DnDLink.cur differ diff --git a/source/ShiftUI/Resources/DnDMove.cur b/source/ShiftUI/Resources/DnDMove.cur new file mode 100644 index 0000000..0150e0e Binary files /dev/null and b/source/ShiftUI/Resources/DnDMove.cur differ diff --git a/source/ShiftUI/Resources/DnDNo.cur b/source/ShiftUI/Resources/DnDNo.cur new file mode 100644 index 0000000..b002e96 Binary files /dev/null and b/source/ShiftUI/Resources/DnDNo.cur differ diff --git a/source/ShiftUI/Resources/NESW.cur b/source/ShiftUI/Resources/NESW.cur new file mode 100644 index 0000000..40c26e1 Binary files /dev/null and b/source/ShiftUI/Resources/NESW.cur differ diff --git a/source/ShiftUI/Resources/NWSE.cur b/source/ShiftUI/Resources/NWSE.cur new file mode 100644 index 0000000..da7003f Binary files /dev/null and b/source/ShiftUI/Resources/NWSE.cur differ diff --git a/source/ShiftUI/Resources/SplitterNS.cur b/source/ShiftUI/Resources/SplitterNS.cur new file mode 100644 index 0000000..2f32171 Binary files /dev/null and b/source/ShiftUI/Resources/SplitterNS.cur differ diff --git a/source/ShiftUI/Resources/SplitterWE.cur b/source/ShiftUI/Resources/SplitterWE.cur new file mode 100644 index 0000000..64fa72d Binary files /dev/null and b/source/ShiftUI/Resources/SplitterWE.cur differ diff --git a/source/ShiftUI/Resources/keyboard_table.bin b/source/ShiftUI/Resources/keyboard_table.bin new file mode 100644 index 0000000..45d1c35 --- /dev/null +++ b/source/ShiftUI/Resources/keyboard_table.bin @@ -0,0 +1 @@ +AAEAAAD/////AQAAAAAAAAAMAgAAAEdjcmVhdGUta2V5Ym9hcmRzLCBWZXJzaW9uPTAuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAcBAAAAAAEAAABAAAAABCNTeXN0ZW0uV2luZG93cy5Gb3Jtcy5LZXlib2FyZExheW91dAIAAAAJAwAAAAkEAAAACQUAAAAJBgAAAAkHAAAACQgAAAAJCQAAAAkKAAAACQsAAAAJDAAAAAkNAAAACQ4AAAAJDwAAAAkQAAAACREAAAAJEgAAAAkTAAAACRQAAAAJFQAAAAkWAAAACRcAAAAJGAAAAAkZAAAACRoAAAAJGwAAAAkcAAAACR0AAAAJHgAAAAkfAAAACSAAAAAJIQAAAAkiAAAACSMAAAAJJAAAAAklAAAACSYAAAAJJwAAAAkoAAAACSkAAAAJKgAAAAkrAAAACSwAAAAJLQAAAAkuAAAACS8AAAAJMAAAAAkxAAAACTIAAAAJMwAAAAk0AAAACTUAAAAJNgAAAAk3AAAACTgAAAAJOQAAAAk6AAAACTsAAAAJPAAAAAk9AAAACT4AAAAJPwAAAAlAAAAACUEAAAAJQgAAAAUDAAAAI1N5c3RlbS5XaW5kb3dzLkZvcm1zLktleWJvYXJkTGF5b3V0BQAAAARMY2lkBE5hbWUJU2NhbkluZGV4CVZLZXlJbmRleARLZXlzAAEEBAMII1N5c3RlbS5XaW5kb3dzLkZvcm1zLlNjYW5UYWJsZUluZGV4AgAAACNTeXN0ZW0uV2luZG93cy5Gb3Jtcy5WS2V5VGFibGVJbmRleAIAAAARU3lzdGVtLlVJbnQzMltdW10CAAAACQQAAAZDAAAAHVVuaXRlZCBTdGF0ZXMga2V5Ym9hcmQgbGF5b3V0Bbz///8jU3lzdGVtLldpbmRvd3MuRm9ybXMuU2NhblRhYmxlSW5kZXgBAAAAB3ZhbHVlX18ACAIAAAAAAAAABbv///8jU3lzdGVtLldpbmRvd3MuRm9ybXMuVktleVRhYmxlSW5kZXgBAAAAB3ZhbHVlX18ACAIAAAAAAAAACUYAAAABBAAAAAMAAAAJBAAABkcAAAAzVW5pdGVkIFN0YXRlcyBrZXlib2FyZCBsYXlvdXQgKHBoYW50b20ga2V5IHZlcnNpb24pAbj///+8////AAAAAAG3////u////wAAAAAJSgAAAAEFAAAAAwAAAAkEAAAGSwAAACZVbml0ZWQgU3RhdGVzIGtleWJvYXJkIGxheW91dCAoZHZvcmFrKQG0////vP///wEAAAABs////7v///8CAAAACU4AAAABBgAAAAMAAAAJBAAABk8AAAArVW5pdGVkIFN0YXRlcyBJbnRlcm5hdGlvbmFsIGtleWJvYXJkIGxheW91dAGw////vP///wAAAAABr////7v///8AAAAACVIAAAABBwAAAAMAAAAJCAAABlMAAAAXQnJpdGlzaCBrZXlib2FyZCBsYXlvdXQBrP///7z///8AAAAAAav///+7////AAAAAAlWAAAAAQgAAAADAAAABwQAAAZXAAAAFkdlcm1hbiBrZXlib2FyZCBsYXlvdXQBqP///7z///8AAAAAAaf///+7////AQAAAAlaAAAAAQkAAAADAAAABwQAAAZbAAAAKEdlcm1hbiBrZXlib2FyZCBsYXlvdXQgd2l0aG91dCBkZWFkIGtleXMBpP///7z///8AAAAAAaP///+7////AQAAAAleAAAAAQoAAAADAAAABwQAAAZfAAAAL0dlcm1hbiBrZXlib2FyZCBsYXlvdXQgZm9yIGxvZ2l0ZWNoIGRlc2t0b3AgcHJvAaD///+8////AAAAAAGf////u////wEAAAAJYgAAAAELAAAAAwAAAAcEAAAGYwAAACxHZXJtYW4ga2V5Ym9hcmQgbGF5b3V0IHdpdGhvdXQgZGVhZCBrZXlzIDEwNQGc////vP///wAAAAABm////7v///8DAAAACWYAAAABDAAAAAMAAAAHCAAABmcAAAAcU3dpc3MgR2VybWFuIGtleWJvYXJkIGxheW91dAGY////vP///wAAAAABl////7v///8BAAAACWoAAAABDQAAAAMAAAAMEAAABmsAAAAcU3dpc3MgRnJlbmNoIGtleWJvYXJkIGxheW91dAGU////vP///wAAAAABk////7v///8BAAAACW4AAAABDgAAAAMAAAAdBAAABm8AAAAXU3dlZGlzaCBrZXlib2FyZCBsYXlvdXQBkP///7z///8AAAAAAY////+7////BQAAAAlyAAAAAQ8AAAADAAAAJQQAAAZzAAAAGEVzdG9uaWFuIGtleWJvYXJkIGxheW91dAGM////vP///wAAAAABi////7v///8AAAAACXYAAAABEAAAAAMAAAAUBAAABncAAAAZTm9yd2VnaWFuIGtleWJvYXJkIGxheW91dAGI////vP///wAAAAABh////7v///8AAAAACXoAAAABEQAAAAMAAAAGBAAABnsAAAAWRGFuaXNoIGtleWJvYXJkIGxheW91dAGE////vP///wAAAAABg////7v///8AAAAACX4AAAABEgAAAAMAAAAMBAAABn8AAAAWRnJlbmNoIGtleWJvYXJkIGxheW91dAGA////vP///wAAAAABf////7v///8EAAAACYIAAAABEwAAAAMAAAAMDAAABoMAAAAfQ2FuYWRpYW4gRnJlbmNoIGtleWJvYXJkIGxheW91dAF8////vP///wAAAAABe////7v///8AAAAACYYAAAABFAAAAAMAAAAMDAAABocAAAAnQ2FuYWRpYW4gRnJlbmNoIGtleWJvYXJkIGxheW91dCAoQ0FfZnIpAXj///+8////AAAAAAF3////u////wAAAAAJigAAAAEVAAAAAwAAAAwMAAAGiwAAABhDYW5hZGlhbiBrZXlib2FyZCBsYXlvdXQBdP///7z///8AAAAAAXP///+7////AAAAAAmOAAAAARYAAAADAAAADAgAAAaPAAAAF0JlbGdpYW4ga2V5Ym9hcmQgbGF5b3V0AXD///+8////AAAAAAFv////u////wQAAAAJkgAAAAEXAAAAAwAAABYIAAAGkwAAABpQb3J0dWd1ZXNlIGtleWJvYXJkIGxheW91dAFs////vP///wAAAAABa////7v///8AAAAACZYAAAABGAAAAAMAAAAWBAAABpcAAAAgQnJhemlsaWFuIEFCTlQtMiBrZXlib2FyZCBsYXlvdXQBaP///7z///8CAAAAAWf///+7////BgAAAAmaAAAAARkAAAADAAAAFgQAAAabAAAAJ0JyYXppbGlhbiBBQk5ULTIga2V5Ym9hcmQgbGF5b3V0IEFMVCBHUgFk////vP///wIAAAABY////7v///8GAAAACZ4AAAABGgAAAAMAAAALBAAABp8AAAAXRmlubmlzaCBrZXlib2FyZCBsYXlvdXQBYP///7z///8AAAAAAV////+7////AAAAAAmiAAAAARsAAAADAAAAAgQAAAajAAAAHUJ1bGdhcmlhbiBiZHMga2V5Ym9hcmQgbGF5b3V0AVz///+8////AAAAAAFb////u////wAAAAAJpgAAAAEcAAAAAwAAAAIEAAAGpwAAACJCdWxnYXJpYW4gcGhvbmV0aWMga2V5Ym9hcmQgbGF5b3V0AVj///+8////AAAAAAFX////u////wAAAAAJqgAAAAEdAAAAAwAAACMEAAAGqwAAABpCZWxhcnVzaWFuIGtleWJvYXJkIGxheW91dAFU////vP///wAAAAABU////7v///8AAAAACa4AAAABHgAAAAMAAAAZBAAABq8AAAAXUnVzc2lhbiBrZXlib2FyZCBsYXlvdXQBUP///7z///8AAAAAAU////+7////AAAAAAmyAAAAAR8AAAADAAAAGQQAAAazAAAALVJ1c3NpYW4ga2V5Ym9hcmQgbGF5b3V0IChwaGFudG9tIGtleSB2ZXJzaW9uKQFM////vP///wAAAAABS////7v///8AAAAACbYAAAABIAAAAAMAAAAZBAAABrcAAAAeUnVzc2lhbiBrZXlib2FyZCBsYXlvdXQgS09JOC1SAUj///+8////AAAAAAFH////u////wAAAAAJugAAAAEhAAAAAwAAABkEAAAGuwAAAB5SdXNzaWFuIGtleWJvYXJkIGxheW91dCBjcDEyNTEBRP///7z///8AAAAAAUP///+7////AAAAAAm+AAAAASIAAAADAAAAGQQAAAa/AAAAIFJ1c3NpYW4gcGhvbmV0aWMga2V5Ym9hcmQgbGF5b3V0AUD///+8////AAAAAAE/////u////wAAAAAJwgAAAAEjAAAAAwAAACIEAAAGwwAAACBVa3JhaW5pYW4ga2V5Ym9hcmQgbGF5b3V0IEtPSTgtVQE8////vP///wAAAAABO////7v///8AAAAACcYAAAABJAAAAAMAAAAiBAAABscAAAAkVWtyYWluaWFuIGtleWJvYXJkIGxheW91dCAoc3RhbmRhcmQpATj///+8////AAAAAAE3////u////wAAAAAJygAAAAElAAAAAwAAABkEAAAGywAAACJSdXNzaWFuIGtleWJvYXJkIGxheW91dCAoc3RhbmRhcmQpATT///+8////AAAAAAEz////u////wAAAAAJzgAAAAEmAAAAAwAAAAoEAAAGzwAAABdTcGFuaXNoIGtleWJvYXJkIGxheW91dAEw////vP///wAAAAABL////7v///8AAAAACdIAAAABJwAAAAMAAAAQBAAABtMAAAAXSXRhbGlhbiBrZXlib2FyZCBsYXlvdXQBLP///7z///8AAAAAASv///+7////AAAAAAnWAAAAASgAAAADAAAADwQAAAbXAAAAGUljZWxhbmRpYyBrZXlib2FyZCBsYXlvdXQBKP///7z///8AAAAAASf///+7////AAAAAAnaAAAAASkAAAADAAAADgQAAAbbAAAAGUh1bmdhcmlhbiBrZXlib2FyZCBsYXlvdXQBJP///7z///8AAAAAASP///+7////AQAAAAneAAAAASoAAAADAAAAFQQAAAbfAAAAJVBvbGlzaCAocHJvZ3JhbW1lcidzKSBrZXlib2FyZCBsYXlvdXQBIP///7z///8AAAAAAR////+7////AAAAAAniAAAAASsAAAADAAAAJAQAAAbjAAAAGVNsb3ZlbmlhbiBrZXlib2FyZCBsYXlvdXQBHP///7z///8AAAAAARv///+7////AQAAAAnmAAAAASwAAAADAAAAGgwAAAbnAAAAGlNlcmJpYW4ga2V5Ym9hcmQgbGF5b3V0IHNyARj///+8////AAAAAAEX////u////wAAAAAJ6gAAAAEtAAAAAwAAABoMAAAG6wAAAB1TZXJiaWFuIGtleWJvYXJkIGxheW91dCB1cyxzcgEU////vP///wAAAAABE////7v///8AAAAACe4AAAABLgAAAAMAAAAaBAAABu8AAAAYQ3JvYXRpYW4ga2V5Ym9hcmQgbGF5b3V0ARD///+8////AAAAAAEP////u////wEAAAAJ8gAAAAEvAAAAAwAAABoEAAAG8wAAACNDcm9hdGlhbiBrZXlib2FyZCBsYXlvdXQgKHNwZWNpZmljKQEM////vP///wAAAAABC////7v///8AAAAACfYAAAABMAAAAAMAAAARBAAABvcAAAAcSmFwYW5lc2UgMTA2IGtleWJvYXJkIGxheW91dAEI////vP///wMAAAABB////7v///8HAAAACfoAAAABMQAAAAMAAAARBAAABvsAAAAfSmFwYW5lc2UgcGM5OHgxIGtleWJvYXJkIGxheW91dAEE////vP///wAAAAABA////7v///8AAAAACf4AAAABMgAAAAMAAAAbBAAABv8AAAAWU2xvdmFrIGtleWJvYXJkIGxheW91dAEA////vP///wAAAAAB//7//7v///8AAAAACQIBAAABMwAAAAMAAAAbBAAABgMBAAAyU2xvdmFrIGFuZCBDemVjaCBrZXlib2FyZCBsYXlvdXQgd2l0aG91dCBkZWFkIGtleXMB/P7//7z///8AAAAAAfv+//+7////AAAAAAkGAQAAATQAAAADAAAABQQAAAYHAQAAFUN6ZWNoIGtleWJvYXJkIGxheW91dAH4/v//vP///wAAAAAB9/7//7v///8AAAAACQoBAAABNQAAAAMAAAAFBAAABgsBAAAYQ3plY2gga2V5Ym9hcmQgbGF5b3V0IGN6AfT+//+8////AAAAAAHz/v//u////wEAAAAJDgEAAAE2AAAAAwAAAAUEAAAGDwEAAB9DemVjaCBrZXlib2FyZCBsYXlvdXQgY3pfcXdlcnR5AfD+//+8////AAAAAAHv/v//u////wAAAAAJEgEAAAE3AAAAAwAAAAoEAAAGEwEAAB5MYXRpbiBBbWVyaWNhbiBrZXlib2FyZCBsYXlvdXQB7P7//7z///8AAAAAAev+//+7////AAAAAAkWAQAAATgAAAADAAAAJwQAAAYXAQAAI0xpdGh1YW5pYW4gKEJhbHRpYykga2V5Ym9hcmQgbGF5b3V0Aej+//+8////AAAAAAHn/v//u////wAAAAAJGgEAAAE5AAAAAwAAAB8EAAAGGwEAABdUdXJraXNoIGtleWJvYXJkIGxheW91dAHk/v//vP///wAAAAAB4/7//7v///8AAAAACR4BAAABOgAAAAMAAAAfBAAABh8BAAAaVHVya2lzaCBrZXlib2FyZCBsYXlvdXQgdHIB4P7//7z///8AAAAAAd/+//+7////AAAAAAkiAQAAATsAAAADAAAAHwQAAAYjAQAAG1R1cmtpc2gga2V5Ym9hcmQgbGF5b3V0IHRyZgHc/v//vP///wAAAAAB2/7//7v///8AAAAACSYBAAABPAAAAAMAAAANBAAABicBAAAZSXNyYWVsaWFuIGtleWJvYXJkIGxheW91dAHY/v//vP///wAAAAAB1/7//7v///8AAAAACSoBAAABPQAAAAMAAAANBAAABisBAAAiSXNyYWVsaWFuIHBob25ldGljIGtleWJvYXJkIGxheW91dAHU/v//vP///wAAAAAB0/7//7v///8AAAAACS4BAAABPgAAAAMAAAANBAAABi8BAAAhSXNyYWVsaWFuIFNhaGFyb24ga2V5Ym9hcmQgbGF5b3V0AdD+//+8////AAAAAAHP/v//u////wAAAAAJMgEAAAE/AAAAAwAAAAkEAAAGMwEAABNWTkMga2V5Ym9hcmQgbGF5b3V0Acz+//+8////BAAAAAHL/v//u////wgAAAAJNgEAAAFAAAAAAwAAAAgEAAAGNwEAABVHcmVlayBrZXlib2FyZCBsYXlvdXQByP7//7z///8AAAAAAcf+//+7////AAAAAAk6AQAAAUEAAAADAAAAHgQAAAY7AQAAIFRoYWkgKEtlZG1hbmVlKSAga2V5Ym9hcmQgbGF5b3V0AcT+//+8////AAAAAAHD/v//u////wAAAAAJPgEAAAFCAAAAAwAAABMEAAAGPwEAABVEdXRjaCBrZXlib2FyZCBsYXlvdXQBwP7//7z///8AAAAAAb/+//+7////AAAAAAlCAQAAB0YAAAABAQAAADEAAAAHDwlDAQAACUQBAAAJRQEAAAlGAQAACUcBAAAJSAEAAAlJAQAACUoBAAAJSwEAAAlMAQAACU0BAAAJTgEAAAlPAQAACVABAAAJUQEAAAlSAQAACVMBAAAJVAEAAAlVAQAACVYBAAAJVwEAAAlYAQAACVkBAAAJWgEAAAlbAQAACVwBAAAJXQEAAAleAQAACV8BAAAJYAEAAAlhAQAACWIBAAAJYwEAAAlkAQAACWUBAAAJZgEAAAlnAQAACWgBAAAJaQEAAAlqAQAACWsBAAAJbAEAAAltAQAACW4BAAAJbwEAAAlwAQAACXEBAAAJcgEAAAlzAQAAB0oAAAABAQAAADEAAAAHDwl0AQAACXUBAAAJdgEAAAl3AQAACXgBAAAJeQEAAAl6AQAACXsBAAAJfAEAAAl9AQAACX4BAAAJfwEAAAmAAQAACYEBAAAJggEAAAmDAQAACYQBAAAJhQEAAAmGAQAACYcBAAAJiAEAAAmJAQAACYoBAAAJiwEAAAmMAQAACY0BAAAJjgEAAAmPAQAACZABAAAJkQEAAAmSAQAACZMBAAAJlAEAAAmVAQAACZYBAAAJlwEAAAmYAQAACZkBAAAJmgEAAAmbAQAACZwBAAAJnQEAAAmeAQAACZ8BAAAJoAEAAAmhAQAACaIBAAAJowEAAAmkAQAAB04AAAABAQAAADEAAAAHDwmlAQAACaYBAAAJpwEAAAmoAQAACakBAAAJqgEAAAmrAQAACawBAAAJrQEAAAmuAQAACa8BAAAJsAEAAAmxAQAACbIBAAAJswEAAAm0AQAACbUBAAAJtgEAAAm3AQAACbgBAAAJuQEAAAm6AQAACbsBAAAJvAEAAAm9AQAACb4BAAAJvwEAAAnAAQAACcEBAAAJwgEAAAnDAQAACcQBAAAJxQEAAAnGAQAACccBAAAJyAEAAAnJAQAACcoBAAAJywEAAAnMAQAACc0BAAAJzgEAAAnPAQAACdABAAAJ0QEAAAnSAQAACdMBAAAJ1AEAAAnVAQAAB1IAAAABAQAAADEAAAAHDwnWAQAACdcBAAAJ2AEAAAnZAQAACdoBAAAJ2wEAAAncAQAACd0BAAAJ3gEAAAnfAQAACeABAAAJ4QEAAAniAQAACeMBAAAJ5AEAAAnlAQAACeYBAAAJ5wEAAAnoAQAACekBAAAJ6gEAAAnrAQAACewBAAAJ7QEAAAnuAQAACe8BAAAJ8AEAAAnxAQAACfIBAAAJ8wEAAAn0AQAACfUBAAAJ9gEAAAn3AQAACfgBAAAJ+QEAAAn6AQAACfsBAAAJ/AEAAAn9AQAACf4BAAAJ/wEAAAkAAgAACQECAAAJAgIAAAkDAgAACQQCAAAJBQIAAAkGAgAAB1YAAAABAQAAADEAAAAHDwkHAgAACQgCAAAJCQIAAAkKAgAACQsCAAAJDAIAAAkNAgAACQ4CAAAJDwIAAAkQAgAACRECAAAJEgIAAAkTAgAACRQCAAAJFQIAAAkWAgAACRcCAAAJGAIAAAkZAgAACRoCAAAJGwIAAAkcAgAACR0CAAAJHgIAAAkfAgAACSACAAAJIQIAAAkiAgAACSMCAAAJJAIAAAklAgAACSYCAAAJJwIAAAkoAgAACSkCAAAJKgIAAAkrAgAACSwCAAAJLQIAAAkuAgAACS8CAAAJMAIAAAkxAgAACTICAAAJMwIAAAk0AgAACTUCAAAJNgIAAAk3AgAAB1oAAAABAQAAADEAAAAHDwk4AgAACTkCAAAJOgIAAAk7AgAACTwCAAAJPQIAAAk+AgAACT8CAAAJQAIAAAlBAgAACUICAAAJQwIAAAlEAgAACUUCAAAJRgIAAAlHAgAACUgCAAAJSQIAAAlKAgAACUsCAAAJTAIAAAlNAgAACU4CAAAJTwIAAAlQAgAACVECAAAJUgIAAAlTAgAACVQCAAAJVQIAAAlWAgAACVcCAAAJWAIAAAlZAgAACVoCAAAJWwIAAAlcAgAACV0CAAAJXgIAAAlfAgAACWACAAAJYQIAAAliAgAACWMCAAAJZAIAAAllAgAACWYCAAAJZwIAAAloAgAAB14AAAABAQAAADEAAAAHDwlpAgAACWoCAAAJawIAAAlsAgAACW0CAAAJbgIAAAlvAgAACXACAAAJcQIAAAlyAgAACXMCAAAJdAIAAAl1AgAACXYCAAAJdwIAAAl4AgAACXkCAAAJegIAAAl7AgAACXwCAAAJfQIAAAl+AgAACX8CAAAJgAIAAAmBAgAACYICAAAJgwIAAAmEAgAACYUCAAAJhgIAAAmHAgAACYgCAAAJiQIAAAmKAgAACYsCAAAJjAIAAAmNAgAACY4CAAAJjwIAAAmQAgAACZECAAAJkgIAAAmTAgAACZQCAAAJlQIAAAmWAgAACZcCAAAJmAIAAAmZAgAAB2IAAAABAQAAADEAAAAHDwmaAgAACZsCAAAJnAIAAAmdAgAACZ4CAAAJnwIAAAmgAgAACaECAAAJogIAAAmjAgAACaQCAAAJpQIAAAmmAgAACacCAAAJqAIAAAmpAgAACaoCAAAJqwIAAAmsAgAACa0CAAAJrgIAAAmvAgAACbACAAAJsQIAAAmyAgAACbMCAAAJtAIAAAm1AgAACbYCAAAJtwIAAAm4AgAACbkCAAAJugIAAAm7AgAACbwCAAAJvQIAAAm+AgAACb8CAAAJwAIAAAnBAgAACcICAAAJwwIAAAnEAgAACcUCAAAJxgIAAAnHAgAACcgCAAAJyQIAAAnKAgAAB2YAAAABAQAAADEAAAAHDwnLAgAACcwCAAAJzQIAAAnOAgAACc8CAAAJ0AIAAAnRAgAACdICAAAJ0wIAAAnUAgAACdUCAAAJ1gIAAAnXAgAACdgCAAAJ2QIAAAnaAgAACdsCAAAJ3AIAAAndAgAACd4CAAAJ3wIAAAngAgAACeECAAAJ4gIAAAnjAgAACeQCAAAJ5QIAAAnmAgAACecCAAAJ6AIAAAnpAgAACeoCAAAJ6wIAAAnsAgAACe0CAAAJ7gIAAAnvAgAACfACAAAJ8QIAAAnyAgAACfMCAAAJ9AIAAAn1AgAACfYCAAAJ9wIAAAn4AgAACfkCAAAJ+gIAAAn7AgAAB2oAAAABAQAAADEAAAAHDwn8AgAACf0CAAAJ/gIAAAn/AgAACQADAAAJAQMAAAkCAwAACQMDAAAJBAMAAAkFAwAACQYDAAAJBwMAAAkIAwAACQkDAAAJCgMAAAkLAwAACQwDAAAJDQMAAAkOAwAACQ8DAAAJEAMAAAkRAwAACRIDAAAJEwMAAAkUAwAACRUDAAAJFgMAAAkXAwAACRgDAAAJGQMAAAkaAwAACRsDAAAJHAMAAAkdAwAACR4DAAAJHwMAAAkgAwAACSEDAAAJIgMAAAkjAwAACSQDAAAJJQMAAAkmAwAACScDAAAJKAMAAAkpAwAACSoDAAAJKwMAAAksAwAAB24AAAABAQAAADEAAAAHDwktAwAACS4DAAAJLwMAAAkwAwAACTEDAAAJMgMAAAkzAwAACTQDAAAJNQMAAAk2AwAACTcDAAAJOAMAAAk5AwAACToDAAAJOwMAAAk8AwAACT0DAAAJPgMAAAk/AwAACUADAAAJQQMAAAlCAwAACUMDAAAJRAMAAAlFAwAACUYDAAAJRwMAAAlIAwAACUkDAAAJSgMAAAlLAwAACUwDAAAJTQMAAAlOAwAACU8DAAAJUAMAAAlRAwAACVIDAAAJUwMAAAlUAwAACVUDAAAJVgMAAAlXAwAACVgDAAAJWQMAAAlaAwAACVsDAAAJXAMAAAldAwAAB3IAAAABAQAAADEAAAAHDwleAwAACV8DAAAJYAMAAAlhAwAACWIDAAAJYwMAAAlkAwAACWUDAAAJZgMAAAlnAwAACWgDAAAJaQMAAAlqAwAACWsDAAAJbAMAAAltAwAACW4DAAAJbwMAAAlwAwAACXEDAAAJcgMAAAlzAwAACXQDAAAJdQMAAAl2AwAACXcDAAAJeAMAAAl5AwAACXoDAAAJewMAAAl8AwAACX0DAAAJfgMAAAl/AwAACYADAAAJgQMAAAmCAwAACYMDAAAJhAMAAAmFAwAACYYDAAAJhwMAAAmIAwAACYkDAAAJigMAAAmLAwAACYwDAAAJjQMAAAmOAwAAB3YAAAABAQAAADEAAAAHDwmPAwAACZADAAAJkQMAAAmSAwAACZMDAAAJlAMAAAmVAwAACZYDAAAJlwMAAAmYAwAACZkDAAAJmgMAAAmbAwAACZwDAAAJnQMAAAmeAwAACZ8DAAAJoAMAAAmhAwAACaIDAAAJowMAAAmkAwAACaUDAAAJpgMAAAmnAwAACagDAAAJqQMAAAmqAwAACasDAAAJrAMAAAmtAwAACa4DAAAJrwMAAAmwAwAACbEDAAAJsgMAAAmzAwAACbQDAAAJtQMAAAm2AwAACbcDAAAJuAMAAAm5AwAACboDAAAJuwMAAAm8AwAACb0DAAAJvgMAAAm/AwAAB3oAAAABAQAAADEAAAAHDwnAAwAACcEDAAAJwgMAAAnDAwAACcQDAAAJxQMAAAnGAwAACccDAAAJyAMAAAnJAwAACcoDAAAJywMAAAnMAwAACc0DAAAJzgMAAAnPAwAACdADAAAJ0QMAAAnSAwAACdMDAAAJ1AMAAAnVAwAACdYDAAAJ1wMAAAnYAwAACdkDAAAJ2gMAAAnbAwAACdwDAAAJ3QMAAAneAwAACd8DAAAJ4AMAAAnhAwAACeIDAAAJ4wMAAAnkAwAACeUDAAAJ5gMAAAnnAwAACegDAAAJ6QMAAAnqAwAACesDAAAJ7AMAAAntAwAACe4DAAAJ7wMAAAnwAwAAB34AAAABAQAAADEAAAAHDwnxAwAACfIDAAAJ8wMAAAn0AwAACfUDAAAJ9gMAAAn3AwAACfgDAAAJ+QMAAAn6AwAACfsDAAAJ/AMAAAn9AwAACf4DAAAJ/wMAAAkABAAACQEEAAAJAgQAAAkDBAAACQQEAAAJBQQAAAkGBAAACQcEAAAJCAQAAAkJBAAACQoEAAAJCwQAAAkMBAAACQ0EAAAJDgQAAAkPBAAACRAEAAAJEQQAAAkSBAAACRMEAAAJFAQAAAkVBAAACRYEAAAJFwQAAAkYBAAACRkEAAAJGgQAAAkbBAAACRwEAAAJHQQAAAkeBAAACR8EAAAJIAQAAAkhBAAAB4IAAAABAQAAADEAAAAHDwkiBAAACSMEAAAJJAQAAAklBAAACSYEAAAJJwQAAAkoBAAACSkEAAAJKgQAAAkrBAAACSwEAAAJLQQAAAkuBAAACS8EAAAJMAQAAAkxBAAACTIEAAAJMwQAAAk0BAAACTUEAAAJNgQAAAk3BAAACTgEAAAJOQQAAAk6BAAACTsEAAAJPAQAAAk9BAAACT4EAAAJPwQAAAlABAAACUEEAAAJQgQAAAlDBAAACUQEAAAJRQQAAAlGBAAACUcEAAAJSAQAAAlJBAAACUoEAAAJSwQAAAlMBAAACU0EAAAJTgQAAAlPBAAACVAEAAAJUQQAAAlSBAAAB4YAAAABAQAAADEAAAAHDwlTBAAACVQEAAAJVQQAAAlWBAAACVcEAAAJWAQAAAlZBAAACVoEAAAJWwQAAAlcBAAACV0EAAAJXgQAAAlfBAAACWAEAAAJYQQAAAliBAAACWMEAAAJZAQAAAllBAAACWYEAAAJZwQAAAloBAAACWkEAAAJagQAAAlrBAAACWwEAAAJbQQAAAluBAAACW8EAAAJcAQAAAlxBAAACXIEAAAJcwQAAAl0BAAACXUEAAAJdgQAAAl3BAAACXgEAAAJeQQAAAl6BAAACXsEAAAJfAQAAAl9BAAACX4EAAAJfwQAAAmABAAACYEEAAAJggQAAAmDBAAAB4oAAAABAQAAADEAAAAHDwmEBAAACYUEAAAJhgQAAAmHBAAACYgEAAAJiQQAAAmKBAAACYsEAAAJjAQAAAmNBAAACY4EAAAJjwQAAAmQBAAACZEEAAAJkgQAAAmTBAAACZQEAAAJlQQAAAmWBAAACZcEAAAJmAQAAAmZBAAACZoEAAAJmwQAAAmcBAAACZ0EAAAJngQAAAmfBAAACaAEAAAJoQQAAAmiBAAACaMEAAAJpAQAAAmlBAAACaYEAAAJpwQAAAmoBAAACakEAAAJqgQAAAmrBAAACawEAAAJrQQAAAmuBAAACa8EAAAJsAQAAAmxBAAACbIEAAAJswQAAAm0BAAAB44AAAABAQAAADEAAAAHDwm1BAAACbYEAAAJtwQAAAm4BAAACbkEAAAJugQAAAm7BAAACbwEAAAJvQQAAAm+BAAACb8EAAAJwAQAAAnBBAAACcIEAAAJwwQAAAnEBAAACcUEAAAJxgQAAAnHBAAACcgEAAAJyQQAAAnKBAAACcsEAAAJzAQAAAnNBAAACc4EAAAJzwQAAAnQBAAACdEEAAAJ0gQAAAnTBAAACdQEAAAJ1QQAAAnWBAAACdcEAAAJ2AQAAAnZBAAACdoEAAAJ2wQAAAncBAAACd0EAAAJ3gQAAAnfBAAACeAEAAAJ4QQAAAniBAAACeMEAAAJ5AQAAAnlBAAAB5IAAAABAQAAADEAAAAHDwnmBAAACecEAAAJ6AQAAAnpBAAACeoEAAAJ6wQAAAnsBAAACe0EAAAJ7gQAAAnvBAAACfAEAAAJ8QQAAAnyBAAACfMEAAAJ9AQAAAn1BAAACfYEAAAJ9wQAAAn4BAAACfkEAAAJ+gQAAAn7BAAACfwEAAAJ/QQAAAn+BAAACf8EAAAJAAUAAAkBBQAACQIFAAAJAwUAAAkEBQAACQUFAAAJBgUAAAkHBQAACQgFAAAJCQUAAAkKBQAACQsFAAAJDAUAAAkNBQAACQ4FAAAJDwUAAAkQBQAACREFAAAJEgUAAAkTBQAACRQFAAAJFQUAAAkWBQAAB5YAAAABAQAAADEAAAAHDwkXBQAACRgFAAAJGQUAAAkaBQAACRsFAAAJHAUAAAkdBQAACR4FAAAJHwUAAAkgBQAACSEFAAAJIgUAAAkjBQAACSQFAAAJJQUAAAkmBQAACScFAAAJKAUAAAkpBQAACSoFAAAJKwUAAAksBQAACS0FAAAJLgUAAAkvBQAACTAFAAAJMQUAAAkyBQAACTMFAAAJNAUAAAk1BQAACTYFAAAJNwUAAAk4BQAACTkFAAAJOgUAAAk7BQAACTwFAAAJPQUAAAk+BQAACT8FAAAJQAUAAAlBBQAACUIFAAAJQwUAAAlEBQAACUUFAAAJRgUAAAlHBQAAB5oAAAABAQAAADEAAAAHDwlIBQAACUkFAAAJSgUAAAlLBQAACUwFAAAJTQUAAAlOBQAACU8FAAAJUAUAAAlRBQAACVIFAAAJUwUAAAlUBQAACVUFAAAJVgUAAAlXBQAACVgFAAAJWQUAAAlaBQAACVsFAAAJXAUAAAldBQAACV4FAAAJXwUAAAlgBQAACWEFAAAJYgUAAAljBQAACWQFAAAJZQUAAAlmBQAACWcFAAAJaAUAAAlpBQAACWoFAAAJawUAAAlsBQAACW0FAAAJbgUAAAlvBQAACXAFAAAJcQUAAAlyBQAACXMFAAAJdAUAAAl1BQAACXYFAAAJdwUAAAl4BQAAB54AAAABAQAAADEAAAAHDwl5BQAACXoFAAAJewUAAAl8BQAACX0FAAAJfgUAAAl/BQAACYAFAAAJgQUAAAmCBQAACYMFAAAJhAUAAAmFBQAACYYFAAAJhwUAAAmIBQAACYkFAAAJigUAAAmLBQAACYwFAAAJjQUAAAmOBQAACY8FAAAJkAUAAAmRBQAACZIFAAAJkwUAAAmUBQAACZUFAAAJlgUAAAmXBQAACZgFAAAJmQUAAAmaBQAACZsFAAAJnAUAAAmdBQAACZ4FAAAJnwUAAAmgBQAACaEFAAAJogUAAAmjBQAACaQFAAAJpQUAAAmmBQAACacFAAAJqAUAAAmpBQAAB6IAAAABAQAAADEAAAAHDwmqBQAACasFAAAJrAUAAAmtBQAACa4FAAAJrwUAAAmwBQAACbEFAAAJsgUAAAmzBQAACbQFAAAJtQUAAAm2BQAACbcFAAAJuAUAAAm5BQAACboFAAAJuwUAAAm8BQAACb0FAAAJvgUAAAm/BQAACcAFAAAJwQUAAAnCBQAACcMFAAAJxAUAAAnFBQAACcYFAAAJxwUAAAnIBQAACckFAAAJygUAAAnLBQAACcwFAAAJzQUAAAnOBQAACc8FAAAJ0AUAAAnRBQAACdIFAAAJ0wUAAAnUBQAACdUFAAAJ1gUAAAnXBQAACdgFAAAJ2QUAAAnaBQAAB6YAAAABAQAAADEAAAAHDwnbBQAACdwFAAAJ3QUAAAneBQAACd8FAAAJ4AUAAAnhBQAACeIFAAAJ4wUAAAnkBQAACeUFAAAJ5gUAAAnnBQAACegFAAAJ6QUAAAnqBQAACesFAAAJ7AUAAAntBQAACe4FAAAJ7wUAAAnwBQAACfEFAAAJ8gUAAAnzBQAACfQFAAAJ9QUAAAn2BQAACfcFAAAJ+AUAAAn5BQAACfoFAAAJ+wUAAAn8BQAACf0FAAAJ/gUAAAn/BQAACQAGAAAJAQYAAAkCBgAACQMGAAAJBAYAAAkFBgAACQYGAAAJBwYAAAkIBgAACQkGAAAJCgYAAAkLBgAAB6oAAAABAQAAADEAAAAHDwkMBgAACQ0GAAAJDgYAAAkPBgAACRAGAAAJEQYAAAkSBgAACRMGAAAJFAYAAAkVBgAACRYGAAAJFwYAAAkYBgAACRkGAAAJGgYAAAkbBgAACRwGAAAJHQYAAAkeBgAACR8GAAAJIAYAAAkhBgAACSIGAAAJIwYAAAkkBgAACSUGAAAJJgYAAAknBgAACSgGAAAJKQYAAAkqBgAACSsGAAAJLAYAAAktBgAACS4GAAAJLwYAAAkwBgAACTEGAAAJMgYAAAkzBgAACTQGAAAJNQYAAAk2BgAACTcGAAAJOAYAAAk5BgAACToGAAAJOwYAAAk8BgAAB64AAAABAQAAADEAAAAHDwk9BgAACT4GAAAJPwYAAAlABgAACUEGAAAJQgYAAAlDBgAACUQGAAAJRQYAAAlGBgAACUcGAAAJSAYAAAlJBgAACUoGAAAJSwYAAAlMBgAACU0GAAAJTgYAAAlPBgAACVAGAAAJUQYAAAlSBgAACVMGAAAJVAYAAAlVBgAACVYGAAAJVwYAAAlYBgAACVkGAAAJWgYAAAlbBgAACVwGAAAJXQYAAAleBgAACV8GAAAJYAYAAAlhBgAACWIGAAAJYwYAAAlkBgAACWUGAAAJZgYAAAlnBgAACWgGAAAJaQYAAAlqBgAACWsGAAAJbAYAAAltBgAAB7IAAAABAQAAADEAAAAHDwluBgAACW8GAAAJcAYAAAlxBgAACXIGAAAJcwYAAAl0BgAACXUGAAAJdgYAAAl3BgAACXgGAAAJeQYAAAl6BgAACXsGAAAJfAYAAAl9BgAACX4GAAAJfwYAAAmABgAACYEGAAAJggYAAAmDBgAACYQGAAAJhQYAAAmGBgAACYcGAAAJiAYAAAmJBgAACYoGAAAJiwYAAAmMBgAACY0GAAAJjgYAAAmPBgAACZAGAAAJkQYAAAmSBgAACZMGAAAJlAYAAAmVBgAACZYGAAAJlwYAAAmYBgAACZkGAAAJmgYAAAmbBgAACZwGAAAJnQYAAAmeBgAAB7YAAAABAQAAADEAAAAHDwmfBgAACaAGAAAJoQYAAAmiBgAACaMGAAAJpAYAAAmlBgAACaYGAAAJpwYAAAmoBgAACakGAAAJqgYAAAmrBgAACawGAAAJrQYAAAmuBgAACa8GAAAJsAYAAAmxBgAACbIGAAAJswYAAAm0BgAACbUGAAAJtgYAAAm3BgAACbgGAAAJuQYAAAm6BgAACbsGAAAJvAYAAAm9BgAACb4GAAAJvwYAAAnABgAACcEGAAAJwgYAAAnDBgAACcQGAAAJxQYAAAnGBgAACccGAAAJyAYAAAnJBgAACcoGAAAJywYAAAnMBgAACc0GAAAJzgYAAAnPBgAAB7oAAAABAQAAADEAAAAHDwnQBgAACdEGAAAJ0gYAAAnTBgAACdQGAAAJ1QYAAAnWBgAACdcGAAAJ2AYAAAnZBgAACdoGAAAJ2wYAAAncBgAACd0GAAAJ3gYAAAnfBgAACeAGAAAJ4QYAAAniBgAACeMGAAAJ5AYAAAnlBgAACeYGAAAJ5wYAAAnoBgAACekGAAAJ6gYAAAnrBgAACewGAAAJ7QYAAAnuBgAACe8GAAAJ8AYAAAnxBgAACfIGAAAJ8wYAAAn0BgAACfUGAAAJ9gYAAAn3BgAACfgGAAAJ+QYAAAn6BgAACfsGAAAJ/AYAAAn9BgAACf4GAAAJ/wYAAAkABwAAB74AAAABAQAAADEAAAAHDwkBBwAACQIHAAAJAwcAAAkEBwAACQUHAAAJBgcAAAkHBwAACQgHAAAJCQcAAAkKBwAACQsHAAAJDAcAAAkNBwAACQ4HAAAJDwcAAAkQBwAACREHAAAJEgcAAAkTBwAACRQHAAAJFQcAAAkWBwAACRcHAAAJGAcAAAkZBwAACRoHAAAJGwcAAAkcBwAACR0HAAAJHgcAAAkfBwAACSAHAAAJIQcAAAkiBwAACSMHAAAJJAcAAAklBwAACSYHAAAJJwcAAAkoBwAACSkHAAAJKgcAAAkrBwAACSwHAAAJLQcAAAkuBwAACS8HAAAJMAcAAAkxBwAAB8IAAAABAQAAADEAAAAHDwkyBwAACTMHAAAJNAcAAAk1BwAACTYHAAAJNwcAAAk4BwAACTkHAAAJOgcAAAk7BwAACTwHAAAJPQcAAAk+BwAACT8HAAAJQAcAAAlBBwAACUIHAAAJQwcAAAlEBwAACUUHAAAJRgcAAAlHBwAACUgHAAAJSQcAAAlKBwAACUsHAAAJTAcAAAlNBwAACU4HAAAJTwcAAAlQBwAACVEHAAAJUgcAAAlTBwAACVQHAAAJVQcAAAlWBwAACVcHAAAJWAcAAAlZBwAACVoHAAAJWwcAAAlcBwAACV0HAAAJXgcAAAlfBwAACWAHAAAJYQcAAAliBwAAB8YAAAABAQAAADEAAAAHDwljBwAACWQHAAAJZQcAAAlmBwAACWcHAAAJaAcAAAlpBwAACWoHAAAJawcAAAlsBwAACW0HAAAJbgcAAAlvBwAACXAHAAAJcQcAAAlyBwAACXMHAAAJdAcAAAl1BwAACXYHAAAJdwcAAAl4BwAACXkHAAAJegcAAAl7BwAACXwHAAAJfQcAAAl+BwAACX8HAAAJgAcAAAmBBwAACYIHAAAJgwcAAAmEBwAACYUHAAAJhgcAAAmHBwAACYgHAAAJiQcAAAmKBwAACYsHAAAJjAcAAAmNBwAACY4HAAAJjwcAAAmQBwAACZEHAAAJkgcAAAmTBwAAB8oAAAABAQAAADEAAAAHDwmUBwAACZUHAAAJlgcAAAmXBwAACZgHAAAJmQcAAAmaBwAACZsHAAAJnAcAAAmdBwAACZ4HAAAJnwcAAAmgBwAACaEHAAAJogcAAAmjBwAACaQHAAAJpQcAAAmmBwAACacHAAAJqAcAAAmpBwAACaoHAAAJqwcAAAmsBwAACa0HAAAJrgcAAAmvBwAACbAHAAAJsQcAAAmyBwAACbMHAAAJtAcAAAm1BwAACbYHAAAJtwcAAAm4BwAACbkHAAAJugcAAAm7BwAACbwHAAAJvQcAAAm+BwAACb8HAAAJwAcAAAnBBwAACcIHAAAJwwcAAAnEBwAAB84AAAABAQAAADEAAAAHDwnFBwAACcYHAAAJxwcAAAnIBwAACckHAAAJygcAAAnLBwAACcwHAAAJzQcAAAnOBwAACc8HAAAJ0AcAAAnRBwAACdIHAAAJ0wcAAAnUBwAACdUHAAAJ1gcAAAnXBwAACdgHAAAJ2QcAAAnaBwAACdsHAAAJ3AcAAAndBwAACd4HAAAJ3wcAAAngBwAACeEHAAAJ4gcAAAnjBwAACeQHAAAJ5QcAAAnmBwAACecHAAAJ6AcAAAnpBwAACeoHAAAJ6wcAAAnsBwAACe0HAAAJ7gcAAAnvBwAACfAHAAAJ8QcAAAnyBwAACfMHAAAJ9AcAAAn1BwAAB9IAAAABAQAAADEAAAAHDwn2BwAACfcHAAAJ+AcAAAn5BwAACfoHAAAJ+wcAAAn8BwAACf0HAAAJ/gcAAAn/BwAACQAIAAAJAQgAAAkCCAAACQMIAAAJBAgAAAkFCAAACQYIAAAJBwgAAAkICAAACQkIAAAJCggAAAkLCAAACQwIAAAJDQgAAAkOCAAACQ8IAAAJEAgAAAkRCAAACRIIAAAJEwgAAAkUCAAACRUIAAAJFggAAAkXCAAACRgIAAAJGQgAAAkaCAAACRsIAAAJHAgAAAkdCAAACR4IAAAJHwgAAAkgCAAACSEIAAAJIggAAAkjCAAACSQIAAAJJQgAAAkmCAAAB9YAAAABAQAAADEAAAAHDwknCAAACSgIAAAJKQgAAAkqCAAACSsIAAAJLAgAAAktCAAACS4IAAAJLwgAAAkwCAAACTEIAAAJMggAAAkzCAAACTQIAAAJNQgAAAk2CAAACTcIAAAJOAgAAAk5CAAACToIAAAJOwgAAAk8CAAACT0IAAAJPggAAAk/CAAACUAIAAAJQQgAAAlCCAAACUMIAAAJRAgAAAlFCAAACUYIAAAJRwgAAAlICAAACUkIAAAJSggAAAlLCAAACUwIAAAJTQgAAAlOCAAACU8IAAAJUAgAAAlRCAAACVIIAAAJUwgAAAlUCAAACVUIAAAJVggAAAlXCAAAB9oAAAABAQAAADEAAAAHDwlYCAAACVkIAAAJWggAAAlbCAAACVwIAAAJXQgAAAleCAAACV8IAAAJYAgAAAlhCAAACWIIAAAJYwgAAAlkCAAACWUIAAAJZggAAAlnCAAACWgIAAAJaQgAAAlqCAAACWsIAAAJbAgAAAltCAAACW4IAAAJbwgAAAlwCAAACXEIAAAJcggAAAlzCAAACXQIAAAJdQgAAAl2CAAACXcIAAAJeAgAAAl5CAAACXoIAAAJewgAAAl8CAAACX0IAAAJfggAAAl/CAAACYAIAAAJgQgAAAmCCAAACYMIAAAJhAgAAAmFCAAACYYIAAAJhwgAAAmICAAAB94AAAABAQAAADEAAAAHDwmJCAAACYoIAAAJiwgAAAmMCAAACY0IAAAJjggAAAmPCAAACZAIAAAJkQgAAAmSCAAACZMIAAAJlAgAAAmVCAAACZYIAAAJlwgAAAmYCAAACZkIAAAJmggAAAmbCAAACZwIAAAJnQgAAAmeCAAACZ8IAAAJoAgAAAmhCAAACaIIAAAJowgAAAmkCAAACaUIAAAJpggAAAmnCAAACagIAAAJqQgAAAmqCAAACasIAAAJrAgAAAmtCAAACa4IAAAJrwgAAAmwCAAACbEIAAAJsggAAAmzCAAACbQIAAAJtQgAAAm2CAAACbcIAAAJuAgAAAm5CAAAB+IAAAABAQAAADEAAAAHDwm6CAAACbsIAAAJvAgAAAm9CAAACb4IAAAJvwgAAAnACAAACcEIAAAJwggAAAnDCAAACcQIAAAJxQgAAAnGCAAACccIAAAJyAgAAAnJCAAACcoIAAAJywgAAAnMCAAACc0IAAAJzggAAAnPCAAACdAIAAAJ0QgAAAnSCAAACdMIAAAJ1AgAAAnVCAAACdYIAAAJ1wgAAAnYCAAACdkIAAAJ2ggAAAnbCAAACdwIAAAJ3QgAAAneCAAACd8IAAAJ4AgAAAnhCAAACeIIAAAJ4wgAAAnkCAAACeUIAAAJ5ggAAAnnCAAACegIAAAJ6QgAAAnqCAAAB+YAAAABAQAAADEAAAAHDwnrCAAACewIAAAJ7QgAAAnuCAAACe8IAAAJ8AgAAAnxCAAACfIIAAAJ8wgAAAn0CAAACfUIAAAJ9ggAAAn3CAAACfgIAAAJ+QgAAAn6CAAACfsIAAAJ/AgAAAn9CAAACf4IAAAJ/wgAAAkACQAACQEJAAAJAgkAAAkDCQAACQQJAAAJBQkAAAkGCQAACQcJAAAJCAkAAAkJCQAACQoJAAAJCwkAAAkMCQAACQ0JAAAJDgkAAAkPCQAACRAJAAAJEQkAAAkSCQAACRMJAAAJFAkAAAkVCQAACRYJAAAJFwkAAAkYCQAACRkJAAAJGgkAAAkbCQAAB+oAAAABAQAAADEAAAAHDwkcCQAACR0JAAAJHgkAAAkfCQAACSAJAAAJIQkAAAkiCQAACSMJAAAJJAkAAAklCQAACSYJAAAJJwkAAAkoCQAACSkJAAAJKgkAAAkrCQAACSwJAAAJLQkAAAkuCQAACS8JAAAJMAkAAAkxCQAACTIJAAAJMwkAAAk0CQAACTUJAAAJNgkAAAk3CQAACTgJAAAJOQkAAAk6CQAACTsJAAAJPAkAAAk9CQAACT4JAAAJPwkAAAlACQAACUEJAAAJQgkAAAlDCQAACUQJAAAJRQkAAAlGCQAACUcJAAAJSAkAAAlJCQAACUoJAAAJSwkAAAlMCQAAB+4AAAABAQAAADEAAAAHDwlNCQAACU4JAAAJTwkAAAlQCQAACVEJAAAJUgkAAAlTCQAACVQJAAAJVQkAAAlWCQAACVcJAAAJWAkAAAlZCQAACVoJAAAJWwkAAAlcCQAACV0JAAAJXgkAAAlfCQAACWAJAAAJYQkAAAliCQAACWMJAAAJZAkAAAllCQAACWYJAAAJZwkAAAloCQAACWkJAAAJagkAAAlrCQAACWwJAAAJbQkAAAluCQAACW8JAAAJcAkAAAlxCQAACXIJAAAJcwkAAAl0CQAACXUJAAAJdgkAAAl3CQAACXgJAAAJeQkAAAl6CQAACXsJAAAJfAkAAAl9CQAAB/IAAAABAQAAADEAAAAHDwl+CQAACX8JAAAJgAkAAAmBCQAACYIJAAAJgwkAAAmECQAACYUJAAAJhgkAAAmHCQAACYgJAAAJiQkAAAmKCQAACYsJAAAJjAkAAAmNCQAACY4JAAAJjwkAAAmQCQAACZEJAAAJkgkAAAmTCQAACZQJAAAJlQkAAAmWCQAACZcJAAAJmAkAAAmZCQAACZoJAAAJmwkAAAmcCQAACZ0JAAAJngkAAAmfCQAACaAJAAAJoQkAAAmiCQAACaMJAAAJpAkAAAmlCQAACaYJAAAJpwkAAAmoCQAACakJAAAJqgkAAAmrCQAACawJAAAJrQkAAAmuCQAAB/YAAAABAQAAADEAAAAHDwmvCQAACbAJAAAJsQkAAAmyCQAACbMJAAAJtAkAAAm1CQAACbYJAAAJtwkAAAm4CQAACbkJAAAJugkAAAm7CQAACbwJAAAJvQkAAAm+CQAACb8JAAAJwAkAAAnBCQAACcIJAAAJwwkAAAnECQAACcUJAAAJxgkAAAnHCQAACcgJAAAJyQkAAAnKCQAACcsJAAAJzAkAAAnNCQAACc4JAAAJzwkAAAnQCQAACdEJAAAJ0gkAAAnTCQAACdQJAAAJ1QkAAAnWCQAACdcJAAAJ2AkAAAnZCQAACdoJAAAJ2wkAAAncCQAACd0JAAAJ3gkAAAnfCQAAB/oAAAABAQAAADEAAAAHDwngCQAACeEJAAAJ4gkAAAnjCQAACeQJAAAJ5QkAAAnmCQAACecJAAAJ6AkAAAnpCQAACeoJAAAJ6wkAAAnsCQAACe0JAAAJ7gkAAAnvCQAACfAJAAAJ8QkAAAnyCQAACfMJAAAJ9AkAAAn1CQAACfYJAAAJ9wkAAAn4CQAACfkJAAAJ+gkAAAn7CQAACfwJAAAJ/QkAAAn+CQAACf8JAAAJAAoAAAkBCgAACQIKAAAJAwoAAAkECgAACQUKAAAJBgoAAAkHCgAACQgKAAAJCQoAAAkKCgAACQsKAAAJDAoAAAkNCgAACQ4KAAAJDwoAAAkQCgAAB/4AAAABAQAAADEAAAAHDwkRCgAACRIKAAAJEwoAAAkUCgAACRUKAAAJFgoAAAkXCgAACRgKAAAJGQoAAAkaCgAACRsKAAAJHAoAAAkdCgAACR4KAAAJHwoAAAkgCgAACSEKAAAJIgoAAAkjCgAACSQKAAAJJQoAAAkmCgAACScKAAAJKAoAAAkpCgAACSoKAAAJKwoAAAksCgAACS0KAAAJLgoAAAkvCgAACTAKAAAJMQoAAAkyCgAACTMKAAAJNAoAAAk1CgAACTYKAAAJNwoAAAk4CgAACTkKAAAJOgoAAAk7CgAACTwKAAAJPQoAAAk+CgAACT8KAAAJQAoAAAlBCgAABwIBAAABAQAAADEAAAAHDwlCCgAACUMKAAAJRAoAAAlFCgAACUYKAAAJRwoAAAlICgAACUkKAAAJSgoAAAlLCgAACUwKAAAJTQoAAAlOCgAACU8KAAAJUAoAAAlRCgAACVIKAAAJUwoAAAlUCgAACVUKAAAJVgoAAAlXCgAACVgKAAAJWQoAAAlaCgAACVsKAAAJXAoAAAldCgAACV4KAAAJXwoAAAlgCgAACWEKAAAJYgoAAAljCgAACWQKAAAJZQoAAAlmCgAACWcKAAAJaAoAAAlpCgAACWoKAAAJawoAAAlsCgAACW0KAAAJbgoAAAlvCgAACXAKAAAJcQoAAAlyCgAABwYBAAABAQAAADEAAAAHDwlzCgAACXQKAAAJdQoAAAl2CgAACXcKAAAJeAoAAAl5CgAACXoKAAAJewoAAAl8CgAACX0KAAAJfgoAAAl/CgAACYAKAAAJgQoAAAmCCgAACYMKAAAJhAoAAAmFCgAACYYKAAAJhwoAAAmICgAACYkKAAAJigoAAAmLCgAACYwKAAAJjQoAAAmOCgAACY8KAAAJkAoAAAmRCgAACZIKAAAJkwoAAAmUCgAACZUKAAAJlgoAAAmXCgAACZgKAAAJmQoAAAmaCgAACZsKAAAJnAoAAAmdCgAACZ4KAAAJnwoAAAmgCgAACaEKAAAJogoAAAmjCgAABwoBAAABAQAAADEAAAAHDwmkCgAACaUKAAAJpgoAAAmnCgAACagKAAAJqQoAAAmqCgAACasKAAAJrAoAAAmtCgAACa4KAAAJrwoAAAmwCgAACbEKAAAJsgoAAAmzCgAACbQKAAAJtQoAAAm2CgAACbcKAAAJuAoAAAm5CgAACboKAAAJuwoAAAm8CgAACb0KAAAJvgoAAAm/CgAACcAKAAAJwQoAAAnCCgAACcMKAAAJxAoAAAnFCgAACcYKAAAJxwoAAAnICgAACckKAAAJygoAAAnLCgAACcwKAAAJzQoAAAnOCgAACc8KAAAJ0AoAAAnRCgAACdIKAAAJ0woAAAnUCgAABw4BAAABAQAAADEAAAAHDwnVCgAACdYKAAAJ1woAAAnYCgAACdkKAAAJ2goAAAnbCgAACdwKAAAJ3QoAAAneCgAACd8KAAAJ4AoAAAnhCgAACeIKAAAJ4woAAAnkCgAACeUKAAAJ5goAAAnnCgAACegKAAAJ6QoAAAnqCgAACesKAAAJ7AoAAAntCgAACe4KAAAJ7woAAAnwCgAACfEKAAAJ8goAAAnzCgAACfQKAAAJ9QoAAAn2CgAACfcKAAAJ+AoAAAn5CgAACfoKAAAJ+woAAAn8CgAACf0KAAAJ/goAAAn/CgAACQALAAAJAQsAAAkCCwAACQMLAAAJBAsAAAkFCwAABxIBAAABAQAAADEAAAAHDwkGCwAACQcLAAAJCAsAAAkJCwAACQoLAAAJCwsAAAkMCwAACQ0LAAAJDgsAAAkPCwAACRALAAAJEQsAAAkSCwAACRMLAAAJFAsAAAkVCwAACRYLAAAJFwsAAAkYCwAACRkLAAAJGgsAAAkbCwAACRwLAAAJHQsAAAkeCwAACR8LAAAJIAsAAAkhCwAACSILAAAJIwsAAAkkCwAACSULAAAJJgsAAAknCwAACSgLAAAJKQsAAAkqCwAACSsLAAAJLAsAAAktCwAACS4LAAAJLwsAAAkwCwAACTELAAAJMgsAAAkzCwAACTQLAAAJNQsAAAk2CwAABxYBAAABAQAAADEAAAAHDwk3CwAACTgLAAAJOQsAAAk6CwAACTsLAAAJPAsAAAk9CwAACT4LAAAJPwsAAAlACwAACUELAAAJQgsAAAlDCwAACUQLAAAJRQsAAAlGCwAACUcLAAAJSAsAAAlJCwAACUoLAAAJSwsAAAlMCwAACU0LAAAJTgsAAAlPCwAACVALAAAJUQsAAAlSCwAACVMLAAAJVAsAAAlVCwAACVYLAAAJVwsAAAlYCwAACVkLAAAJWgsAAAlbCwAACVwLAAAJXQsAAAleCwAACV8LAAAJYAsAAAlhCwAACWILAAAJYwsAAAlkCwAACWULAAAJZgsAAAlnCwAABxoBAAABAQAAADEAAAAHDwloCwAACWkLAAAJagsAAAlrCwAACWwLAAAJbQsAAAluCwAACW8LAAAJcAsAAAlxCwAACXILAAAJcwsAAAl0CwAACXULAAAJdgsAAAl3CwAACXgLAAAJeQsAAAl6CwAACXsLAAAJfAsAAAl9CwAACX4LAAAJfwsAAAmACwAACYELAAAJggsAAAmDCwAACYQLAAAJhQsAAAmGCwAACYcLAAAJiAsAAAmJCwAACYoLAAAJiwsAAAmMCwAACY0LAAAJjgsAAAmPCwAACZALAAAJkQsAAAmSCwAACZMLAAAJlAsAAAmVCwAACZYLAAAJlwsAAAmYCwAABx4BAAABAQAAADEAAAAHDwmZCwAACZoLAAAJmwsAAAmcCwAACZ0LAAAJngsAAAmfCwAACaALAAAJoQsAAAmiCwAACaMLAAAJpAsAAAmlCwAACaYLAAAJpwsAAAmoCwAACakLAAAJqgsAAAmrCwAACawLAAAJrQsAAAmuCwAACa8LAAAJsAsAAAmxCwAACbILAAAJswsAAAm0CwAACbULAAAJtgsAAAm3CwAACbgLAAAJuQsAAAm6CwAACbsLAAAJvAsAAAm9CwAACb4LAAAJvwsAAAnACwAACcELAAAJwgsAAAnDCwAACcQLAAAJxQsAAAnGCwAACccLAAAJyAsAAAnJCwAAByIBAAABAQAAADEAAAAHDwnKCwAACcsLAAAJzAsAAAnNCwAACc4LAAAJzwsAAAnQCwAACdELAAAJ0gsAAAnTCwAACdQLAAAJ1QsAAAnWCwAACdcLAAAJ2AsAAAnZCwAACdoLAAAJ2wsAAAncCwAACd0LAAAJ3gsAAAnfCwAACeALAAAJ4QsAAAniCwAACeMLAAAJ5AsAAAnlCwAACeYLAAAJ5wsAAAnoCwAACekLAAAJ6gsAAAnrCwAACewLAAAJ7QsAAAnuCwAACe8LAAAJ8AsAAAnxCwAACfILAAAJ8wsAAAn0CwAACfULAAAJ9gsAAAn3CwAACfgLAAAJ+QsAAAn6CwAAByYBAAABAQAAADEAAAAHDwn7CwAACfwLAAAJ/QsAAAn+CwAACf8LAAAJAAwAAAkBDAAACQIMAAAJAwwAAAkEDAAACQUMAAAJBgwAAAkHDAAACQgMAAAJCQwAAAkKDAAACQsMAAAJDAwAAAkNDAAACQ4MAAAJDwwAAAkQDAAACREMAAAJEgwAAAkTDAAACRQMAAAJFQwAAAkWDAAACRcMAAAJGAwAAAkZDAAACRoMAAAJGwwAAAkcDAAACR0MAAAJHgwAAAkfDAAACSAMAAAJIQwAAAkiDAAACSMMAAAJJAwAAAklDAAACSYMAAAJJwwAAAkoDAAACSkMAAAJKgwAAAkrDAAAByoBAAABAQAAADEAAAAHDwksDAAACS0MAAAJLgwAAAkvDAAACTAMAAAJMQwAAAkyDAAACTMMAAAJNAwAAAk1DAAACTYMAAAJNwwAAAk4DAAACTkMAAAJOgwAAAk7DAAACTwMAAAJPQwAAAk+DAAACT8MAAAJQAwAAAlBDAAACUIMAAAJQwwAAAlEDAAACUUMAAAJRgwAAAlHDAAACUgMAAAJSQwAAAlKDAAACUsMAAAJTAwAAAlNDAAACU4MAAAJTwwAAAlQDAAACVEMAAAJUgwAAAlTDAAACVQMAAAJVQwAAAlWDAAACVcMAAAJWAwAAAlZDAAACVoMAAAJWwwAAAlcDAAABy4BAAABAQAAADEAAAAHDwldDAAACV4MAAAJXwwAAAlgDAAACWEMAAAJYgwAAAljDAAACWQMAAAJZQwAAAlmDAAACWcMAAAJaAwAAAlpDAAACWoMAAAJawwAAAlsDAAACW0MAAAJbgwAAAlvDAAACXAMAAAJcQwAAAlyDAAACXMMAAAJdAwAAAl1DAAACXYMAAAJdwwAAAl4DAAACXkMAAAJegwAAAl7DAAACXwMAAAJfQwAAAl+DAAACX8MAAAJgAwAAAmBDAAACYIMAAAJgwwAAAmEDAAACYUMAAAJhgwAAAmHDAAACYgMAAAJiQwAAAmKDAAACYsMAAAJjAwAAAmNDAAABzIBAAABAQAAADEAAAAHDwmODAAACY8MAAAJkAwAAAmRDAAACZIMAAAJkwwAAAmUDAAACZUMAAAJlgwAAAmXDAAACZgMAAAJmQwAAAmaDAAACZsMAAAJnAwAAAmdDAAACZ4MAAAJnwwAAAmgDAAACaEMAAAJogwAAAmjDAAACaQMAAAJpQwAAAmmDAAACacMAAAJqAwAAAmpDAAACaoMAAAJqwwAAAmsDAAACa0MAAAJrgwAAAmvDAAACbAMAAAJsQwAAAmyDAAACbMMAAAJtAwAAAm1DAAACbYMAAAJtwwAAAm4DAAACbkMAAAJugwAAAm7DAAACbwMAAAJvQwAAAm+DAAABzYBAAABAQAAADEAAAAHDwm/DAAACcAMAAAJwQwAAAnCDAAACcMMAAAJxAwAAAnFDAAACcYMAAAJxwwAAAnIDAAACckMAAAJygwAAAnLDAAACcwMAAAJzQwAAAnODAAACc8MAAAJ0AwAAAnRDAAACdIMAAAJ0wwAAAnUDAAACdUMAAAJ1gwAAAnXDAAACdgMAAAJ2QwAAAnaDAAACdsMAAAJ3AwAAAndDAAACd4MAAAJ3wwAAAngDAAACeEMAAAJ4gwAAAnjDAAACeQMAAAJ5QwAAAnmDAAACecMAAAJ6AwAAAnpDAAACeoMAAAJ6wwAAAnsDAAACe0MAAAJ7gwAAAnvDAAABzoBAAABAQAAADEAAAAHDwnwDAAACfEMAAAJ8gwAAAnzDAAACfQMAAAJ9QwAAAn2DAAACfcMAAAJ+AwAAAn5DAAACfoMAAAJ+wwAAAn8DAAACf0MAAAJ/gwAAAn/DAAACQANAAAJAQ0AAAkCDQAACQMNAAAJBA0AAAkFDQAACQYNAAAJBw0AAAkIDQAACQkNAAAJCg0AAAkLDQAACQwNAAAJDQ0AAAkODQAACQ8NAAAJEA0AAAkRDQAACRINAAAJEw0AAAkUDQAACRUNAAAJFg0AAAkXDQAACRgNAAAJGQ0AAAkaDQAACRsNAAAJHA0AAAkdDQAACR4NAAAJHw0AAAkgDQAABz4BAAABAQAAADEAAAAHDwkhDQAACSINAAAJIw0AAAkkDQAACSUNAAAJJg0AAAknDQAACSgNAAAJKQ0AAAkqDQAACSsNAAAJLA0AAAktDQAACS4NAAAJLw0AAAkwDQAACTENAAAJMg0AAAkzDQAACTQNAAAJNQ0AAAk2DQAACTcNAAAJOA0AAAk5DQAACToNAAAJOw0AAAk8DQAACT0NAAAJPg0AAAk/DQAACUANAAAJQQ0AAAlCDQAACUMNAAAJRA0AAAlFDQAACUYNAAAJRw0AAAlIDQAACUkNAAAJSg0AAAlLDQAACUwNAAAJTQ0AAAlODQAACU8NAAAJUA0AAAlRDQAAB0IBAAABAQAAADEAAAAHDwlSDQAACVMNAAAJVA0AAAlVDQAACVYNAAAJVw0AAAlYDQAACVkNAAAJWg0AAAlbDQAACVwNAAAJXQ0AAAleDQAACV8NAAAJYA0AAAlhDQAACWINAAAJYw0AAAlkDQAACWUNAAAJZg0AAAlnDQAACWgNAAAJaQ0AAAlqDQAACWsNAAAJbA0AAAltDQAACW4NAAAJbw0AAAlwDQAACXENAAAJcg0AAAlzDQAACXQNAAAJdQ0AAAl2DQAACXcNAAAJeA0AAAl5DQAACXoNAAAJew0AAAl8DQAACX0NAAAJfg0AAAl/DQAACYANAAAJgQ0AAAmCDQAAD0MBAAACAAAAD2AAAAB+AAAAD0QBAAACAAAADzEAAAAhAAAAD0UBAAACAAAADzIAAABAAAAAD0YBAAACAAAADzMAAAAjAAAAD0cBAAACAAAADzQAAAAkAAAAD0gBAAACAAAADzUAAAAlAAAAD0kBAAACAAAADzYAAABeAAAAD0oBAAACAAAADzcAAAAmAAAAD0sBAAACAAAADzgAAAAqAAAAD0wBAAACAAAADzkAAAAoAAAAD00BAAACAAAADzAAAAApAAAAD04BAAACAAAADy0AAABfAAAAD08BAAACAAAADz0AAAArAAAAD1ABAAACAAAAD3EAAABRAAAAD1EBAAACAAAAD3cAAABXAAAAD1IBAAACAAAAD2UAAABFAAAAD1MBAAACAAAAD3IAAABSAAAAD1QBAAACAAAAD3QAAABUAAAAD1UBAAACAAAAD3kAAABZAAAAD1YBAAACAAAAD3UAAABVAAAAD1cBAAACAAAAD2kAAABJAAAAD1gBAAACAAAAD28AAABPAAAAD1kBAAACAAAAD3AAAABQAAAAD1oBAAACAAAAD1sAAAB7AAAAD1sBAAACAAAAD10AAAB9AAAAD1wBAAACAAAAD2EAAABBAAAAD10BAAACAAAAD3MAAABTAAAAD14BAAACAAAAD2QAAABEAAAAD18BAAACAAAAD2YAAABGAAAAD2ABAAACAAAAD2cAAABHAAAAD2EBAAACAAAAD2gAAABIAAAAD2IBAAACAAAAD2oAAABKAAAAD2MBAAACAAAAD2sAAABLAAAAD2QBAAACAAAAD2wAAABMAAAAD2UBAAACAAAADzsAAAA6AAAAD2YBAAACAAAADycAAAAiAAAAD2cBAAACAAAAD1wAAAB8AAAAD2gBAAACAAAAD3oAAABaAAAAD2kBAAACAAAAD3gAAABYAAAAD2oBAAACAAAAD2MAAABDAAAAD2sBAAACAAAAD3YAAABWAAAAD2wBAAACAAAAD2IAAABCAAAAD20BAAACAAAAD24AAABOAAAAD24BAAACAAAAD20AAABNAAAAD28BAAACAAAADywAAAA8AAAAD3ABAAACAAAADy4AAAA+AAAAD3EBAAACAAAADy8AAAA/AAAAD3IBAAAAAAAADw9zAQAAAAAAAA8PdAEAAAIAAAAPYAAAAH4AAAAPdQEAAAIAAAAPMQAAACEAAAAPdgEAAAIAAAAPMgAAAEAAAAAPdwEAAAIAAAAPMwAAACMAAAAPeAEAAAIAAAAPNAAAACQAAAAPeQEAAAIAAAAPNQAAACUAAAAPegEAAAIAAAAPNgAAAF4AAAAPewEAAAIAAAAPNwAAACYAAAAPfAEAAAIAAAAPOAAAACoAAAAPfQEAAAIAAAAPOQAAACgAAAAPfgEAAAIAAAAPMAAAACkAAAAPfwEAAAIAAAAPLQAAAF8AAAAPgAEAAAIAAAAPPQAAACsAAAAPgQEAAAIAAAAPcQAAAFEAAAAPggEAAAIAAAAPdwAAAFcAAAAPgwEAAAIAAAAPZQAAAEUAAAAPhAEAAAIAAAAPcgAAAFIAAAAPhQEAAAIAAAAPdAAAAFQAAAAPhgEAAAIAAAAPeQAAAFkAAAAPhwEAAAIAAAAPdQAAAFUAAAAPiAEAAAIAAAAPaQAAAEkAAAAPiQEAAAIAAAAPbwAAAE8AAAAPigEAAAIAAAAPcAAAAFAAAAAPiwEAAAIAAAAPWwAAAHsAAAAPjAEAAAIAAAAPXQAAAH0AAAAPjQEAAAIAAAAPYQAAAEEAAAAPjgEAAAIAAAAPcwAAAFMAAAAPjwEAAAIAAAAPZAAAAEQAAAAPkAEAAAIAAAAPZgAAAEYAAAAPkQEAAAIAAAAPZwAAAEcAAAAPkgEAAAIAAAAPaAAAAEgAAAAPkwEAAAIAAAAPagAAAEoAAAAPlAEAAAIAAAAPawAAAEsAAAAPlQEAAAIAAAAPbAAAAEwAAAAPlgEAAAIAAAAPOwAAADoAAAAPlwEAAAIAAAAPJwAAACIAAAAPmAEAAAIAAAAPXAAAAHwAAAAPmQEAAAIAAAAPegAAAFoAAAAPmgEAAAIAAAAPeAAAAFgAAAAPmwEAAAIAAAAPYwAAAEMAAAAPnAEAAAIAAAAPdgAAAFYAAAAPnQEAAAIAAAAPYgAAAEIAAAAPngEAAAIAAAAPbgAAAE4AAAAPnwEAAAIAAAAPbQAAAE0AAAAPoAEAAAIAAAAPLAAAADwAAAAPoQEAAAIAAAAPLgAAAD4AAAAPogEAAAIAAAAPLwAAAD8AAAAPowEAAAIAAAAPPAAAAD4AAAAPpAEAAAAAAAAPD6UBAAACAAAAD2AAAAB+AAAAD6YBAAACAAAADzEAAAAhAAAAD6cBAAACAAAADzIAAABAAAAAD6gBAAACAAAADzMAAAAjAAAAD6kBAAACAAAADzQAAAAkAAAAD6oBAAACAAAADzUAAAAlAAAAD6sBAAACAAAADzYAAABeAAAAD6wBAAACAAAADzcAAAAmAAAAD60BAAACAAAADzgAAAAqAAAAD64BAAACAAAADzkAAAAoAAAAD68BAAACAAAADzAAAAApAAAAD7ABAAACAAAAD1sAAAB7AAAAD7EBAAACAAAAD10AAAB9AAAAD7IBAAACAAAADycAAAAiAAAAD7MBAAACAAAADywAAAA8AAAAD7QBAAACAAAADy4AAAA+AAAAD7UBAAACAAAAD3AAAABQAAAAD7YBAAACAAAAD3kAAABZAAAAD7cBAAACAAAAD2YAAABGAAAAD7gBAAACAAAAD2cAAABHAAAAD7kBAAACAAAAD2MAAABDAAAAD7oBAAACAAAAD3IAAABSAAAAD7sBAAACAAAAD2wAAABMAAAAD7wBAAACAAAADy8AAAA/AAAAD70BAAACAAAADz0AAAArAAAAD74BAAACAAAAD2EAAABBAAAAD78BAAACAAAAD28AAABPAAAAD8ABAAACAAAAD2UAAABFAAAAD8EBAAACAAAAD3UAAABVAAAAD8IBAAACAAAAD2kAAABJAAAAD8MBAAACAAAAD2QAAABEAAAAD8QBAAACAAAAD2gAAABIAAAAD8UBAAACAAAAD3QAAABUAAAAD8YBAAACAAAAD24AAABOAAAAD8cBAAACAAAAD3MAAABTAAAAD8gBAAACAAAADy0AAABfAAAAD8kBAAACAAAAD1wAAAB8AAAAD8oBAAACAAAADzsAAAA6AAAAD8sBAAACAAAAD3EAAABRAAAAD8wBAAACAAAAD2oAAABKAAAAD80BAAACAAAAD2sAAABLAAAAD84BAAACAAAAD3gAAABYAAAAD88BAAACAAAAD2IAAABCAAAAD9ABAAACAAAAD20AAABNAAAAD9EBAAACAAAAD3cAAABXAAAAD9IBAAACAAAAD3YAAABWAAAAD9MBAAACAAAAD3oAAABaAAAAD9QBAAAAAAAADw/VAQAAAAAAAA8P1gEAAAIAAAAPYAAAAH4AAAAP1wEAAAIAAAAPMQAAACEAAAAP2AEAAAIAAAAPMgAAAEAAAAAP2QEAAAIAAAAPMwAAACMAAAAP2gEAAAIAAAAPNAAAACQAAAAP2wEAAAIAAAAPNQAAACUAAAAP3AEAAAIAAAAPNgAAAF4AAAAP3QEAAAIAAAAPNwAAACYAAAAP3gEAAAIAAAAPOAAAACoAAAAP3wEAAAIAAAAPOQAAACgAAAAP4AEAAAIAAAAPMAAAACkAAAAP4QEAAAIAAAAPLQAAAF8AAAAP4gEAAAIAAAAPPQAAACsAAAAP4wEAAAIAAAAPXAAAAHwAAAAP5AEAAAIAAAAPcQAAAFEAAAAP5QEAAAIAAAAPdwAAAFcAAAAP5gEAAAIAAAAPZQAAAEUAAAAP5wEAAAIAAAAPcgAAAFIAAAAP6AEAAAIAAAAPdAAAAFQAAAAP6QEAAAIAAAAPeQAAAFkAAAAP6gEAAAIAAAAPdQAAAFUAAAAP6wEAAAIAAAAPaQAAAEkAAAAP7AEAAAIAAAAPbwAAAE8AAAAP7QEAAAIAAAAPcAAAAFAAAAAP7gEAAAIAAAAPWwAAAHsAAAAP7wEAAAIAAAAPXQAAAH0AAAAP8AEAAAIAAAAPYQAAAEEAAAAP8QEAAAIAAAAPcwAAAFMAAAAP8gEAAAIAAAAPZAAAAEQAAAAP8wEAAAIAAAAPZgAAAEYAAAAP9AEAAAIAAAAPZwAAAEcAAAAP9QEAAAIAAAAPaAAAAEgAAAAP9gEAAAIAAAAPagAAAEoAAAAP9wEAAAIAAAAPawAAAEsAAAAP+AEAAAIAAAAPbAAAAEwAAAAP+QEAAAIAAAAPOwAAADoAAAAP+gEAAAIAAAAPJwAAACIAAAAP+wEAAAIAAAAPegAAAFoAAAAP/AEAAAIAAAAPeAAAAFgAAAAP/QEAAAIAAAAPYwAAAEMAAAAP/gEAAAIAAAAPdgAAAFYAAAAP/wEAAAIAAAAPYgAAAEIAAAAPAAIAAAIAAAAPbgAAAE4AAAAPAQIAAAIAAAAPbQAAAE0AAAAPAgIAAAIAAAAPLAAAADwAAAAPAwIAAAIAAAAPLgAAAD4AAAAPBAIAAAIAAAAPLwAAAD8AAAAPBQIAAAAAAAAPDwYCAAAAAAAADw8HAgAAAQAAAA9gAAAADwgCAAACAAAADzEAAAAhAAAADwkCAAACAAAADzIAAAAiAAAADwoCAAACAAAADzMAAACj////DwsCAAACAAAADzQAAAAkAAAADwwCAAACAAAADzUAAAAlAAAADw0CAAACAAAADzYAAABeAAAADw4CAAACAAAADzcAAAAmAAAADw8CAAACAAAADzgAAAAqAAAADxACAAACAAAADzkAAAAoAAAADxECAAACAAAADzAAAAApAAAADxICAAACAAAADy0AAABfAAAADxMCAAACAAAADz0AAAArAAAADxQCAAACAAAAD3EAAABRAAAADxUCAAACAAAAD3cAAABXAAAADxYCAAACAAAAD2UAAABFAAAADxcCAAACAAAAD3IAAABSAAAADxgCAAACAAAAD3QAAABUAAAADxkCAAACAAAAD3kAAABZAAAADxoCAAACAAAAD3UAAABVAAAADxsCAAACAAAAD2kAAABJAAAADxwCAAACAAAAD28AAABPAAAADx0CAAACAAAAD3AAAABQAAAADx4CAAACAAAAD1sAAAB7AAAADx8CAAACAAAAD10AAAB9AAAADyACAAACAAAAD2EAAABBAAAADyECAAACAAAAD3MAAABTAAAADyICAAACAAAAD2QAAABEAAAADyMCAAACAAAAD2YAAABGAAAADyQCAAACAAAAD2cAAABHAAAADyUCAAACAAAAD2gAAABIAAAADyYCAAACAAAAD2oAAABKAAAADycCAAACAAAAD2sAAABLAAAADygCAAACAAAAD2wAAABMAAAADykCAAACAAAADzsAAAA6AAAADyoCAAACAAAADycAAABAAAAADysCAAACAAAADyMAAAB+AAAADywCAAACAAAAD3oAAABaAAAADy0CAAACAAAAD3gAAABYAAAADy4CAAACAAAAD2MAAABDAAAADy8CAAACAAAAD3YAAABWAAAADzACAAACAAAAD2IAAABCAAAADzECAAACAAAAD24AAABOAAAADzICAAACAAAAD20AAABNAAAADzMCAAACAAAADywAAAA8AAAADzQCAAACAAAADy4AAAA+AAAADzUCAAACAAAADy8AAAA/AAAADzYCAAACAAAAD1wAAAB8AAAADzcCAAAAAAAADw84AgAAAgAAAA9eAAAAsP///w85AgAAAgAAAA8xAAAAIQAAAA86AgAAAgAAAA8yAAAAIgAAAA87AgAAAgAAAA8zAAAAp////w88AgAAAgAAAA80AAAAJAAAAA89AgAAAgAAAA81AAAAJQAAAA8+AgAAAgAAAA82AAAAJgAAAA8/AgAAAgAAAA83AAAALwAAAA9AAgAAAgAAAA84AAAAKAAAAA9BAgAAAgAAAA85AAAAKQAAAA9CAgAAAgAAAA8wAAAAPQAAAA9DAgAAAgAAAA/f////PwAAAA9EAgAAAgAAAA+0////YAAAAA9FAgAAAgAAAA9xAAAAUQAAAA9GAgAAAgAAAA93AAAAVwAAAA9HAgAAAgAAAA9lAAAARQAAAA9IAgAAAgAAAA9yAAAAUgAAAA9JAgAAAgAAAA90AAAAVAAAAA9KAgAAAgAAAA96AAAAWgAAAA9LAgAAAgAAAA91AAAAVQAAAA9MAgAAAgAAAA9pAAAASQAAAA9NAgAAAgAAAA9vAAAATwAAAA9OAgAAAgAAAA9wAAAAUAAAAA9PAgAAAgAAAA/8////3P///w9QAgAAAgAAAA8rAAAAKgAAAA9RAgAAAgAAAA9hAAAAQQAAAA9SAgAAAgAAAA9zAAAAUwAAAA9TAgAAAgAAAA9kAAAARAAAAA9UAgAAAgAAAA9mAAAARgAAAA9VAgAAAgAAAA9nAAAARwAAAA9WAgAAAgAAAA9oAAAASAAAAA9XAgAAAgAAAA9qAAAASgAAAA9YAgAAAgAAAA9rAAAASwAAAA9ZAgAAAgAAAA9sAAAATAAAAA9aAgAAAgAAAA/2////1v///w9bAgAAAgAAAA/k////xP///w9cAgAAAgAAAA8jAAAAJwAAAA9dAgAAAgAAAA95AAAAWQAAAA9eAgAAAgAAAA94AAAAWAAAAA9fAgAAAgAAAA9jAAAAQwAAAA9gAgAAAgAAAA92AAAAVgAAAA9hAgAAAgAAAA9iAAAAQgAAAA9iAgAAAgAAAA9uAAAATgAAAA9jAgAAAgAAAA9tAAAATQAAAA9kAgAAAgAAAA8sAAAAOwAAAA9lAgAAAgAAAA8uAAAAOgAAAA9mAgAAAgAAAA8tAAAAXwAAAA9nAgAAAwAAAA88AAAAPgAAAHwAAAAPaAIAAAAAAAAPD2kCAAACAAAAD14AAACw////D2oCAAACAAAADzEAAAAhAAAAD2sCAAACAAAADzIAAAAiAAAAD2wCAAACAAAADzMAAACn////D20CAAACAAAADzQAAAAkAAAAD24CAAACAAAADzUAAAAlAAAAD28CAAACAAAADzYAAAAmAAAAD3ACAAADAAAADzcAAAAvAAAAewAAAA9xAgAAAwAAAA84AAAAKAAAAFsAAAAPcgIAAAMAAAAPOQAAACkAAABdAAAAD3MCAAADAAAADzAAAAA9AAAAfQAAAA90AgAAAwAAAA/f////PwAAAFwAAAAPdQIAAAEAAAAPtP///w92AgAAAgAAAA9xAAAAUQAAAA93AgAAAgAAAA93AAAAVwAAAA94AgAAAgAAAA9lAAAARQAAAA95AgAAAgAAAA9yAAAAUgAAAA96AgAAAgAAAA90AAAAVAAAAA97AgAAAgAAAA96AAAAWgAAAA98AgAAAgAAAA91AAAAVQAAAA99AgAAAgAAAA9pAAAASQAAAA9+AgAAAgAAAA9vAAAATwAAAA9/AgAAAgAAAA9wAAAAUAAAAA+AAgAAAgAAAA/8////3P///w+BAgAAAwAAAA8rAAAAKgAAAH4AAAAPggIAAAIAAAAPYQAAAEEAAAAPgwIAAAIAAAAPcwAAAFMAAAAPhAIAAAIAAAAPZAAAAEQAAAAPhQIAAAIAAAAPZgAAAEYAAAAPhgIAAAIAAAAPZwAAAEcAAAAPhwIAAAIAAAAPaAAAAEgAAAAPiAIAAAIAAAAPagAAAEoAAAAPiQIAAAIAAAAPawAAAEsAAAAPigIAAAIAAAAPbAAAAEwAAAAPiwIAAAIAAAAP9v///9b///8PjAIAAAIAAAAP5P///8T///8PjQIAAAIAAAAPIwAAACcAAAAPjgIAAAIAAAAPeQAAAFkAAAAPjwIAAAIAAAAPeAAAAFgAAAAPkAIAAAIAAAAPYwAAAEMAAAAPkQIAAAIAAAAPdgAAAFYAAAAPkgIAAAIAAAAPYgAAAEIAAAAPkwIAAAIAAAAPbgAAAE4AAAAPlAIAAAIAAAAPbQAAAE0AAAAPlQIAAAIAAAAPLAAAADsAAAAPlgIAAAIAAAAPLgAAADoAAAAPlwIAAAIAAAAPLQAAAF8AAAAPmAIAAAIAAAAPPAAAAD4AAAAPmQIAAAAAAAAPD5oCAAACAAAAD14AAACw////D5sCAAACAAAADzEAAAAhAAAAD5wCAAACAAAADzIAAAAiAAAAD50CAAACAAAADzMAAACn////D54CAAACAAAADzQAAAAkAAAAD58CAAACAAAADzUAAAAlAAAAD6ACAAACAAAADzYAAAAmAAAAD6ECAAADAAAADzcAAAAvAAAAewAAAA+iAgAAAwAAAA84AAAAKAAAAFsAAAAPowIAAAMAAAAPOQAAACkAAABdAAAAD6QCAAADAAAADzAAAAA9AAAAfQAAAA+lAgAAAwAAAA/f////PwAAAFwAAAAPpgIAAAIAAAAPJwAAAGAAAAAPpwIAAAMAAAAPcQAAAFEAAABAAAAAD6gCAAACAAAAD3cAAABXAAAAD6kCAAACAAAAD2UAAABFAAAAD6oCAAACAAAAD3IAAABSAAAAD6sCAAACAAAAD3QAAABUAAAAD6wCAAACAAAAD3oAAABaAAAAD60CAAACAAAAD3UAAABVAAAAD64CAAACAAAAD2kAAABJAAAAD68CAAACAAAAD28AAABPAAAAD7ACAAACAAAAD3AAAABQAAAAD7ECAAACAAAAD/z////c////D7ICAAADAAAADysAAAAqAAAAfgAAAA+zAgAAAgAAAA9hAAAAQQAAAA+0AgAAAgAAAA9zAAAAUwAAAA+1AgAAAgAAAA9kAAAARAAAAA+2AgAAAgAAAA9mAAAARgAAAA+3AgAAAgAAAA9nAAAARwAAAA+4AgAAAgAAAA9oAAAASAAAAA+5AgAAAgAAAA9qAAAASgAAAA+6AgAAAgAAAA9rAAAASwAAAA+7AgAAAgAAAA9sAAAATAAAAA+8AgAAAgAAAA/2////1v///w+9AgAAAgAAAA/k////xP///w++AgAAAgAAAA8jAAAAJwAAAA+/AgAAAgAAAA95AAAAWQAAAA/AAgAAAgAAAA94AAAAWAAAAA/BAgAAAgAAAA9jAAAAQwAAAA/CAgAAAgAAAA92AAAAVgAAAA/DAgAAAgAAAA9iAAAAQgAAAA/EAgAAAgAAAA9uAAAATgAAAA/FAgAAAgAAAA9tAAAATQAAAA/GAgAAAgAAAA8sAAAAOwAAAA/HAgAAAgAAAA8uAAAAOgAAAA/IAgAAAgAAAA8tAAAAXwAAAA/JAgAAAwAAAA88AAAAPgAAAHwAAAAPygIAAAAAAAAPD8sCAAACAAAAD14AAACw////D8wCAAACAAAADzEAAAAhAAAAD80CAAADAAAADzIAAAAiAAAAsv///w/OAgAAAwAAAA8zAAAAp////7P///8PzwIAAAIAAAAPNAAAACQAAAAP0AIAAAIAAAAPNQAAACUAAAAP0QIAAAIAAAAPNgAAACYAAAAP0gIAAAMAAAAPNwAAAC8AAAB7AAAAD9MCAAADAAAADzgAAAAoAAAAWwAAAA/UAgAAAwAAAA85AAAAKQAAAF0AAAAP1QIAAAMAAAAPMAAAAD0AAAB9AAAAD9YCAAADAAAAD9////8/AAAAXAAAAA/XAgAAAgAAAA8nAAAAYAAAAA/YAgAAAwAAAA9xAAAAUQAAAEAAAAAP2QIAAAIAAAAPdwAAAFcAAAAP2gIAAAIAAAAPZQAAAEUAAAAP2wIAAAIAAAAPcgAAAFIAAAAP3AIAAAIAAAAPdAAAAFQAAAAP3QIAAAIAAAAPegAAAFoAAAAP3gIAAAIAAAAPdQAAAFUAAAAP3wIAAAIAAAAPaQAAAEkAAAAP4AIAAAIAAAAPbwAAAE8AAAAP4QIAAAIAAAAPcAAAAFAAAAAP4gIAAAIAAAAP/P///9z///8P4wIAAAMAAAAPKwAAACoAAAB+AAAAD+QCAAACAAAAD2EAAABBAAAAD+UCAAACAAAAD3MAAABTAAAAD+YCAAACAAAAD2QAAABEAAAAD+cCAAACAAAAD2YAAABGAAAAD+gCAAACAAAAD2cAAABHAAAAD+kCAAACAAAAD2gAAABIAAAAD+oCAAACAAAAD2oAAABKAAAAD+sCAAACAAAAD2sAAABLAAAAD+wCAAACAAAAD2wAAABMAAAAD+0CAAACAAAAD/b////W////D+4CAAACAAAAD+T////E////D+8CAAACAAAADyMAAAAnAAAAD/ACAAADAAAADzwAAAA+AAAAfAAAAA/xAgAAAgAAAA95AAAAWQAAAA/yAgAAAgAAAA94AAAAWAAAAA/zAgAAAgAAAA9jAAAAQwAAAA/0AgAAAgAAAA92AAAAVgAAAA/1AgAAAgAAAA9iAAAAQgAAAA/2AgAAAgAAAA9uAAAATgAAAA/3AgAAAgAAAA9tAAAATQAAAA/4AgAAAgAAAA8sAAAAOwAAAA/5AgAAAgAAAA8uAAAAOgAAAA/6AgAAAgAAAA8tAAAAXwAAAA/7AgAAAAAAAA8P/AIAAAIAAAAPp////7D///8P/QIAAAIAAAAPMQAAACsAAAAP/gIAAAIAAAAPMgAAACIAAAAP/wIAAAIAAAAPMwAAACoAAAAPAAMAAAIAAAAPNAAAAOf///8PAQMAAAIAAAAPNQAAACUAAAAPAgMAAAIAAAAPNgAAACYAAAAPAwMAAAIAAAAPNwAAAC8AAAAPBAMAAAIAAAAPOAAAACgAAAAPBQMAAAIAAAAPOQAAACkAAAAPBgMAAAIAAAAPMAAAAD0AAAAPBwMAAAIAAAAPJwAAAD8AAAAPCAMAAAIAAAAPXgAAAGAAAAAPCQMAAAIAAAAPcQAAAFEAAAAPCgMAAAIAAAAPdwAAAFcAAAAPCwMAAAIAAAAPZQAAAEUAAAAPDAMAAAIAAAAPcgAAAFIAAAAPDQMAAAIAAAAPdAAAAFQAAAAPDgMAAAIAAAAPegAAAFoAAAAPDwMAAAIAAAAPdQAAAFUAAAAPEAMAAAIAAAAPaQAAAEkAAAAPEQMAAAIAAAAPbwAAAE8AAAAPEgMAAAIAAAAPcAAAAFAAAAAPEwMAAAIAAAAP/P///+j///8PFAMAAAIAAAAPqP///yEAAAAPFQMAAAIAAAAPYQAAAEEAAAAPFgMAAAIAAAAPcwAAAFMAAAAPFwMAAAIAAAAPZAAAAEQAAAAPGAMAAAIAAAAPZgAAAEYAAAAPGQMAAAIAAAAPZwAAAEcAAAAPGgMAAAIAAAAPaAAAAEgAAAAPGwMAAAIAAAAPagAAAEoAAAAPHAMAAAIAAAAPawAAAEsAAAAPHQMAAAIAAAAPbAAAAEwAAAAPHgMAAAIAAAAP9v///+n///8PHwMAAAIAAAAP5P///+D///8PIAMAAAIAAAAPJAAAAKP///8PIQMAAAIAAAAPeQAAAFkAAAAPIgMAAAIAAAAPeAAAAFgAAAAPIwMAAAIAAAAPYwAAAEMAAAAPJAMAAAIAAAAPdgAAAFYAAAAPJQMAAAIAAAAPYgAAAEIAAAAPJgMAAAIAAAAPbgAAAE4AAAAPJwMAAAIAAAAPbQAAAE0AAAAPKAMAAAIAAAAPLAAAADsAAAAPKQMAAAIAAAAPLgAAADoAAAAPKgMAAAIAAAAPLQAAAF8AAAAPKwMAAAIAAAAPPAAAAD4AAAAPLAMAAAAAAAAPDy0DAAACAAAAD6f///+w////Dy4DAAACAAAADzEAAAArAAAADy8DAAACAAAADzIAAAAiAAAADzADAAACAAAADzMAAAAqAAAADzEDAAACAAAADzQAAADn////DzIDAAACAAAADzUAAAAlAAAADzMDAAACAAAADzYAAAAmAAAADzQDAAACAAAADzcAAAAvAAAADzUDAAACAAAADzgAAAAoAAAADzYDAAACAAAADzkAAAApAAAADzcDAAACAAAADzAAAAA9AAAADzgDAAACAAAADycAAAA/AAAADzkDAAACAAAAD14AAABgAAAADzoDAAACAAAAD3EAAABRAAAADzsDAAACAAAAD3cAAABXAAAADzwDAAACAAAAD2UAAABFAAAADz0DAAACAAAAD3IAAABSAAAADz4DAAACAAAAD3QAAABUAAAADz8DAAACAAAAD3oAAABaAAAAD0ADAAACAAAAD3UAAABVAAAAD0EDAAACAAAAD2kAAABJAAAAD0IDAAACAAAAD28AAABPAAAAD0MDAAACAAAAD3AAAABQAAAAD0QDAAACAAAAD+j////8////D0UDAAACAAAAD6j///8hAAAAD0YDAAACAAAAD2EAAABBAAAAD0cDAAACAAAAD3MAAABTAAAAD0gDAAACAAAAD2QAAABEAAAAD0kDAAACAAAAD2YAAABGAAAAD0oDAAACAAAAD2cAAABHAAAAD0sDAAACAAAAD2gAAABIAAAAD0wDAAACAAAAD2oAAABKAAAAD00DAAACAAAAD2sAAABLAAAAD04DAAACAAAAD2wAAABMAAAAD08DAAACAAAAD+n////2////D1ADAAACAAAAD+D////k////D1EDAAACAAAADyQAAACj////D1IDAAACAAAAD3kAAABZAAAAD1MDAAACAAAAD3gAAABYAAAAD1QDAAACAAAAD2MAAABDAAAAD1UDAAACAAAAD3YAAABWAAAAD1YDAAACAAAAD2IAAABCAAAAD1cDAAACAAAAD24AAABOAAAAD1gDAAACAAAAD20AAABNAAAAD1kDAAACAAAADywAAAA7AAAAD1oDAAACAAAADy4AAAA6AAAAD1sDAAACAAAADy0AAABfAAAAD1wDAAACAAAADzwAAAA+AAAAD10DAAAAAAAADw9eAwAAAgAAAA+n////vf///w9fAwAAAgAAAA8xAAAAIQAAAA9gAwAAAgAAAA8yAAAAIgAAAA9hAwAAAgAAAA8zAAAAIwAAAA9iAwAAAgAAAA80AAAApP///w9jAwAAAgAAAA81AAAAJQAAAA9kAwAAAgAAAA82AAAAJgAAAA9lAwAAAgAAAA83AAAALwAAAA9mAwAAAgAAAA84AAAAKAAAAA9nAwAAAgAAAA85AAAAKQAAAA9oAwAAAgAAAA8wAAAAPQAAAA9pAwAAAgAAAA8rAAAAPwAAAA9qAwAAAgAAAA+0////YAAAAA9rAwAAAgAAAA9xAAAAUQAAAA9sAwAAAgAAAA93AAAAVwAAAA9tAwAAAgAAAA9lAAAARQAAAA9uAwAAAgAAAA9yAAAAUgAAAA9vAwAAAgAAAA90AAAAVAAAAA9wAwAAAgAAAA95AAAAWQAAAA9xAwAAAgAAAA91AAAAVQAAAA9yAwAAAgAAAA9pAAAASQAAAA9zAwAAAgAAAA9vAAAATwAAAA90AwAAAgAAAA9wAAAAUAAAAA91AwAAAgAAAA/l////xf///w92AwAAAgAAAA+o////XgAAAA93AwAAAgAAAA9hAAAAQQAAAA94AwAAAgAAAA9zAAAAUwAAAA95AwAAAgAAAA9kAAAARAAAAA96AwAAAgAAAA9mAAAARgAAAA97AwAAAgAAAA9nAAAARwAAAA98AwAAAgAAAA9oAAAASAAAAA99AwAAAgAAAA9qAAAASgAAAA9+AwAAAgAAAA9rAAAASwAAAA9/AwAAAgAAAA9sAAAATAAAAA+AAwAAAgAAAA/2////1v///w+BAwAAAgAAAA/k////xP///w+CAwAAAgAAAA8nAAAAKgAAAA+DAwAAAgAAAA96AAAAWgAAAA+EAwAAAgAAAA94AAAAWAAAAA+FAwAAAgAAAA9jAAAAQwAAAA+GAwAAAgAAAA92AAAAVgAAAA+HAwAAAgAAAA9iAAAAQgAAAA+IAwAAAgAAAA9uAAAATgAAAA+JAwAAAgAAAA9tAAAATQAAAA+KAwAAAgAAAA8sAAAAOwAAAA+LAwAAAgAAAA8uAAAAOgAAAA+MAwAAAgAAAA8tAAAAXwAAAA+NAwAAAgAAAA88AAAAPgAAAA+OAwAAAAAAAA8PjwMAAAIAAAAPt////34AAAAPkAMAAAIAAAAPMQAAACEAAAAPkQMAAAIAAAAPMgAAACIAAAAPkgMAAAIAAAAPMwAAACMAAAAPkwMAAAIAAAAPNAAAAKT///8PlAMAAAIAAAAPNQAAACUAAAAPlQMAAAIAAAAPNgAAACYAAAAPlgMAAAIAAAAPNwAAAC8AAAAPlwMAAAIAAAAPOAAAACgAAAAPmAMAAAIAAAAPOQAAACkAAAAPmQMAAAIAAAAPMAAAAD0AAAAPmgMAAAIAAAAPKwAAAD8AAAAPmwMAAAIAAAAPtP///2AAAAAPnAMAAAIAAAAPcQAAAFEAAAAPnQMAAAIAAAAPdwAAAFcAAAAPngMAAAIAAAAPZQAAAEUAAAAPnwMAAAIAAAAPcgAAAFIAAAAPoAMAAAIAAAAPdAAAAFQAAAAPoQMAAAIAAAAPeQAAAFkAAAAPogMAAAIAAAAPdQAAAFUAAAAPowMAAAIAAAAPaQAAAEkAAAAPpAMAAAIAAAAPbwAAAE8AAAAPpQMAAAIAAAAPcAAAAFAAAAAPpgMAAAIAAAAP/P///9z///8PpwMAAAIAAAAP9f///9X///8PqAMAAAIAAAAPYQAAAEEAAAAPqQMAAAIAAAAPcwAAAFMAAAAPqgMAAAIAAAAPZAAAAEQAAAAPqwMAAAIAAAAPZgAAAEYAAAAPrAMAAAIAAAAPZwAAAEcAAAAPrQMAAAIAAAAPaAAAAEgAAAAPrgMAAAIAAAAPagAAAEoAAAAPrwMAAAIAAAAPawAAAEsAAAAPsAMAAAIAAAAPbAAAAEwAAAAPsQMAAAIAAAAP9v///9b///8PsgMAAAIAAAAP5P///8T///8PswMAAAIAAAAPJwAAACoAAAAPtAMAAAIAAAAPegAAAFoAAAAPtQMAAAIAAAAPeAAAAFgAAAAPtgMAAAIAAAAPYwAAAEMAAAAPtwMAAAIAAAAPdgAAAFYAAAAPuAMAAAIAAAAPYgAAAEIAAAAPuQMAAAIAAAAPbgAAAE4AAAAPugMAAAIAAAAPbQAAAE0AAAAPuwMAAAIAAAAPLAAAADsAAAAPvAMAAAIAAAAPLgAAADoAAAAPvQMAAAIAAAAPLQAAAF8AAAAPvgMAAAIAAAAPPAAAAD4AAAAPvwMAAAAAAAAPD8ADAAACAAAAD3wAAACn////D8EDAAACAAAADzEAAAAhAAAAD8IDAAADAAAADzIAAAAiAAAAQAAAAA/DAwAAAwAAAA8zAAAAIwAAAKP///8PxAMAAAMAAAAPNAAAAKT///8kAAAAD8UDAAACAAAADzUAAAAlAAAAD8YDAAACAAAADzYAAAAmAAAAD8cDAAADAAAADzcAAAAvAAAAewAAAA/IAwAAAwAAAA84AAAAKAAAAFsAAAAPyQMAAAMAAAAPOQAAACkAAABdAAAAD8oDAAADAAAADzAAAAA9AAAAfQAAAA/LAwAAAgAAAA8rAAAAPwAAAA/MAwAAAwAAAA9cAAAAYAAAALT///8PzQMAAAIAAAAPcQAAAFEAAAAPzgMAAAIAAAAPdwAAAFcAAAAPzwMAAAIAAAAPZQAAAEUAAAAP0AMAAAIAAAAPcgAAAFIAAAAP0QMAAAIAAAAPdAAAAFQAAAAP0gMAAAIAAAAPeQAAAFkAAAAP0wMAAAIAAAAPdQAAAFUAAAAP1AMAAAIAAAAPaQAAAEkAAAAP1QMAAAIAAAAPbwAAAE8AAAAP1gMAAAIAAAAPcAAAAFAAAAAP1wMAAAIAAAAP5f///8X///8P2AMAAAMAAAAPqP///14AAAB+AAAAD9kDAAACAAAAD2EAAABBAAAAD9oDAAACAAAAD3MAAABTAAAAD9sDAAACAAAAD2QAAABEAAAAD9wDAAACAAAAD2YAAABGAAAAD90DAAACAAAAD2cAAABHAAAAD94DAAACAAAAD2gAAABIAAAAD98DAAACAAAAD2oAAABKAAAAD+ADAAACAAAAD2sAAABLAAAAD+EDAAACAAAAD2wAAABMAAAAD+IDAAACAAAAD/j////Y////D+MDAAACAAAAD+b////G////D+QDAAACAAAADycAAAAqAAAAD+UDAAACAAAAD3oAAABaAAAAD+YDAAACAAAAD3gAAABYAAAAD+cDAAACAAAAD2MAAABDAAAAD+gDAAACAAAAD3YAAABWAAAAD+kDAAACAAAAD2IAAABCAAAAD+oDAAACAAAAD24AAABOAAAAD+sDAAACAAAAD20AAABNAAAAD+wDAAACAAAADywAAAA7AAAAD+0DAAACAAAADy4AAAA6AAAAD+4DAAACAAAADy0AAABfAAAAD+8DAAACAAAADzwAAAA+AAAAD/ADAAAAAAAADw/xAwAAAgAAAA+9////p////w/yAwAAAgAAAA8xAAAAIQAAAA/zAwAAAgAAAA8yAAAAIgAAAA/0AwAAAgAAAA8zAAAAIwAAAA/1AwAAAgAAAA80AAAApP///w/2AwAAAgAAAA81AAAAJQAAAA/3AwAAAgAAAA82AAAAJgAAAA/4AwAAAgAAAA83AAAALwAAAA/5AwAAAgAAAA84AAAAKAAAAA/6AwAAAgAAAA85AAAAKQAAAA/7AwAAAgAAAA8wAAAAPQAAAA/8AwAAAgAAAA8rAAAAPwAAAA/9AwAAAgAAAA+0////YAAAAA/+AwAAAgAAAA9xAAAAUQAAAA//AwAAAgAAAA93AAAAVwAAAA8ABAAAAgAAAA9lAAAARQAAAA8BBAAAAgAAAA9yAAAAUgAAAA8CBAAAAgAAAA90AAAAVAAAAA8DBAAAAgAAAA95AAAAWQAAAA8EBAAAAgAAAA91AAAAVQAAAA8FBAAAAgAAAA9pAAAASQAAAA8GBAAAAgAAAA9vAAAATwAAAA8HBAAAAgAAAA9wAAAAUAAAAA8IBAAAAgAAAA/l////xf///w8JBAAAAgAAAA+o////XgAAAA8KBAAAAgAAAA9hAAAAQQAAAA8LBAAAAgAAAA9zAAAAUwAAAA8MBAAAAgAAAA9kAAAARAAAAA8NBAAAAgAAAA9mAAAARgAAAA8OBAAAAgAAAA9nAAAARwAAAA8PBAAAAgAAAA9oAAAASAAAAA8QBAAAAgAAAA9qAAAASgAAAA8RBAAAAgAAAA9rAAAASwAAAA8SBAAAAgAAAA9sAAAATAAAAA8TBAAAAgAAAA/m////xv///w8UBAAAAgAAAA/4////2P///w8VBAAAAgAAAA8nAAAAKgAAAA8WBAAAAgAAAA96AAAAWgAAAA8XBAAAAgAAAA94AAAAWAAAAA8YBAAAAgAAAA9jAAAAQwAAAA8ZBAAAAgAAAA92AAAAVgAAAA8aBAAAAgAAAA9iAAAAQgAAAA8bBAAAAgAAAA9uAAAATgAAAA8cBAAAAgAAAA9tAAAATQAAAA8dBAAAAgAAAA8sAAAAOwAAAA8eBAAAAgAAAA8uAAAAOgAAAA8fBAAAAgAAAA8tAAAAXwAAAA8gBAAAAgAAAA88AAAAPgAAAA8hBAAAAAAAAA8PIgQAAAEAAAAPsv///w8jBAAAAgAAAA8mAAAAMQAAAA8kBAAAAwAAAA/p////MgAAAH4AAAAPJQQAAAMAAAAPIgAAADMAAAAjAAAADyYEAAADAAAADycAAAA0AAAAewAAAA8nBAAAAwAAAA8oAAAANQAAAFsAAAAPKAQAAAMAAAAPLQAAADYAAAB8AAAADykEAAADAAAAD+j///83AAAAYAAAAA8qBAAAAwAAAA9fAAAAOAAAAFwAAAAPKwQAAAQAAAAP5////zkAAABeAAAAsf///w8sBAAAAwAAAA/g////MAAAAEAAAAAPLQQAAAMAAAAPKQAAALD///9dAAAADy4EAAADAAAADz0AAAArAAAAfQAAAA8vBAAAAgAAAA9hAAAAQQAAAA8wBAAAAgAAAA96AAAAWgAAAA8xBAAAAwAAAA9lAAAARQAAAL////8PMgQAAAIAAAAPcgAAAFIAAAAPMwQAAAIAAAAPdAAAAFQAAAAPNAQAAAIAAAAPeQAAAFkAAAAPNQQAAAIAAAAPdQAAAFUAAAAPNgQAAAIAAAAPaQAAAEkAAAAPNwQAAAIAAAAPbwAAAE8AAAAPOAQAAAIAAAAPcAAAAFAAAAAPOQQAAAIAAAAPXgAAAKj///8POgQAAAMAAAAPJAAAAKP///+k////DzsEAAACAAAAD3EAAABRAAAADzwEAAADAAAAD3MAAABTAAAA3////w89BAAAAgAAAA9kAAAARAAAAA8+BAAAAgAAAA9mAAAARgAAAA8/BAAAAgAAAA9nAAAARwAAAA9ABAAAAgAAAA9oAAAASAAAAA9BBAAAAgAAAA9qAAAASgAAAA9CBAAAAgAAAA9rAAAASwAAAA9DBAAAAgAAAA9sAAAATAAAAA9EBAAAAgAAAA9tAAAATQAAAA9FBAAAAgAAAA/5////JQAAAA9GBAAAAgAAAA8qAAAAtf///w9HBAAAAgAAAA93AAAAVwAAAA9IBAAAAgAAAA94AAAAWAAAAA9JBAAAAgAAAA9jAAAAQwAAAA9KBAAAAgAAAA92AAAAVgAAAA9LBAAAAgAAAA9iAAAAQgAAAA9MBAAAAgAAAA9uAAAATgAAAA9NBAAAAgAAAA8sAAAAPwAAAA9OBAAAAgAAAA87AAAALgAAAA9PBAAAAgAAAA86AAAALwAAAA9QBAAAAgAAAA8hAAAAp////w9RBAAAAgAAAA88AAAAPgAAAA9SBAAAAAAAAA8PUwQAAAMAAAAPIwAAAHwAAABcAAAAD1QEAAADAAAADzEAAAAhAAAAsf///w9VBAAAAwAAAA8yAAAAIgAAAEAAAAAPVgQAAAMAAAAPMwAAAC8AAACj////D1cEAAADAAAADzQAAAAkAAAAov///w9YBAAAAwAAAA81AAAAJQAAAKT///8PWQQAAAMAAAAPNgAAAD8AAACs////D1oEAAADAAAADzcAAAAmAAAApv///w9bBAAAAwAAAA84AAAAKgAAALL///8PXAQAAAMAAAAPOQAAACgAAACz////D10EAAADAAAADzAAAAApAAAAvP///w9eBAAAAwAAAA8tAAAAXwAAAL3///8PXwQAAAMAAAAPPQAAACsAAAC+////D2AEAAACAAAAD3EAAABRAAAAD2EEAAACAAAAD3cAAABXAAAAD2IEAAACAAAAD2UAAABFAAAAD2MEAAACAAAAD3IAAABSAAAAD2QEAAACAAAAD3QAAABUAAAAD2UEAAACAAAAD3kAAABZAAAAD2YEAAACAAAAD3UAAABVAAAAD2cEAAACAAAAD2kAAABJAAAAD2gEAAADAAAAD28AAABPAAAAp////w9pBAAAAwAAAA9wAAAAUAAAALb///8PagQAAAMAAAAPXgAAAF4AAABbAAAAD2sEAAADAAAAD7j///+o////XQAAAA9sBAAAAgAAAA9hAAAAQQAAAA9tBAAAAgAAAA9zAAAAUwAAAA9uBAAAAgAAAA9kAAAARAAAAA9vBAAAAgAAAA9mAAAARgAAAA9wBAAAAgAAAA9nAAAARwAAAA9xBAAAAgAAAA9oAAAASAAAAA9yBAAAAgAAAA9qAAAASgAAAA9zBAAAAgAAAA9rAAAASwAAAA90BAAAAgAAAA9sAAAATAAAAA91BAAAAwAAAA87AAAAOgAAAH4AAAAPdgQAAAMAAAAPYAAAAGAAAAB7AAAAD3cEAAADAAAADzwAAAA+AAAAfQAAAA94BAAAAgAAAA96AAAAWgAAAA95BAAAAgAAAA94AAAAWAAAAA96BAAAAgAAAA9jAAAAQwAAAA97BAAAAgAAAA92AAAAVgAAAA98BAAAAgAAAA9iAAAAQgAAAA99BAAAAgAAAA9uAAAATgAAAA9+BAAAAgAAAA9tAAAATQAAAA9/BAAAAwAAAA8sAAAAJwAAAC0AAAAPgAQAAAEAAAAPLgAAAA+BBAAAAgAAAA/p////yf///w+CBAAAAwAAAA+r////u////7D///8PgwQAAAAAAAAPD4QEAAACAAAADyMAAAB8AAAAD4UEAAACAAAADzEAAAAhAAAAD4YEAAACAAAADzIAAAAiAAAAD4cEAAACAAAADzMAAAAvAAAAD4gEAAACAAAADzQAAAAkAAAAD4kEAAACAAAADzUAAAAlAAAAD4oEAAACAAAADzYAAAA/AAAAD4sEAAACAAAADzcAAAAmAAAAD4wEAAACAAAADzgAAAAqAAAAD40EAAACAAAADzkAAAAoAAAAD44EAAACAAAADzAAAAApAAAAD48EAAACAAAADy0AAABfAAAAD5AEAAACAAAADz0AAAArAAAAD5EEAAACAAAAD3EAAABRAAAAD5IEAAACAAAAD3cAAABXAAAAD5MEAAACAAAAD2UAAABFAAAAD5QEAAACAAAAD3IAAABSAAAAD5UEAAACAAAAD3QAAABUAAAAD5YEAAACAAAAD3kAAABZAAAAD5cEAAACAAAAD3UAAABVAAAAD5gEAAACAAAAD2kAAABJAAAAD5kEAAACAAAAD28AAABPAAAAD5oEAAACAAAAD3AAAABQAAAAD5sEAAACAAAAD14AAABeAAAAD5wEAAACAAAAD7j///+o////D50EAAACAAAAD2EAAABBAAAAD54EAAACAAAAD3MAAABTAAAAD58EAAACAAAAD2QAAABEAAAAD6AEAAACAAAAD2YAAABGAAAAD6EEAAACAAAAD2cAAABHAAAAD6IEAAACAAAAD2gAAABIAAAAD6MEAAACAAAAD2oAAABKAAAAD6QEAAACAAAAD2sAAABLAAAAD6UEAAACAAAAD2wAAABMAAAAD6YEAAACAAAADzsAAAA6AAAAD6cEAAACAAAAD2AAAABgAAAAD6gEAAACAAAADzwAAAA+AAAAD6kEAAACAAAAD3oAAABaAAAAD6oEAAACAAAAD3gAAABYAAAAD6sEAAACAAAAD2MAAABDAAAAD6wEAAACAAAAD3YAAABWAAAAD60EAAACAAAAD2IAAABCAAAAD64EAAACAAAAD24AAABOAAAAD68EAAACAAAAD20AAABNAAAAD7AEAAACAAAADywAAAAnAAAAD7EEAAABAAAADy4AAAAPsgQAAAIAAAAP6f///8n///8PswQAAAIAAAAPq////7v///8PtAQAAAAAAAAPD7UEAAACAAAADy8AAABcAAAAD7YEAAAEAAAADzEAAAAhAAAAuf///6H///8PtwQAAAMAAAAPMgAAAEAAAACy////D7gEAAAEAAAADzMAAAAjAAAAs////6P///8PuQQAAAQAAAAPNAAAACQAAAC8////pP///w+6BAAAAwAAAA81AAAAJQAAAL3///8PuwQAAAMAAAAPNgAAAD8AAAC+////D7wEAAACAAAADzcAAAAmAAAAD70EAAACAAAADzgAAAAqAAAAD74EAAACAAAADzkAAAAoAAAAD78EAAACAAAADzAAAAApAAAAD8AEAAACAAAADy0AAABfAAAAD8EEAAACAAAADz0AAAArAAAAD8IEAAACAAAAD3EAAABRAAAAD8MEAAACAAAAD3cAAABXAAAAD8QEAAACAAAAD2UAAABFAAAAD8UEAAACAAAAD3IAAABSAAAAD8YEAAACAAAAD3QAAABUAAAAD8cEAAACAAAAD3kAAABZAAAAD8gEAAACAAAAD3UAAABVAAAAD8kEAAACAAAAD2kAAABJAAAAD8oEAAAEAAAAD28AAABPAAAA+P///9j///8PywQAAAQAAAAPcAAAAFAAAAD+////3v///w/MBAAAAwAAAA9eAAAAqP///6j///8PzQQAAAMAAAAP5////8f///9+AAAAD84EAAAEAAAAD2EAAABBAAAA5v///8b///8PzwQAAAQAAAAPcwAAAFMAAADf////p////w/QBAAABAAAAA9kAAAARAAAAPD////Q////D9EEAAACAAAAD2YAAABGAAAAD9IEAAACAAAAD2cAAABHAAAAD9MEAAACAAAAD2gAAABIAAAAD9QEAAACAAAAD2oAAABKAAAAD9UEAAACAAAAD2sAAABLAAAAD9YEAAACAAAAD2wAAABMAAAAD9cEAAADAAAADzsAAAA6AAAAtP///w/YBAAAAgAAAA/o////yP///w/ZBAAAAgAAAA/g////wP///w/aBAAAAgAAAA96AAAAWgAAAA/bBAAAAgAAAA94AAAAWAAAAA/cBAAABAAAAA9jAAAAQwAAAKL///+p////D90EAAACAAAAD3YAAABWAAAAD94EAAACAAAAD2IAAABCAAAAD98EAAACAAAAD24AAABOAAAAD+AEAAAEAAAAD20AAABNAAAAtf///7r///8P4QQAAAIAAAAPLAAAACcAAAAP4gQAAAQAAAAPLgAAACIAAAC3////9////w/jBAAAAgAAAA/p////yf///w/kBAAAAgAAAA/5////2f///w/lBAAAAAAAAA8P5gQAAAAAAAAPD+cEAAADAAAADyYAAAAxAAAAfAAAAA/oBAAAAwAAAA/p////MgAAAEAAAAAP6QQAAAMAAAAPIgAAADMAAAAjAAAAD+oEAAACAAAADycAAAA0AAAAD+sEAAACAAAADygAAAA1AAAAD+wEAAADAAAAD6f///82AAAAXgAAAA/tBAAAAgAAAA/o////NwAAAA/uBAAAAgAAAA8hAAAAOAAAAA/vBAAAAwAAAA/n////OQAAAHsAAAAP8AQAAAMAAAAP4P///zAAAAB9AAAAD/EEAAACAAAADykAAACw////D/IEAAACAAAADy0AAABfAAAAD/MEAAACAAAAD2EAAABBAAAAD/QEAAACAAAAD3oAAABaAAAAD/UEAAADAAAAD2UAAABFAAAApP///w/2BAAAAgAAAA9yAAAAUgAAAA/3BAAAAgAAAA90AAAAVAAAAA/4BAAAAgAAAA95AAAAWQAAAA/5BAAAAgAAAA91AAAAVQAAAA/6BAAAAgAAAA9pAAAASQAAAA/7BAAAAgAAAA9vAAAATwAAAA/8BAAAAgAAAA9wAAAAUAAAAA/9BAAAAwAAAA9eAAAAqP///1sAAAAP/gQAAAMAAAAPJAAAACoAAABdAAAAD/8EAAACAAAAD3EAAABRAAAADwAFAAADAAAAD3MAAABTAAAA3////w8BBQAAAgAAAA9kAAAARAAAAA8CBQAAAgAAAA9mAAAARgAAAA8DBQAAAgAAAA9nAAAARwAAAA8EBQAAAgAAAA9oAAAASAAAAA8FBQAAAgAAAA9qAAAASgAAAA8GBQAAAgAAAA9rAAAASwAAAA8HBQAAAgAAAA9sAAAATAAAAA8IBQAAAgAAAA9tAAAATQAAAA8JBQAAAwAAAA/5////JQAAALT///8PCgUAAAMAAAAPtf///6P///9gAAAADwsFAAACAAAAD3cAAABXAAAADwwFAAACAAAAD3gAAABYAAAADw0FAAACAAAAD2MAAABDAAAADw4FAAACAAAAD3YAAABWAAAADw8FAAACAAAAD2IAAABCAAAADxAFAAACAAAAD24AAABOAAAADxEFAAACAAAADywAAAA/AAAADxIFAAACAAAADzsAAAAuAAAADxMFAAACAAAADzoAAAAvAAAADxQFAAADAAAADz0AAAArAAAAfgAAAA8VBQAAAwAAAA88AAAAPgAAAFwAAAAPFgUAAAAAAAAPDxcFAAACAAAAD1wAAAB8AAAADxgFAAACAAAADzEAAAAhAAAADxkFAAACAAAADzIAAAAiAAAADxoFAAACAAAADzMAAAAjAAAADxsFAAACAAAADzQAAAAkAAAADxwFAAACAAAADzUAAAAlAAAADx0FAAACAAAADzYAAAAmAAAADx4FAAACAAAADzcAAAAvAAAADx8FAAACAAAADzgAAAAoAAAADyAFAAACAAAADzkAAAApAAAADyEFAAACAAAADzAAAAA9AAAADyIFAAACAAAADycAAAA/AAAADyMFAAACAAAAD6v///+7////DyQFAAACAAAAD3EAAABRAAAADyUFAAACAAAAD3cAAABXAAAADyYFAAACAAAAD2UAAABFAAAADycFAAACAAAAD3IAAABSAAAADygFAAACAAAAD3QAAABUAAAADykFAAACAAAAD3kAAABZAAAADyoFAAACAAAAD3UAAABVAAAADysFAAACAAAAD2kAAABJAAAADywFAAACAAAAD28AAABPAAAADy0FAAACAAAAD3AAAABQAAAADy4FAAACAAAADysAAAAqAAAADy8FAAACAAAAD7T///9gAAAADzAFAAACAAAAD2EAAABBAAAADzEFAAACAAAAD3MAAABTAAAADzIFAAACAAAAD2QAAABEAAAADzMFAAACAAAAD2YAAABGAAAADzQFAAACAAAAD2cAAABHAAAADzUFAAACAAAAD2gAAABIAAAADzYFAAACAAAAD2oAAABKAAAADzcFAAACAAAAD2sAAABLAAAADzgFAAACAAAAD2wAAABMAAAADzkFAAACAAAAD+f////H////DzoFAAACAAAAD7r///+q////DzsFAAACAAAAD34AAABeAAAADzwFAAACAAAAD3oAAABaAAAADz0FAAACAAAAD3gAAABYAAAADz4FAAACAAAAD2MAAABDAAAADz8FAAACAAAAD3YAAABWAAAAD0AFAAACAAAAD2IAAABCAAAAD0EFAAACAAAAD24AAABOAAAAD0IFAAACAAAAD20AAABNAAAAD0MFAAACAAAADywAAAA7AAAAD0QFAAACAAAADy4AAAA6AAAAD0UFAAACAAAADy0AAABfAAAAD0YFAAACAAAADzwAAAA+AAAAD0cFAAAAAAAADw9IBQAAAgAAAA8nAAAAIgAAAA9JBQAAAgAAAA8xAAAAIQAAAA9KBQAAAgAAAA8yAAAAQAAAAA9LBQAAAgAAAA8zAAAAIwAAAA9MBQAAAgAAAA80AAAAJAAAAA9NBQAAAgAAAA81AAAAJQAAAA9OBQAAAgAAAA82AAAAqP///w9PBQAAAgAAAA83AAAAJgAAAA9QBQAAAgAAAA84AAAAKgAAAA9RBQAAAgAAAA85AAAAKAAAAA9SBQAAAgAAAA8wAAAAKQAAAA9TBQAAAgAAAA8tAAAAXwAAAA9UBQAAAgAAAA89AAAAKwAAAA9VBQAAAgAAAA9xAAAAUQAAAA9WBQAAAgAAAA93AAAAVwAAAA9XBQAAAgAAAA9lAAAARQAAAA9YBQAAAgAAAA9yAAAAUgAAAA9ZBQAAAgAAAA90AAAAVAAAAA9aBQAAAgAAAA95AAAAWQAAAA9bBQAAAgAAAA91AAAAVQAAAA9cBQAAAgAAAA9pAAAASQAAAA9dBQAAAgAAAA9vAAAATwAAAA9eBQAAAgAAAA9wAAAAUAAAAA9fBQAAAgAAAA+0////YAAAAA9gBQAAAgAAAA9bAAAAewAAAA9hBQAAAgAAAA9hAAAAQQAAAA9iBQAAAgAAAA9zAAAAUwAAAA9jBQAAAgAAAA9kAAAARAAAAA9kBQAAAgAAAA9mAAAARgAAAA9lBQAAAgAAAA9nAAAARwAAAA9mBQAAAgAAAA9oAAAASAAAAA9nBQAAAgAAAA9qAAAASgAAAA9oBQAAAgAAAA9rAAAASwAAAA9pBQAAAgAAAA9sAAAATAAAAA9qBQAAAgAAAA/n////x////w9rBQAAAgAAAA9+AAAAXgAAAA9sBQAAAgAAAA9dAAAAfQAAAA9tBQAAAgAAAA9cAAAAfAAAAA9uBQAAAgAAAA96AAAAWgAAAA9vBQAAAgAAAA94AAAAWAAAAA9wBQAAAgAAAA9jAAAAQwAAAA9xBQAAAgAAAA92AAAAVgAAAA9yBQAAAgAAAA9iAAAAQgAAAA9zBQAAAgAAAA9uAAAATgAAAA90BQAAAgAAAA9tAAAATQAAAA91BQAAAgAAAA8sAAAAPAAAAA92BQAAAgAAAA8uAAAAPgAAAA93BQAAAgAAAA87AAAAOgAAAA94BQAAAgAAAA8vAAAAPwAAAA95BQAAAgAAAA8nAAAAIgAAAA96BQAAAwAAAA8xAAAAIQAAADkAAAAPewUAAAMAAAAPMgAAAEAAAAAyAAAAD3wFAAADAAAADzMAAAAjAAAAMwAAAA99BQAAAwAAAA80AAAAJAAAACMAAAAPfgUAAAMAAAAPNQAAACUAAAAiAAAAD38FAAADAAAADzYAAAAoAAAALAAAAA+ABQAAAgAAAA83AAAAJgAAAA+BBQAAAgAAAA84AAAAKgAAAA+CBQAAAgAAAA85AAAAKAAAAA+DBQAAAgAAAA8wAAAAKQAAAA+EBQAAAgAAAA8tAAAAXwAAAA+FBQAAAwAAAA89AAAAKwAAACcAAAAPhgUAAAIAAAAPcQAAAFEAAAAPhwUAAAIAAAAPdwAAAFcAAAAPiAUAAAIAAAAPZQAAAEUAAAAPiQUAAAIAAAAPcgAAAFIAAAAPigUAAAIAAAAPdAAAAFQAAAAPiwUAAAIAAAAPeQAAAFkAAAAPjAUAAAIAAAAPdQAAAFUAAAAPjQUAAAIAAAAPaQAAAEkAAAAPjgUAAAIAAAAPbwAAAE8AAAAPjwUAAAIAAAAPcAAAAFAAAAAPkAUAAAIAAAAPNAAAAGAAAAAPkQUAAAMAAAAPWwAAAHsAAAAqAAAAD5IFAAACAAAAD2EAAABBAAAAD5MFAAACAAAAD3MAAABTAAAAD5QFAAACAAAAD2QAAABEAAAAD5UFAAACAAAAD2YAAABGAAAAD5YFAAACAAAAD2cAAABHAAAAD5cFAAACAAAAD2gAAABIAAAAD5gFAAACAAAAD2oAAABKAAAAD5kFAAACAAAAD2sAAABLAAAAD5oFAAACAAAAD2wAAABMAAAAD5sFAAACAAAAD2cAAABHAAAAD5wFAAACAAAAD34AAABeAAAAD50FAAADAAAAD10AAAB9AAAAOgAAAA+eBQAAAgAAAA9cAAAAfAAAAA+fBQAAAgAAAA96AAAAWgAAAA+gBQAAAgAAAA94AAAAWAAAAA+hBQAAAgAAAA9jAAAAQwAAAA+iBQAAAgAAAA92AAAAVgAAAA+jBQAAAgAAAA9iAAAAQgAAAA+kBQAAAgAAAA9uAAAATgAAAA+lBQAAAgAAAA9tAAAATQAAAA+mBQAAAgAAAA8sAAAAPAAAAA+nBQAAAgAAAA8uAAAAPgAAAA+oBQAAAgAAAA87AAAAOgAAAA+pBQAAAwAAAA8vAAAAPwAAADAAAAAPqgUAAAIAAAAPp////73///8PqwUAAAIAAAAPMQAAACEAAAAPrAUAAAIAAAAPMgAAACIAAAAPrQUAAAIAAAAPMwAAACMAAAAPrgUAAAIAAAAPNAAAAKT///8PrwUAAAIAAAAPNQAAACUAAAAPsAUAAAIAAAAPNgAAACYAAAAPsQUAAAIAAAAPNwAAAC8AAAAPsgUAAAIAAAAPOAAAACgAAAAPswUAAAIAAAAPOQAAACkAAAAPtAUAAAIAAAAPMAAAAD0AAAAPtQUAAAIAAAAPKwAAAD8AAAAPtgUAAAIAAAAPtP///2AAAAAPtwUAAAIAAAAPcQAAAFEAAAAPuAUAAAIAAAAPdwAAAFcAAAAPuQUAAAIAAAAPZQAAAEUAAAAPugUAAAIAAAAPcgAAAFIAAAAPuwUAAAIAAAAPdAAAAFQAAAAPvAUAAAIAAAAPeQAAAFkAAAAPvQUAAAIAAAAPdQAAAFUAAAAPvgUAAAIAAAAPaQAAAEkAAAAPvwUAAAIAAAAPbwAAAE8AAAAPwAUAAAIAAAAPcAAAAFAAAAAPwQUAAAIAAAAP5f///8X///8PwgUAAAIAAAAPqP///14AAAAPwwUAAAIAAAAPYQAAAEEAAAAPxAUAAAIAAAAPcwAAAFMAAAAPxQUAAAIAAAAPZAAAAEQAAAAPxgUAAAIAAAAPZgAAAEYAAAAPxwUAAAIAAAAPZwAAAEcAAAAPyAUAAAIAAAAPaAAAAEgAAAAPyQUAAAIAAAAPagAAAEoAAAAPygUAAAIAAAAPawAAAEsAAAAPywUAAAIAAAAPbAAAAEwAAAAPzAUAAAIAAAAP9v///9b///8PzQUAAAIAAAAP5P///8T///8PzgUAAAIAAAAPJwAAACoAAAAPzwUAAAIAAAAPegAAAFoAAAAP0AUAAAIAAAAPeAAAAFgAAAAP0QUAAAIAAAAPYwAAAEMAAAAP0gUAAAIAAAAPdgAAAFYAAAAP0wUAAAIAAAAPYgAAAEIAAAAP1AUAAAIAAAAPbgAAAE4AAAAP1QUAAAIAAAAPbQAAAE0AAAAP1gUAAAIAAAAPLAAAADsAAAAP1wUAAAIAAAAPLgAAADoAAAAP2AUAAAIAAAAPLQAAAF8AAAAP2QUAAAIAAAAPPAAAAD4AAAAP2gUAAAAAAAAPD9sFAAAEAAAAD2AAAAB+AAAAKAAAACkAAAAP3AUAAAIAAAAPMQAAACEAAAAP3QUAAAQAAAAPMgAAAEAAAAAyAAAAPwAAAA/eBQAABAAAAA8zAAAAIwAAADMAAAArAAAAD98FAAAEAAAADzQAAAAkAAAANAAAACIAAAAP4AUAAAIAAAAPNQAAACUAAAAP4QUAAAQAAAAPNgAAAF4AAAA2AAAAPQAAAA/iBQAABAAAAA83AAAAJgAAADcAAAA6AAAAD+MFAAAEAAAADzgAAAAqAAAAOAAAAC8AAAAP5AUAAAIAAAAPOQAAACgAAAAP5QUAAAIAAAAPMAAAACkAAAAP5gUAAAQAAAAPLQAAAF8AAAAtAAAASQAAAA/nBQAABAAAAA89AAAAKwAAAC4AAABWAAAAD+gFAAAEAAAAD3EAAABRAAAALAAAAPv///8P6QUAAAQAAAAPdwAAAFcAAADz////0////w/qBQAABAAAAA9lAAAARQAAAOX////F////D+sFAAAEAAAAD3IAAABSAAAA6P///8j///8P7AUAAAQAAAAPdAAAAFQAAAD4////2P///w/tBQAABAAAAA95AAAAWQAAAPn////Z////D+4FAAAEAAAAD3UAAABVAAAA6v///8r///8P7wUAAAQAAAAPaQAAAEkAAADx////0f///w/wBQAABAAAAA9vAAAATwAAAOT////E////D/EFAAAEAAAAD3AAAABQAAAA5////8f///8P8gUAAAQAAAAPWwAAAHsAAAD2////1v///w/zBQAAAwAAAA9dAAAAfQAAADsAAAAP9AUAAAQAAAAPYQAAAEEAAAD8////3P///w/1BQAABAAAAA9zAAAAUwAAAP/////f////D/YFAAAEAAAAD2QAAABEAAAA4P///8D///8P9wUAAAQAAAAPZgAAAEYAAADu////zv///w/4BQAABAAAAA9nAAAARwAAAOb////G////D/kFAAAEAAAAD2gAAABIAAAA4////8P///8P+gUAAAQAAAAPagAAAEoAAADy////0v///w/7BQAABAAAAA9rAAAASwAAAO3////N////D/wFAAAEAAAAD2wAAABMAAAA4v///8L///8P/QUAAAQAAAAPOwAAADoAAADs////zP///w/+BQAABAAAAA8nAAAAIgAAAPf////X////D/8FAAAEAAAAD1wAAAB8AAAAJwAAANv///8PAAYAAAQAAAAPegAAAFoAAAD+////3v///w8BBgAABAAAAA94AAAAWAAAAOn////J////DwIGAAAEAAAAD2MAAABDAAAA+v///9r///8PAwYAAAQAAAAPdgAAAFYAAAD9////3f///w8EBgAABAAAAA9iAAAAQgAAAPT////U////DwUGAAAEAAAAD24AAABOAAAA9f///9X///8PBgYAAAQAAAAPbQAAAE0AAADv////z////w8HBgAABAAAAA8sAAAAPAAAAPD////Q////DwgGAAAEAAAADy4AAAA+AAAA6////8v///8PCQYAAAQAAAAPLwAAAD8AAADh////wf///w8KBgAAAgAAAA88AAAAPgAAAA8LBgAAAAAAAA8PDAYAAAQAAAAPYAAAAH4AAAD3////1////w8NBgAAAgAAAA8xAAAAIQAAAA8OBgAAAgAAAA8yAAAAQAAAAA8PBgAAAgAAAA8zAAAAIwAAAA8QBgAAAgAAAA80AAAAJAAAAA8RBgAAAgAAAA81AAAAJQAAAA8SBgAAAgAAAA82AAAAXgAAAA8TBgAAAgAAAA83AAAAJgAAAA8UBgAAAgAAAA84AAAAKgAAAA8VBgAAAgAAAA85AAAAKAAAAA8WBgAAAgAAAA8wAAAAKQAAAA8XBgAAAgAAAA8tAAAAXwAAAA8YBgAAAgAAAA89AAAAKwAAAA8ZBgAABAAAAA9xAAAAUQAAAP/////f////DxoGAAAEAAAAD3cAAABXAAAA4v///8L///8PGwYAAAQAAAAPZQAAAEUAAADl////xf///w8cBgAABAAAAA9yAAAAUgAAAPD////Q////Dx0GAAAEAAAAD3QAAABUAAAA8v///9L///8PHgYAAAQAAAAPeQAAAFkAAAD6////2v///w8fBgAABAAAAA91AAAAVQAAAPP////T////DyAGAAAEAAAAD2kAAABJAAAA6P///8j///8PIQYAAAQAAAAPbwAAAE8AAADu////zv///w8iBgAABAAAAA9wAAAAUAAAAO/////P////DyMGAAAEAAAAD1sAAAB7AAAA+P///9j///8PJAYAAAQAAAAPXQAAAH0AAAD5////2f///w8lBgAABAAAAA9hAAAAQQAAAOD////A////DyYGAAAEAAAAD3MAAABTAAAA8f///9H///8PJwYAAAQAAAAPZAAAAEQAAADk////xP///w8oBgAABAAAAA9mAAAARgAAAPT////U////DykGAAAEAAAAD2cAAABHAAAA4////8P///8PKgYAAAQAAAAPaAAAAEgAAAD1////1f///w8rBgAABAAAAA9qAAAASgAAAOn////J////DywGAAAEAAAAD2sAAABLAAAA6v///8r///8PLQYAAAQAAAAPbAAAAEwAAADr////y////w8uBgAAAgAAAA87AAAAOgAAAA8vBgAAAgAAAA8nAAAAIgAAAA8wBgAABAAAAA9cAAAAfAAAAP7////e////DzEGAAAEAAAAD3oAAABaAAAA5////8f///8PMgYAAAQAAAAPeAAAAFgAAAD8////3P///w8zBgAABAAAAA9jAAAAQwAAAPb////W////DzQGAAAEAAAAD3YAAABWAAAA5v///8b///8PNQYAAAQAAAAPYgAAAEIAAADh////wf///w82BgAABAAAAA9uAAAATgAAAO3////N////DzcGAAAEAAAAD20AAABNAAAA7P///8z///8POAYAAAIAAAAPLAAAADwAAAAPOQYAAAIAAAAPLgAAAD4AAAAPOgYAAAIAAAAPLwAAAD8AAAAPOwYAAAIAAAAPPAAAAD4AAAAPPAYAAAAAAAAPDz0GAAAEAAAAD2AAAAB+AAAAo////7P///8PPgYAAAIAAAAPMQAAACEAAAAPPwYAAAIAAAAPMgAAAEAAAAAPQAYAAAIAAAAPMwAAACMAAAAPQQYAAAIAAAAPNAAAACQAAAAPQgYAAAIAAAAPNQAAACUAAAAPQwYAAAIAAAAPNgAAAF4AAAAPRAYAAAIAAAAPNwAAACYAAAAPRQYAAAIAAAAPOAAAACoAAAAPRgYAAAIAAAAPOQAAACgAAAAPRwYAAAIAAAAPMAAAACkAAAAPSAYAAAIAAAAPLQAAAF8AAAAPSQYAAAIAAAAPPQAAACsAAAAPSgYAAAQAAAAPcQAAAFEAAADK////6v///w9LBgAABAAAAA93AAAAVwAAAMP////j////D0wGAAAEAAAAD2UAAABFAAAA1f////X///8PTQYAAAQAAAAPcgAAAFIAAADL////6////w9OBgAABAAAAA90AAAAVAAAAMX////l////D08GAAAEAAAAD3kAAABZAAAAzv///+7///8PUAYAAAQAAAAPdQAAAFUAAADH////5////w9RBgAABAAAAA9pAAAASQAAANv////7////D1IGAAAEAAAAD28AAABPAAAArv///77///8PUwYAAAQAAAAPcAAAAFAAAADa////+v///w9UBgAABAAAAA9bAAAAewAAAMj////o////D1UGAAAEAAAAD10AAAB9AAAAJwAAACcAAAAPVgYAAAQAAAAPYQAAAEEAAADG////5v///w9XBgAABAAAAA9zAAAAUwAAANn////5////D1gGAAAEAAAAD2QAAABEAAAA1/////f///8PWQYAAAQAAAAPZgAAAEYAAADB////4f///w9aBgAABAAAAA9nAAAARwAAAND////w////D1sGAAAEAAAAD2gAAABIAAAA0v////L///8PXAYAAAQAAAAPagAAAEoAAADP////7////w9dBgAABAAAAA9rAAAASwAAAMz////s////D14GAAAEAAAAD2wAAABMAAAAxP///+T///8PXwYAAAQAAAAPOwAAADoAAADW////9v///w9gBgAABAAAAA8nAAAAIgAAANz////8////D2EGAAAEAAAAD1wAAAB8AAAALwAAAHwAAAAPYgYAAAQAAAAPegAAAFoAAADR////8f///w9jBgAABAAAAA94AAAAWAAAAN7////+////D2QGAAAEAAAAD2MAAABDAAAA0/////P///8PZQYAAAQAAAAPdgAAAFYAAADN////7f///w9mBgAABAAAAA9iAAAAQgAAAKb///+2////D2cGAAAEAAAAD24AAABOAAAA1P////T///8PaAYAAAQAAAAPbQAAAE0AAADY////+P///w9pBgAABAAAAA8sAAAAPAAAAML////i////D2oGAAAEAAAADy4AAAA+AAAAwP///+D///8PawYAAAQAAAAPLwAAAD8AAAAuAAAALAAAAA9sBgAABAAAAA88AAAAPgAAAHwAAACm////D20GAAAAAAAADw9uBgAAAgAAAA9gAAAAfgAAAA9vBgAAAgAAAA8xAAAAIQAAAA9wBgAAAgAAAA8yAAAAQAAAAA9xBgAAAgAAAA8zAAAAIwAAAA9yBgAAAgAAAA80AAAAJAAAAA9zBgAAAgAAAA81AAAAJQAAAA90BgAAAgAAAA82AAAAXgAAAA91BgAAAgAAAA83AAAAJgAAAA92BgAAAgAAAA84AAAAKgAAAA93BgAAAgAAAA85AAAAKAAAAA94BgAAAgAAAA8wAAAAKQAAAA95BgAAAgAAAA8tAAAAXwAAAA96BgAAAgAAAA89AAAAKwAAAA97BgAABAAAAA9xAAAAUQAAAMr////q////D3wGAAAEAAAAD3cAAABXAAAAw////+P///8PfQYAAAQAAAAPZQAAAEUAAADV////9f///w9+BgAABAAAAA9yAAAAUgAAAMv////r////D38GAAAEAAAAD3QAAABUAAAAxf///+X///8PgAYAAAQAAAAPeQAAAFkAAADO////7v///w+BBgAABAAAAA91AAAAVQAAAMf////n////D4IGAAAEAAAAD2kAAABJAAAA2/////v///8PgwYAAAQAAAAPbwAAAE8AAADd/////f///w+EBgAABAAAAA9wAAAAUAAAANr////6////D4UGAAAEAAAAD1sAAAB7AAAAyP///+j///8PhgYAAAQAAAAPXQAAAH0AAADf/////////w+HBgAABAAAAA9hAAAAQQAAAMb////m////D4gGAAAEAAAAD3MAAABTAAAA2f////n///8PiQYAAAQAAAAPZAAAAEQAAADX////9////w+KBgAABAAAAA9mAAAARgAAAMH////h////D4sGAAAEAAAAD2cAAABHAAAA0P////D///8PjAYAAAQAAAAPaAAAAEgAAADS////8v///w+NBgAABAAAAA9qAAAASgAAAM/////v////D44GAAAEAAAAD2sAAABLAAAAzP///+z///8PjwYAAAQAAAAPbAAAAEwAAADE////5P///w+QBgAABAAAAA87AAAAOgAAANb////2////D5EGAAAEAAAADycAAAAiAAAA3P////z///8PkgYAAAIAAAAPXAAAAHwAAAAPkwYAAAQAAAAPegAAAFoAAADR////8f///w+UBgAABAAAAA94AAAAWAAAAN7////+////D5UGAAAEAAAAD2MAAABDAAAA0/////P///8PlgYAAAQAAAAPdgAAAFYAAADN////7f///w+XBgAABAAAAA9iAAAAQgAAAMn////p////D5gGAAAEAAAAD24AAABOAAAA1P////T///8PmQYAAAQAAAAPbQAAAE0AAADY////+P///w+aBgAABAAAAA8sAAAAPAAAAML////i////D5sGAAAEAAAADy4AAAA+AAAAwP///+D///8PnAYAAAIAAAAPLwAAAD8AAAAPnQYAAAAAAAAPD54GAAAAAAAADw+fBgAAAgAAAA9gAAAAfgAAAA+gBgAAAgAAAA8xAAAAIQAAAA+hBgAAAgAAAA8yAAAAQAAAAA+iBgAAAgAAAA8zAAAAIwAAAA+jBgAAAgAAAA80AAAAJAAAAA+kBgAAAgAAAA81AAAAJQAAAA+lBgAAAgAAAA82AAAAXgAAAA+mBgAAAgAAAA83AAAAJgAAAA+nBgAAAgAAAA84AAAAKgAAAA+oBgAAAgAAAA85AAAAKAAAAA+pBgAAAgAAAA8wAAAAKQAAAA+qBgAAAgAAAA8tAAAAXwAAAA+rBgAAAgAAAA89AAAAKwAAAA+sBgAABAAAAA9xAAAAUQAAAMr////q////D60GAAAEAAAAD3cAAABXAAAAw////+P///8PrgYAAAQAAAAPZQAAAEUAAADV////9f///w+vBgAABAAAAA9yAAAAUgAAAMv////r////D7AGAAAEAAAAD3QAAABUAAAAxf///+X///8PsQYAAAQAAAAPeQAAAFkAAADO////7v///w+yBgAABAAAAA91AAAAVQAAAMf////n////D7MGAAAEAAAAD2kAAABJAAAA2/////v///8PtAYAAAQAAAAPbwAAAE8AAADd/////f///w+1BgAABAAAAA9wAAAAUAAAANr////6////D7YGAAAEAAAAD1sAAAB7AAAAyP///+j///8PtwYAAAQAAAAPXQAAAH0AAADf/////////w+4BgAABAAAAA9hAAAAQQAAAMb////m////D7kGAAAEAAAAD3MAAABTAAAA2f////n///8PugYAAAQAAAAPZAAAAEQAAADX////9////w+7BgAABAAAAA9mAAAARgAAAMH////h////D7wGAAAEAAAAD2cAAABHAAAA0P////D///8PvQYAAAQAAAAPaAAAAEgAAADS////8v///w++BgAABAAAAA9qAAAASgAAAM/////v////D78GAAAEAAAAD2sAAABLAAAAzP///+z///8PwAYAAAQAAAAPbAAAAEwAAADE////5P///w/BBgAABAAAAA87AAAAOgAAANb////2////D8IGAAAEAAAADycAAAAiAAAA3P////z///8PwwYAAAIAAAAPXAAAAHwAAAAPxAYAAAQAAAAPegAAAFoAAADR////8f///w/FBgAABAAAAA94AAAAWAAAAN7////+////D8YGAAAEAAAAD2MAAABDAAAA0/////P///8PxwYAAAQAAAAPdgAAAFYAAADN////7f///w/IBgAABAAAAA9iAAAAQgAAAMn////p////D8kGAAAEAAAAD24AAABOAAAA1P////T///8PygYAAAQAAAAPbQAAAE0AAADY////+P///w/LBgAABAAAAA8sAAAAPAAAAML////i////D8wGAAAEAAAADy4AAAA+AAAAwP///+D///8PzQYAAAIAAAAPLwAAAD8AAAAPzgYAAAIAAAAPPAAAAD4AAAAPzwYAAAAAAAAPD9AGAAACAAAADygAAAApAAAAD9EGAAACAAAADzEAAAAhAAAAD9IGAAACAAAADzIAAAAiAAAAD9MGAAACAAAADzMAAAAvAAAAD9QGAAACAAAADzQAAAAkAAAAD9UGAAACAAAADzUAAAA6AAAAD9YGAAACAAAADzYAAAAsAAAAD9cGAAACAAAADzcAAAAuAAAAD9gGAAACAAAADzgAAAA7AAAAD9kGAAACAAAADzkAAAA/AAAAD9oGAAACAAAADzAAAAAlAAAAD9sGAAACAAAADy0AAABfAAAAD9wGAAACAAAADz0AAAArAAAAD90GAAACAAAAD8r////q////D94GAAACAAAAD8P////j////D98GAAACAAAAD9X////1////D+AGAAACAAAAD8v////r////D+EGAAACAAAAD8X////l////D+IGAAACAAAAD87////u////D+MGAAACAAAAD8f////n////D+QGAAACAAAAD9v////7////D+UGAAACAAAAD93////9////D+YGAAACAAAAD9r////6////D+cGAAACAAAAD8j////o////D+gGAAACAAAAD9//////////D+kGAAACAAAAD8b////m////D+oGAAACAAAAD9n////5////D+sGAAACAAAAD9f////3////D+wGAAACAAAAD8H////h////D+0GAAACAAAAD9D////w////D+4GAAACAAAAD9L////y////D+8GAAACAAAAD8/////v////D/AGAAACAAAAD8z////s////D/EGAAACAAAAD8T////k////D/IGAAACAAAAD9b////2////D/MGAAACAAAAD9z////8////D/QGAAACAAAAD1wAAAB8AAAAD/UGAAACAAAAD9H////x////D/YGAAACAAAAD97////+////D/cGAAACAAAAD9P////z////D/gGAAACAAAAD83////t////D/kGAAACAAAAD8n////p////D/oGAAACAAAAD9T////0////D/sGAAACAAAAD9j////4////D/wGAAACAAAAD8L////i////D/0GAAACAAAAD8D////g////D/4GAAACAAAADy8AAAA/AAAAD/8GAAACAAAADzwAAAA+AAAADwAHAAAAAAAADw8BBwAAAgAAAA9gAAAAfgAAAA8CBwAAAgAAAA8xAAAAIQAAAA8DBwAAAgAAAA8yAAAAQAAAAA8EBwAAAgAAAA8zAAAAIwAAAA8FBwAAAgAAAA80AAAAJAAAAA8GBwAAAgAAAA81AAAAJQAAAA8HBwAAAgAAAA82AAAAXgAAAA8IBwAAAgAAAA83AAAAJgAAAA8JBwAAAgAAAA84AAAAKgAAAA8KBwAAAgAAAA85AAAAKAAAAA8LBwAAAgAAAA8wAAAAKQAAAA8MBwAAAgAAAA8tAAAAXwAAAA8NBwAAAgAAAA89AAAAKwAAAA8OBwAABAAAAA9xAAAAUQAAAOn////J////Dw8HAAAEAAAAD3cAAABXAAAA9v///9b///8PEAcAAAQAAAAPZQAAAEUAAADz////0////w8RBwAABAAAAA9yAAAAUgAAAOr////K////DxIHAAAEAAAAD3QAAABUAAAA5f///8X///8PEwcAAAQAAAAPeQAAAFkAAADt////zf///w8UBwAABAAAAA91AAAAVQAAAOP////D////DxUHAAAEAAAAD2kAAABJAAAA+P///9j///8PFgcAAAQAAAAPbwAAAE8AAAD5////2f///w8XBwAABAAAAA9wAAAAUAAAAOf////H////DxgHAAAEAAAAD1sAAAB7AAAA9f///9X///8PGQcAAAQAAAAPXQAAAH0AAAD6////2v///w8aBwAABAAAAA9hAAAAQQAAAPT////U////DxsHAAAEAAAAD3MAAABTAAAA+////9v///8PHAcAAAQAAAAPZAAAAEQAAADi////wv///w8dBwAABAAAAA9mAAAARgAAAOD////A////Dx4HAAAEAAAAD2cAAABHAAAA7////8////8PHwcAAAQAAAAPaAAAAEgAAADw////0P///w8gBwAABAAAAA9qAAAASgAAAO7////O////DyEHAAAEAAAAD2sAAABLAAAA6////8v///8PIgcAAAQAAAAPbAAAAEwAAADk////xP///w8jBwAABAAAAA87AAAAOgAAAOb////G////DyQHAAAEAAAADycAAAAiAAAA/f///93///8PJQcAAAIAAAAPXAAAAHwAAAAPJgcAAAQAAAAPegAAAFoAAAD/////3////w8nBwAABAAAAA94AAAAWAAAAPf////X////DygHAAAEAAAAD2MAAABDAAAA8f///9H///8PKQcAAAQAAAAPdgAAAFYAAADs////zP///w8qBwAABAAAAA9iAAAAQgAAAOj////I////DysHAAAEAAAAD24AAABOAAAA8v///9L///8PLAcAAAQAAAAPbQAAAE0AAAD8////3P///w8tBwAABAAAAA8sAAAAPAAAAOH////B////Dy4HAAAEAAAADy4AAAA+AAAA/v///97///8PLwcAAAIAAAAPLwAAAD8AAAAPMAcAAAIAAAAPPAAAAD4AAAAPMQcAAAAAAAAPDzIHAAACAAAAD2AAAAB+AAAADzMHAAACAAAADzEAAAAhAAAADzQHAAACAAAADzIAAABAAAAADzUHAAACAAAADzMAAAAjAAAADzYHAAACAAAADzQAAAAkAAAADzcHAAACAAAADzUAAAAlAAAADzgHAAACAAAADzYAAABeAAAADzkHAAACAAAADzcAAAAmAAAADzoHAAACAAAADzgAAAAqAAAADzsHAAACAAAADzkAAAAoAAAADzwHAAACAAAADzAAAAApAAAADz0HAAACAAAADy0AAABfAAAADz4HAAACAAAADz0AAAArAAAADz8HAAAEAAAAD3EAAABRAAAA0f////H///8PQAcAAAQAAAAPdwAAAFcAAADX////9////w9BBwAABAAAAA9lAAAARQAAAMX////l////D0IHAAAEAAAAD3IAAABSAAAA0v////L///8PQwcAAAQAAAAPdAAAAFQAAADU////9P///w9EBwAABAAAAA95AAAAWQAAANn////5////D0UHAAAEAAAAD3UAAABVAAAA1f////X///8PRgcAAAQAAAAPaQAAAEkAAADJ////6f///w9HBwAABAAAAA9vAAAATwAAAM/////v////D0gHAAAEAAAAD3AAAABQAAAA0P////D///8PSQcAAAQAAAAPWwAAAHsAAADb////+////w9KBwAABAAAAA9dAAAAfQAAAN3////9////D0sHAAAEAAAAD2EAAABBAAAAwf///+H///8PTAcAAAQAAAAPcwAAAFMAAADT////8////w9NBwAABAAAAA9kAAAARAAAAMT////k////D04HAAAEAAAAD2YAAABGAAAAxv///+b///8PTwcAAAQAAAAPZwAAAEcAAADH////5////w9QBwAABAAAAA9oAAAASAAAAMj////o////D1EHAAAEAAAAD2oAAABKAAAAyv///+r///8PUgcAAAQAAAAPawAAAEsAAADL////6////w9TBwAABAAAAA9sAAAATAAAAMz////s////D1QHAAACAAAADzsAAAA6AAAAD1UHAAACAAAADycAAAAiAAAAD1YHAAACAAAAD1wAAAB8AAAAD1cHAAAEAAAAD3oAAABaAAAA2v////r///8PWAcAAAQAAAAPeAAAAFgAAADY////+P///w9ZBwAABAAAAA9jAAAAQwAAAMP////j////D1oHAAAEAAAAD3YAAABWAAAA1v////b///8PWwcAAAQAAAAPYgAAAEIAAADC////4v///w9cBwAABAAAAA9uAAAATgAAAM7////u////D10HAAAEAAAAD20AAABNAAAAzf///+3///8PXgcAAAIAAAAPLAAAADwAAAAPXwcAAAIAAAAPLgAAAD4AAAAPYAcAAAIAAAAPLwAAAD8AAAAPYQcAAAIAAAAPPAAAAD4AAAAPYgcAAAAAAAAPD2MHAAAEAAAAD2AAAAB+AAAArf///73///8PZAcAAAQAAAAPMQAAACEAAAAxAAAAIQAAAA9lBwAABAAAAA8yAAAAQAAAADIAAAAiAAAAD2YHAAAEAAAADzMAAAAjAAAAMwAAACcAAAAPZwcAAAQAAAAPNAAAACQAAAA0AAAAKgAAAA9oBwAABAAAAA81AAAAJQAAADUAAAA6AAAAD2kHAAAEAAAADzYAAABeAAAANgAAACwAAAAPagcAAAQAAAAPNwAAACYAAAA3AAAALgAAAA9rBwAABAAAAA84AAAAKgAAADgAAAA7AAAAD2wHAAAEAAAADzkAAAAoAAAAOQAAACgAAAAPbQcAAAQAAAAPMAAAACkAAAAwAAAAKQAAAA9uBwAABAAAAA8tAAAAXwAAAC0AAABfAAAAD28HAAAEAAAADz0AAAArAAAAPQAAACsAAAAPcAcAAAQAAAAPcQAAAFEAAADK////6v///w9xBwAABAAAAA93AAAAVwAAAMP////j////D3IHAAAEAAAAD2UAAABFAAAA1f////X///8PcwcAAAQAAAAPcgAAAFIAAADL////6////w90BwAABAAAAA90AAAAVAAAAMX////l////D3UHAAAEAAAAD3kAAABZAAAAzv///+7///8PdgcAAAQAAAAPdQAAAFUAAADH////5////w93BwAABAAAAA9pAAAASQAAANv////7////D3gHAAAEAAAAD28AAABPAAAA3f////3///8PeQcAAAQAAAAPcAAAAFAAAADa////+v///w96BwAABAAAAA9bAAAAewAAAMj////o////D3sHAAAEAAAAD10AAAB9AAAAp////7f///8PfAcAAAQAAAAPYQAAAEEAAADG////5v///w99BwAABAAAAA9zAAAAUwAAAKb///+2////D34HAAAEAAAAD2QAAABEAAAA1/////f///8PfwcAAAQAAAAPZgAAAEYAAADB////4f///w+ABwAABAAAAA9nAAAARwAAAND////w////D4EHAAAEAAAAD2gAAABIAAAA0v////L///8PggcAAAQAAAAPagAAAEoAAADP////7////w+DBwAABAAAAA9rAAAASwAAAMz////s////D4QHAAAEAAAAD2wAAABMAAAAxP///+T///8PhQcAAAQAAAAPOwAAADoAAADW////9v///w+GBwAABAAAAA8nAAAAIgAAAKT///+0////D4cHAAAEAAAAD1wAAAB8AAAAXAAAAHwAAAAPiAcAAAQAAAAPegAAAFoAAADR////8f///w+JBwAABAAAAA94AAAAWAAAAN7////+////D4oHAAAEAAAAD2MAAABDAAAA0/////P///8PiwcAAAQAAAAPdgAAAFYAAADN////7f///w+MBwAABAAAAA9iAAAAQgAAAMn////p////D40HAAAEAAAAD24AAABOAAAA1P////T///8PjgcAAAQAAAAPbQAAAE0AAADY////+P///w+PBwAABAAAAA8sAAAAPAAAAML////i////D5AHAAAEAAAADy4AAAA+AAAAwP///+D///8PkQcAAAQAAAAPLwAAAD8AAAAvAAAAPwAAAA+SBwAAAgAAAA88AAAAPgAAAA+TBwAAAAAAAA8PlAcAAAIAAAAPrf///73///8PlQcAAAIAAAAPMQAAACEAAAAPlgcAAAIAAAAPMgAAACIAAAAPlwcAAAIAAAAPMwAAACcAAAAPmAcAAAIAAAAPNAAAADsAAAAPmQcAAAIAAAAPNQAAACUAAAAPmgcAAAIAAAAPNgAAADoAAAAPmwcAAAIAAAAPNwAAAD8AAAAPnAcAAAIAAAAPOAAAACoAAAAPnQcAAAIAAAAPOQAAACgAAAAPngcAAAIAAAAPMAAAACkAAAAPnwcAAAIAAAAPLQAAAF8AAAAPoAcAAAIAAAAPPQAAACsAAAAPoQcAAAIAAAAPyv///+r///8PogcAAAIAAAAPw////+P///8PowcAAAIAAAAP1f////X///8PpAcAAAIAAAAPy////+v///8PpQcAAAIAAAAPxf///+X///8PpgcAAAIAAAAPzv///+7///8PpwcAAAIAAAAPx////+f///8PqAcAAAIAAAAP2/////v///8PqQcAAAIAAAAP3f////3///8PqgcAAAIAAAAP2v////r///8PqwcAAAIAAAAPyP///+j///8PrAcAAAIAAAAPp////7f///8PrQcAAAIAAAAPxv///+b///8PrgcAAAIAAAAPpv///7b///8PrwcAAAIAAAAP1/////f///8PsAcAAAIAAAAPwf///+H///8PsQcAAAIAAAAP0P////D///8PsgcAAAIAAAAP0v////L///8PswcAAAIAAAAPz////+////8PtAcAAAIAAAAPzP///+z///8PtQcAAAIAAAAPxP///+T///8PtgcAAAIAAAAP1v////b///8PtwcAAAIAAAAPpP///7T///8PuAcAAAIAAAAPXAAAAC8AAAAPuQcAAAIAAAAP0f////H///8PugcAAAIAAAAP3v////7///8PuwcAAAIAAAAP0/////P///8PvAcAAAIAAAAPzf///+3///8PvQcAAAIAAAAPyf///+n///8PvgcAAAIAAAAP1P////T///8PvwcAAAIAAAAP2P////j///8PwAcAAAIAAAAPwv///+L///8PwQcAAAIAAAAPwP///+D///8PwgcAAAIAAAAPLgAAACwAAAAPwwcAAAIAAAAPPAAAAD4AAAAPxAcAAAAAAAAPD8UHAAACAAAAD6P///+z////D8YHAAACAAAADzEAAAAhAAAAD8cHAAACAAAADzIAAAAiAAAAD8gHAAACAAAADzMAAAAnAAAAD8kHAAACAAAADzQAAAA7AAAAD8oHAAACAAAADzUAAAAlAAAAD8sHAAACAAAADzYAAAA6AAAAD8wHAAACAAAADzcAAAA/AAAAD80HAAACAAAADzgAAAAqAAAAD84HAAACAAAADzkAAAAoAAAAD88HAAACAAAADzAAAAApAAAAD9AHAAACAAAADy0AAABfAAAAD9EHAAACAAAADz0AAAArAAAAD9IHAAACAAAAD8r////q////D9MHAAACAAAAD8P////j////D9QHAAACAAAAD9X////1////D9UHAAACAAAAD8v////r////D9YHAAACAAAAD8X////l////D9cHAAACAAAAD87////u////D9gHAAACAAAAD8f////n////D9kHAAACAAAAD9v////7////D9oHAAACAAAAD93////9////D9sHAAACAAAAD9r////6////D9wHAAACAAAAD8j////o////D90HAAACAAAAD9//////////D94HAAACAAAAD8b////m////D98HAAACAAAAD9n////5////D+AHAAACAAAAD9f////3////D+EHAAACAAAAD8H////h////D+IHAAACAAAAD9D////w////D+MHAAACAAAAD9L////y////D+QHAAACAAAAD8/////v////D+UHAAACAAAAD8z////s////D+YHAAACAAAAD8T////k////D+cHAAACAAAAD9b////2////D+gHAAACAAAAD9z////8////D+kHAAACAAAAD1wAAAAvAAAAD+oHAAACAAAAD9H////x////D+sHAAACAAAAD97////+////D+wHAAACAAAAD9P////z////D+0HAAACAAAAD83////t////D+4HAAACAAAAD8n////p////D+8HAAACAAAAD9T////0////D/AHAAACAAAAD9j////4////D/EHAAACAAAAD8L////i////D/IHAAACAAAAD8D////g////D/MHAAACAAAADy4AAAAsAAAAD/QHAAACAAAADzwAAAA+AAAAD/UHAAAAAAAADw/2BwAAAgAAAA+6////qv///w/3BwAAAgAAAA8xAAAAIQAAAA/4BwAAAgAAAA8yAAAAIgAAAA/5BwAAAgAAAA8zAAAAt////w/6BwAAAgAAAA80AAAAJAAAAA/7BwAAAgAAAA81AAAAJQAAAA/8BwAAAgAAAA82AAAAJgAAAA/9BwAAAgAAAA83AAAALwAAAA/+BwAAAgAAAA84AAAAKAAAAA//BwAAAgAAAA85AAAAKQAAAA8ACAAAAgAAAA8wAAAAPQAAAA8BCAAAAgAAAA8nAAAAPwAAAA8CCAAAAgAAAA+h////v////w8DCAAAAgAAAA9xAAAAUQAAAA8ECAAAAgAAAA93AAAAVwAAAA8FCAAAAgAAAA9lAAAARQAAAA8GCAAAAgAAAA9yAAAAUgAAAA8HCAAAAgAAAA90AAAAVAAAAA8ICAAAAgAAAA95AAAAWQAAAA8JCAAAAgAAAA91AAAAVQAAAA8KCAAAAgAAAA9pAAAASQAAAA8LCAAAAgAAAA9vAAAATwAAAA8MCAAAAgAAAA9wAAAAUAAAAA8NCAAAAgAAAA9gAAAAXgAAAA8OCAAAAgAAAA8rAAAAKgAAAA8PCAAAAgAAAA9hAAAAQQAAAA8QCAAAAgAAAA9zAAAAUwAAAA8RCAAAAgAAAA9kAAAARAAAAA8SCAAAAgAAAA9mAAAARgAAAA8TCAAAAgAAAA9nAAAARwAAAA8UCAAAAgAAAA9oAAAASAAAAA8VCAAAAgAAAA9qAAAASgAAAA8WCAAAAgAAAA9rAAAASwAAAA8XCAAAAgAAAA9sAAAATAAAAA8YCAAAAgAAAA/x////0f///w8ZCAAAAgAAAA+0////qP///w8aCAAAAgAAAA/n////x////w8bCAAAAgAAAA96AAAAWgAAAA8cCAAAAgAAAA94AAAAWAAAAA8dCAAAAgAAAA9jAAAAQwAAAA8eCAAAAgAAAA92AAAAVgAAAA8fCAAAAgAAAA9iAAAAQgAAAA8gCAAAAgAAAA9uAAAATgAAAA8hCAAAAgAAAA9tAAAATQAAAA8iCAAAAgAAAA8sAAAAOwAAAA8jCAAAAgAAAA8uAAAAOgAAAA8kCAAAAgAAAA8tAAAAXwAAAA8lCAAAAgAAAA88AAAAPgAAAA8mCAAAAAAAAA8PJwgAAAIAAAAPXAAAAHwAAAAPKAgAAAIAAAAPMQAAACEAAAAPKQgAAAIAAAAPMgAAACIAAAAPKggAAAIAAAAPMwAAAKP///8PKwgAAAIAAAAPNAAAACQAAAAPLAgAAAIAAAAPNQAAACUAAAAPLQgAAAIAAAAPNgAAACYAAAAPLggAAAIAAAAPNwAAAC8AAAAPLwgAAAIAAAAPOAAAACgAAAAPMAgAAAIAAAAPOQAAACkAAAAPMQgAAAIAAAAPMAAAAD0AAAAPMggAAAIAAAAPJwAAAD8AAAAPMwgAAAIAAAAP7P///14AAAAPNAgAAAIAAAAPcQAAAFEAAAAPNQgAAAIAAAAPdwAAAFcAAAAPNggAAAIAAAAPZQAAAEUAAAAPNwgAAAIAAAAPcgAAAFIAAAAPOAgAAAIAAAAPdAAAAFQAAAAPOQgAAAIAAAAPeQAAAFkAAAAPOggAAAIAAAAPdQAAAFUAAAAPOwgAAAIAAAAPaQAAAEkAAAAPPAgAAAIAAAAPbwAAAE8AAAAPPQgAAAIAAAAPcAAAAFAAAAAPPggAAAIAAAAP6P///+n///8PPwgAAAIAAAAPKwAAACoAAAAPQAgAAAIAAAAPYQAAAEEAAAAPQQgAAAIAAAAPcwAAAFMAAAAPQggAAAIAAAAPZAAAAEQAAAAPQwgAAAIAAAAPZgAAAEYAAAAPRAgAAAIAAAAPZwAAAEcAAAAPRQgAAAIAAAAPaAAAAEgAAAAPRggAAAIAAAAPagAAAEoAAAAPRwgAAAIAAAAPawAAAEsAAAAPSAgAAAIAAAAPbAAAAEwAAAAPSQgAAAIAAAAP8v///+f///8PSggAAAIAAAAP4P///7D///8PSwgAAAIAAAAP+f///6f///8PTAgAAAIAAAAPegAAAFoAAAAPTQgAAAIAAAAPeAAAAFgAAAAPTggAAAIAAAAPYwAAAEMAAAAPTwgAAAIAAAAPdgAAAFYAAAAPUAgAAAIAAAAPYgAAAEIAAAAPUQgAAAIAAAAPbgAAAE4AAAAPUggAAAIAAAAPbQAAAE0AAAAPUwgAAAIAAAAPLAAAADsAAAAPVAgAAAIAAAAPLgAAADoAAAAPVQgAAAIAAAAPLQAAAF8AAAAPVggAAAIAAAAPPAAAAD4AAAAPVwgAAAAAAAAPD1gIAAABAAAAD7D///8PWQgAAAIAAAAPMQAAACEAAAAPWggAAAIAAAAPMgAAACIAAAAPWwgAAAIAAAAPMwAAACMAAAAPXAgAAAIAAAAPNAAAACQAAAAPXQgAAAIAAAAPNQAAACUAAAAPXggAAAIAAAAPNgAAACYAAAAPXwgAAAIAAAAPNwAAAC8AAAAPYAgAAAIAAAAPOAAAACgAAAAPYQgAAAIAAAAPOQAAACkAAAAPYggAAAIAAAAPMAAAAD0AAAAPYwgAAAIAAAAP9v///9b///8PZAgAAAIAAAAPLQAAAF8AAAAPZQgAAAIAAAAPcQAAAFEAAAAPZggAAAIAAAAPdwAAAFcAAAAPZwgAAAIAAAAPZQAAAEUAAAAPaAgAAAIAAAAPcgAAAFIAAAAPaQgAAAIAAAAPdAAAAFQAAAAPaggAAAIAAAAPeQAAAFkAAAAPawgAAAIAAAAPdQAAAFUAAAAPbAgAAAIAAAAPaQAAAEkAAAAPbQgAAAIAAAAPbwAAAE8AAAAPbggAAAIAAAAPcAAAAFAAAAAPbwgAAAIAAAAP8P///9D///8PcAgAAAIAAAAPJwAAAD8AAAAPcQgAAAIAAAAPYQAAAEEAAAAPcggAAAIAAAAPcwAAAFMAAAAPcwgAAAIAAAAPZAAAAEQAAAAPdAgAAAIAAAAPZgAAAEYAAAAPdQgAAAIAAAAPZwAAAEcAAAAPdggAAAIAAAAPaAAAAEgAAAAPdwgAAAIAAAAPagAAAEoAAAAPeAgAAAIAAAAPawAAAEsAAAAPeQgAAAIAAAAPbAAAAEwAAAAPeggAAAIAAAAP5v///8b///8PewgAAAIAAAAPtP///8T///8PfAgAAAIAAAAPKwAAACoAAAAPfQgAAAIAAAAPegAAAFoAAAAPfggAAAIAAAAPeAAAAFgAAAAPfwgAAAIAAAAPYwAAAEMAAAAPgAgAAAIAAAAPdgAAAFYAAAAPgQgAAAIAAAAPYgAAAEIAAAAPgggAAAIAAAAPbgAAAE4AAAAPgwgAAAIAAAAPbQAAAE0AAAAPhAgAAAIAAAAPLAAAADsAAAAPhQgAAAIAAAAPLgAAADoAAAAPhggAAAIAAAAP/v///97///8PhwgAAAIAAAAPPAAAAD4AAAAPiAgAAAAAAAAPD4kIAAACAAAADzAAAACn////D4oIAAADAAAADzEAAAAnAAAAfgAAAA+LCAAAAwAAAA8yAAAAIgAAALf///8PjAgAAAMAAAAPMwAAACsAAABeAAAAD40IAAADAAAADzQAAAAhAAAAov///w+OCAAABAAAAA81AAAAJQAAADAAAACw////D48IAAADAAAADzYAAAAvAAAAsv///w+QCAAAAwAAAA83AAAAPQAAAGAAAAAPkQgAAAMAAAAPOAAAACgAAAD/////D5IIAAADAAAADzkAAAApAAAAtP///w+TCAAAAwAAAA/2////1v///73///8PlAgAAAMAAAAP/P///9z///+o////D5UIAAADAAAAD/P////T////uP///w+WCAAAAwAAAA9xAAAAUQAAAFwAAAAPlwgAAAMAAAAPdwAAAFcAAAB8AAAAD5gIAAACAAAAD2UAAABFAAAAD5kIAAACAAAAD3IAAABSAAAAD5oIAAACAAAAD3QAAABUAAAAD5sIAAACAAAAD3oAAABaAAAAD5wIAAACAAAAD3UAAABVAAAAD50IAAADAAAAD2kAAABJAAAAzf///w+eCAAAAwAAAA9vAAAATwAAAPj///8PnwgAAAIAAAAPcAAAAFAAAAAPoAgAAAMAAAAP9f///9X////3////D6EIAAADAAAAD/r////a////1////w+iCAAAAgAAAA9hAAAAQQAAAA+jCAAAAwAAAA9zAAAAUwAAAPD///8PpAgAAAMAAAAPZAAAAEQAAADQ////D6UIAAADAAAAD2YAAABGAAAAWwAAAA+mCAAAAwAAAA9nAAAARwAAAF0AAAAPpwgAAAIAAAAPaAAAAEgAAAAPqAgAAAMAAAAPagAAAEoAAADt////D6kIAAADAAAAD2sAAABLAAAAs////w+qCAAAAwAAAA9sAAAATAAAAKP///8PqwgAAAMAAAAP6f///8n///8kAAAAD6wIAAADAAAAD+H////B////3////w+tCAAAAwAAAA/7////2////6T///8PrggAAAMAAAAPeQAAAFkAAAA+AAAAD68IAAADAAAAD3gAAABYAAAAIwAAAA+wCAAAAwAAAA9jAAAAQwAAACYAAAAPsQgAAAMAAAAPdgAAAFYAAABAAAAAD7IIAAADAAAAD2IAAABCAAAAewAAAA+zCAAAAwAAAA9uAAAATgAAAH0AAAAPtAgAAAIAAAAPbQAAAE0AAAAPtQgAAAMAAAAPLAAAAD8AAAA7AAAAD7YIAAADAAAADy4AAAA6AAAAPgAAAA+3CAAAAwAAAA8tAAAAXwAAACoAAAAPuAgAAAMAAAAP7f///83///88AAAAD7kIAAAAAAAADw+6CAAAAgAAAA9gAAAAfgAAAA+7CAAAAgAAAA8xAAAAIQAAAA+8CAAAAgAAAA8yAAAAQAAAAA+9CAAAAgAAAA8zAAAAIwAAAA++CAAAAgAAAA80AAAAJAAAAA+/CAAAAgAAAA81AAAAJQAAAA/ACAAAAgAAAA82AAAAXgAAAA/BCAAAAwAAAA83AAAAJgAAAKf///8PwggAAAIAAAAPOAAAACoAAAAPwwgAAAIAAAAPOQAAACgAAAAPxAgAAAIAAAAPMAAAACkAAAAPxQgAAAIAAAAPLQAAAF8AAAAPxggAAAIAAAAPPQAAACsAAAAPxwgAAAIAAAAPcQAAAFEAAAAPyAgAAAIAAAAPdwAAAFcAAAAPyQgAAAQAAAAPZQAAAEUAAADq////yv///w/KCAAAAgAAAA9yAAAAUgAAAA/LCAAAAgAAAA90AAAAVAAAAA/MCAAAAgAAAA95AAAAWQAAAA/NCAAAAgAAAA91AAAAVQAAAA/OCAAAAgAAAA9pAAAASQAAAA/PCAAABAAAAA9vAAAATwAAAPP////T////D9AIAAACAAAAD3AAAABQAAAAD9EIAAACAAAAD1sAAAB7AAAAD9IIAAACAAAAD10AAAB9AAAAD9MIAAAEAAAAD2EAAABBAAAAsf///6H///8P1AgAAAQAAAAPcwAAAFMAAAC2////pv///w/VCAAAAgAAAA9kAAAARAAAAA/WCAAAAgAAAA9mAAAARgAAAA/XCAAAAgAAAA9nAAAARwAAAA/YCAAAAgAAAA9oAAAASAAAAA/ZCAAAAgAAAA9qAAAASgAAAA/aCAAAAgAAAA9rAAAASwAAAA/bCAAABAAAAA9sAAAATAAAALP///+j////D9wIAAACAAAADzsAAAA6AAAAD90IAAACAAAADycAAAAiAAAAD94IAAACAAAAD1wAAAB8AAAAD98IAAAEAAAAD3oAAABaAAAAv////6////8P4AgAAAQAAAAPeAAAAFgAAAC8////rP///w/hCAAABAAAAA9jAAAAQwAAAOb////G////D+IIAAACAAAAD3YAAABWAAAAD+MIAAACAAAAD2IAAABCAAAAD+QIAAAEAAAAD24AAABOAAAA8f///9H///8P5QgAAAIAAAAPbQAAAE0AAAAP5ggAAAIAAAAPLAAAADwAAAAP5wgAAAIAAAAPLgAAAD4AAAAP6AgAAAIAAAAPLwAAAD8AAAAP6QgAAAMAAAAPPAAAAD4AAAB8AAAAD+oIAAAAAAAADw/rCAAAAgAAAA+4////qP///w/sCAAAAgAAAA8xAAAAIQAAAA/tCAAAAgAAAA8yAAAAIgAAAA/uCAAAAgAAAA8zAAAAIwAAAA/vCAAAAgAAAA80AAAAJAAAAA/wCAAAAgAAAA81AAAAJQAAAA/xCAAAAgAAAA82AAAAJgAAAA/yCAAAAgAAAA83AAAALwAAAA/zCAAAAgAAAA84AAAAKAAAAA/0CAAAAgAAAA85AAAAKQAAAA/1CAAAAgAAAA8wAAAAPQAAAA/2CAAAAgAAAA8nAAAAPwAAAA/3CAAAAgAAAA8rAAAAKgAAAA/4CAAAAgAAAA9xAAAAUQAAAA/5CAAAAgAAAA93AAAAVwAAAA/6CAAAAgAAAA9lAAAARQAAAA/7CAAAAgAAAA9yAAAAUgAAAA/8CAAAAgAAAA90AAAAVAAAAA/9CAAAAgAAAA96AAAAWgAAAA/+CAAAAgAAAA91AAAAVQAAAA//CAAAAgAAAA9pAAAASQAAAA8ACQAAAgAAAA9vAAAATwAAAA8BCQAAAgAAAA9wAAAAUAAAAA8CCQAAAgAAAA+5////qf///w8DCQAAAgAAAA/w////0P///w8ECQAAAgAAAA9hAAAAQQAAAA8FCQAAAgAAAA9zAAAAUwAAAA8GCQAAAgAAAA9kAAAARAAAAA8HCQAAAgAAAA9mAAAARgAAAA8ICQAAAgAAAA9nAAAARwAAAA8JCQAAAgAAAA9oAAAASAAAAA8KCQAAAgAAAA9qAAAASgAAAA8LCQAAAgAAAA9rAAAASwAAAA8MCQAAAgAAAA9sAAAATAAAAA8NCQAAAgAAAA/o////yP///w8OCQAAAgAAAA/m////xv///w8PCQAAAgAAAA++////rv///w8QCQAAAgAAAA95AAAAWQAAAA8RCQAAAgAAAA94AAAAWAAAAA8SCQAAAgAAAA9jAAAAQwAAAA8TCQAAAgAAAA92AAAAVgAAAA8UCQAAAgAAAA9iAAAAQgAAAA8VCQAAAgAAAA9uAAAATgAAAA8WCQAAAgAAAA9tAAAATQAAAA8XCQAAAgAAAA8sAAAAOwAAAA8YCQAAAgAAAA8uAAAAOgAAAA8ZCQAAAgAAAA8tAAAAXwAAAA8aCQAAAgAAAA88AAAAPgAAAA8bCQAAAAAAAA8PHAkAAAIAAAAPYAAAAH4AAAAPHQkAAAIAAAAPMQAAACEAAAAPHgkAAAIAAAAPMgAAACIAAAAPHwkAAAIAAAAPMwAAACMAAAAPIAkAAAIAAAAPNAAAACQAAAAPIQkAAAIAAAAPNQAAACUAAAAPIgkAAAIAAAAPNgAAACYAAAAPIwkAAAIAAAAPNwAAAC8AAAAPJAkAAAIAAAAPOAAAACgAAAAPJQkAAAIAAAAPOQAAACkAAAAPJgkAAAIAAAAPMAAAAD0AAAAPJwkAAAIAAAAPJwAAAD8AAAAPKAkAAAIAAAAPKwAAACoAAAAPKQkAAAIAAAAPqf///7n///8PKgkAAAIAAAAPqv///7r///8PKwkAAAIAAAAPxf///+X///8PLAkAAAIAAAAP0v////L///8PLQkAAAIAAAAP1P////T///8PLgkAAAIAAAAP2v////r///8PLwkAAAIAAAAP1f////X///8PMAkAAAIAAAAPyf///+n///8PMQkAAAIAAAAPz////+////8PMgkAAAIAAAAP0P////D///8PMwkAAAIAAAAP2/////v///8PNAkAAAIAAAAPWwAAAF0AAAAPNQkAAAIAAAAPwf///+H///8PNgkAAAIAAAAP0/////P///8PNwkAAAIAAAAPxP///+T///8POAkAAAIAAAAPxv///+b///8POQkAAAIAAAAPx////+f///8POgkAAAIAAAAPyP///+j///8POwkAAAIAAAAPqP///7j///8PPAkAAAIAAAAPy////+v///8PPQkAAAIAAAAPzP///+z///8PPgkAAAIAAAAP3v////7///8PPwkAAAIAAAAPq////7v///8PQAkAAAIAAAAPLQAAAF8AAAAPQQkAAAIAAAAPof///7H///8PQgkAAAIAAAAPr////7////8PQwkAAAIAAAAPw////+P///8PRAkAAAIAAAAP1/////f///8PRQkAAAIAAAAPwv///+L///8PRgkAAAIAAAAPzv///+7///8PRwkAAAIAAAAPzf///+3///8PSAkAAAIAAAAPLAAAADsAAAAPSQkAAAIAAAAPLgAAADoAAAAPSgkAAAIAAAAP1v////b///8PSwkAAAIAAAAPPAAAAD4AAAAPTAkAAAAAAAAPD00JAAACAAAAD2AAAAB+AAAAD04JAAACAAAADzEAAAAhAAAAD08JAAAEAAAADzIAAABAAAAAMgAAACIAAAAPUAkAAAIAAAAPMwAAACMAAAAPUQkAAAIAAAAPNAAAACQAAAAPUgkAAAIAAAAPNQAAACUAAAAPUwkAAAQAAAAPNgAAAF4AAAA2AAAAJgAAAA9UCQAABAAAAA83AAAAJgAAADcAAAAvAAAAD1UJAAAEAAAADzgAAAAqAAAAOAAAACgAAAAPVgkAAAQAAAAPOQAAACgAAAA5AAAAKQAAAA9XCQAABAAAAA8wAAAAKQAAADAAAAA9AAAAD1gJAAAEAAAADy0AAABfAAAAJwAAAD8AAAAPWQkAAAQAAAAPPQAAACsAAAArAAAAKgAAAA9aCQAABAAAAA9xAAAAUQAAAKn///+5////D1sJAAAEAAAAD3cAAABXAAAAqv///7r///8PXAkAAAQAAAAPZQAAAEUAAADF////5f///w9dCQAABAAAAA9yAAAAUgAAANL////y////D14JAAAEAAAAD3QAAABUAAAA1P////T///8PXwkAAAQAAAAPeQAAAFkAAADa////+v///w9gCQAABAAAAA91AAAAVQAAANX////1////D2EJAAAEAAAAD2kAAABJAAAAyf///+n///8PYgkAAAQAAAAPbwAAAE8AAADP////7////w9jCQAABAAAAA9wAAAAUAAAAND////w////D2QJAAAEAAAAD1sAAAB7AAAA2/////v///8PZQkAAAQAAAAPXQAAAH0AAABbAAAAXQAAAA9mCQAABAAAAA9hAAAAQQAAAMH////h////D2cJAAAEAAAAD3MAAABTAAAA0/////P///8PaAkAAAQAAAAPZAAAAEQAAADE////5P///w9pCQAABAAAAA9mAAAARgAAAMb////m////D2oJAAAEAAAAD2cAAABHAAAAx////+f///8PawkAAAQAAAAPaAAAAEgAAADI////6P///w9sCQAABAAAAA9qAAAASgAAAKj///+4////D20JAAAEAAAAD2sAAABLAAAAy////+v///8PbgkAAAQAAAAPbAAAAEwAAADM////7P///w9vCQAABAAAAA87AAAAOgAAAN7////+////D3AJAAAEAAAADycAAAAiAAAAq////7v///8PcQkAAAQAAAAPXAAAAHwAAAAtAAAAXwAAAA9yCQAABAAAAA96AAAAWgAAAKH///+x////D3MJAAAEAAAAD3gAAABYAAAAr////7////8PdAkAAAQAAAAPYwAAAEMAAADD////4////w91CQAABAAAAA92AAAAVgAAANf////3////D3YJAAAEAAAAD2IAAABCAAAAwv///+L///8PdwkAAAQAAAAPbgAAAE4AAADO////7v///w94CQAABAAAAA9tAAAATQAAAM3////t////D3kJAAAEAAAADywAAAA8AAAALAAAADsAAAAPegkAAAQAAAAPLgAAAD4AAAAuAAAAOgAAAA97CQAABAAAAA8vAAAAPwAAANb////2////D3wJAAACAAAADzwAAAA+AAAAD30JAAAAAAAADw9+CQAAAgAAAA+4////qP///w9/CQAAAgAAAA8xAAAAIQAAAA+ACQAAAgAAAA8yAAAAIgAAAA+BCQAAAgAAAA8zAAAAIwAAAA+CCQAAAgAAAA80AAAAJAAAAA+DCQAAAgAAAA81AAAAJQAAAA+ECQAAAgAAAA82AAAAJgAAAA+FCQAAAgAAAA83AAAALwAAAA+GCQAAAgAAAA84AAAAKAAAAA+HCQAAAgAAAA85AAAAKQAAAA+ICQAAAgAAAA8wAAAAPQAAAA+JCQAAAgAAAA8nAAAAPwAAAA+KCQAAAgAAAA8rAAAAKgAAAA+LCQAAAgAAAA9xAAAAUQAAAA+MCQAAAgAAAA93AAAAVwAAAA+NCQAAAgAAAA9lAAAARQAAAA+OCQAAAgAAAA9yAAAAUgAAAA+PCQAAAgAAAA90AAAAVAAAAA+QCQAAAgAAAA96AAAAWgAAAA+RCQAAAgAAAA91AAAAVQAAAA+SCQAAAgAAAA9pAAAASQAAAA+TCQAAAgAAAA9vAAAATwAAAA+UCQAAAgAAAA9wAAAAUAAAAA+VCQAAAgAAAA+5////qf///w+WCQAAAgAAAA/w////0P///w+XCQAAAgAAAA9hAAAAQQAAAA+YCQAAAgAAAA9zAAAAUwAAAA+ZCQAAAgAAAA9kAAAARAAAAA+aCQAAAgAAAA9mAAAARgAAAA+bCQAAAgAAAA9nAAAARwAAAA+cCQAAAgAAAA9oAAAASAAAAA+dCQAAAgAAAA9qAAAASgAAAA+eCQAAAgAAAA9rAAAASwAAAA+fCQAAAgAAAA9sAAAATAAAAA+gCQAAAgAAAA/o////yP///w+hCQAAAgAAAA/m////xv///w+iCQAAAgAAAA++////rv///w+jCQAAAgAAAA95AAAAWQAAAA+kCQAAAgAAAA94AAAAWAAAAA+lCQAAAgAAAA9jAAAAQwAAAA+mCQAAAgAAAA92AAAAVgAAAA+nCQAAAgAAAA9iAAAAQgAAAA+oCQAAAgAAAA9uAAAATgAAAA+pCQAAAgAAAA9tAAAATQAAAA+qCQAAAgAAAA8sAAAAOwAAAA+rCQAAAgAAAA8uAAAAOgAAAA+sCQAAAgAAAA8vAAAAPwAAAA+tCQAAAgAAAA88AAAAPgAAAA+uCQAAAAAAAA8PrwkAAAIAAAAPYAAAAH4AAAAPsAkAAAIAAAAPMQAAACEAAAAPsQkAAAIAAAAPMgAAAEAAAAAPsgkAAAIAAAAPMwAAACMAAAAPswkAAAIAAAAPNAAAACQAAAAPtAkAAAIAAAAPNQAAACUAAAAPtQkAAAIAAAAPNgAAAF4AAAAPtgkAAAIAAAAPNwAAACYAAAAPtwkAAAIAAAAPOAAAACoAAAAPuAkAAAIAAAAPOQAAACgAAAAPuQkAAAIAAAAPMAAAACkAAAAPugkAAAIAAAAPLQAAAF8AAAAPuwkAAAIAAAAPPQAAACsAAAAPvAkAAAIAAAAPcQAAAFEAAAAPvQkAAAIAAAAPdwAAAFcAAAAPvgkAAAIAAAAPZQAAAEUAAAAPvwkAAAIAAAAPcgAAAFIAAAAPwAkAAAIAAAAPdAAAAFQAAAAPwQkAAAIAAAAPeQAAAFkAAAAPwgkAAAIAAAAPdQAAAFUAAAAPwwkAAAIAAAAPaQAAAEkAAAAPxAkAAAIAAAAPbwAAAE8AAAAPxQkAAAIAAAAPcAAAAFAAAAAPxgkAAAQAAAAPWwAAAHsAAAC5////qf///w/HCQAABAAAAA9dAAAAfQAAAPD////Q////D8gJAAACAAAAD2EAAABBAAAAD8kJAAACAAAAD3MAAABTAAAAD8oJAAACAAAAD2QAAABEAAAAD8sJAAACAAAAD2YAAABGAAAAD8wJAAACAAAAD2cAAABHAAAAD80JAAACAAAAD2gAAABIAAAAD84JAAACAAAAD2oAAABKAAAAD88JAAACAAAAD2sAAABLAAAAD9AJAAACAAAAD2wAAABMAAAAD9EJAAAEAAAADzsAAAA6AAAA6P///8j///8P0gkAAAQAAAAPJwAAACIAAADm////xv///w/TCQAABAAAAA9cAAAAfAAAAL7///+u////D9QJAAACAAAAD3oAAABaAAAAD9UJAAACAAAAD3gAAABYAAAAD9YJAAACAAAAD2MAAABDAAAAD9cJAAACAAAAD3YAAABWAAAAD9gJAAACAAAAD2IAAABCAAAAD9kJAAACAAAAD24AAABOAAAAD9oJAAACAAAAD20AAABNAAAAD9sJAAACAAAADywAAAA8AAAAD9wJAAACAAAADy4AAAA+AAAAD90JAAACAAAADy8AAAA/AAAAD94JAAADAAAADzwAAAA+AAAAfAAAAA/fCQAAAAAAAA8P4AkAAAIAAAAPMQAAACEAAAAP4QkAAAIAAAAPMgAAACIAAAAP4gkAAAIAAAAPMwAAACMAAAAP4wkAAAIAAAAPNAAAACQAAAAP5AkAAAIAAAAPNQAAACUAAAAP5QkAAAIAAAAPNgAAACYAAAAP5gkAAAIAAAAPNwAAACcAAAAP5wkAAAIAAAAPOAAAACgAAAAP6AkAAAIAAAAPOQAAACkAAAAP6QkAAAIAAAAPMAAAAH4AAAAP6gkAAAIAAAAPLQAAAD0AAAAP6wkAAAIAAAAPXgAAAH4AAAAP7AkAAAIAAAAPXAAAAHwAAAAP7QkAAAIAAAAPcQAAAFEAAAAP7gkAAAIAAAAPdwAAAFcAAAAP7wkAAAIAAAAPZQAAAEUAAAAP8AkAAAIAAAAPcgAAAFIAAAAP8QkAAAIAAAAPdAAAAFQAAAAP8gkAAAIAAAAPeQAAAFkAAAAP8wkAAAIAAAAPdQAAAFUAAAAP9AkAAAIAAAAPaQAAAEkAAAAP9QkAAAIAAAAPbwAAAE8AAAAP9gkAAAIAAAAPcAAAAFAAAAAP9wkAAAIAAAAPQAAAAGAAAAAP+AkAAAIAAAAPWwAAAHsAAAAP+QkAAAIAAAAPYQAAAEEAAAAP+gkAAAIAAAAPcwAAAFMAAAAP+wkAAAIAAAAPZAAAAEQAAAAP/AkAAAIAAAAPZgAAAEYAAAAP/QkAAAIAAAAPZwAAAEcAAAAP/gkAAAIAAAAPaAAAAEgAAAAP/wkAAAIAAAAPagAAAEoAAAAPAAoAAAIAAAAPawAAAEsAAAAPAQoAAAIAAAAPbAAAAEwAAAAPAgoAAAIAAAAPOwAAACsAAAAPAwoAAAIAAAAPOgAAACoAAAAPBAoAAAIAAAAPXQAAAH0AAAAPBQoAAAIAAAAPegAAAFoAAAAPBgoAAAIAAAAPeAAAAFgAAAAPBwoAAAIAAAAPYwAAAEMAAAAPCAoAAAIAAAAPdgAAAFYAAAAPCQoAAAIAAAAPYgAAAEIAAAAPCgoAAAIAAAAPbgAAAE4AAAAPCwoAAAIAAAAPbQAAAE0AAAAPDAoAAAIAAAAPLAAAADwAAAAPDQoAAAIAAAAPLgAAAD4AAAAPDgoAAAIAAAAPLwAAAD8AAAAPDwoAAAIAAAAPXAAAAF8AAAAPEAoAAAAAAAAPDxEKAAACAAAADzEAAAAhAAAADxIKAAACAAAADzIAAAAiAAAADxMKAAACAAAADzMAAAAjAAAADxQKAAACAAAADzQAAAAkAAAADxUKAAACAAAADzUAAAAlAAAADxYKAAACAAAADzYAAAAmAAAADxcKAAACAAAADzcAAAAnAAAADxgKAAACAAAADzgAAAAoAAAADxkKAAACAAAADzkAAAApAAAADxoKAAABAAAADzAAAAAPGwoAAAIAAAAPLQAAAD0AAAAPHAoAAAIAAAAPXgAAAGAAAAAPHQoAAAIAAAAPXAAAAHwAAAAPHgoAAAIAAAAPcQAAAFEAAAAPHwoAAAIAAAAPdwAAAFcAAAAPIAoAAAIAAAAPZQAAAEUAAAAPIQoAAAIAAAAPcgAAAFIAAAAPIgoAAAIAAAAPdAAAAFQAAAAPIwoAAAIAAAAPeQAAAFkAAAAPJAoAAAIAAAAPdQAAAFUAAAAPJQoAAAIAAAAPaQAAAEkAAAAPJgoAAAIAAAAPbwAAAE8AAAAPJwoAAAIAAAAPcAAAAFAAAAAPKAoAAAIAAAAPQAAAAH4AAAAPKQoAAAIAAAAPWwAAAHsAAAAPKgoAAAIAAAAPYQAAAEEAAAAPKwoAAAIAAAAPcwAAAFMAAAAPLAoAAAIAAAAPZAAAAEQAAAAPLQoAAAIAAAAPZgAAAEYAAAAPLgoAAAIAAAAPZwAAAEcAAAAPLwoAAAIAAAAPaAAAAEgAAAAPMAoAAAIAAAAPagAAAEoAAAAPMQoAAAIAAAAPawAAAEsAAAAPMgoAAAIAAAAPbAAAAEwAAAAPMwoAAAIAAAAPOwAAACsAAAAPNAoAAAIAAAAPOgAAACoAAAAPNQoAAAIAAAAPXQAAAH0AAAAPNgoAAAIAAAAPegAAAFoAAAAPNwoAAAIAAAAPeAAAAFgAAAAPOAoAAAIAAAAPYwAAAEMAAAAPOQoAAAIAAAAPdgAAAFYAAAAPOgoAAAIAAAAPYgAAAEIAAAAPOwoAAAIAAAAPbgAAAE4AAAAPPAoAAAIAAAAPbQAAAE0AAAAPPQoAAAIAAAAPLAAAADwAAAAPPgoAAAIAAAAPLgAAAD4AAAAPPwoAAAIAAAAPLwAAAD8AAAAPQAoAAAIAAAAPXAAAAF8AAAAPQQoAAAAAAAAPD0IKAAACAAAADzsAAAAwAAAAD0MKAAACAAAADysAAAAxAAAAD0QKAAACAAAAD7X///8yAAAAD0UKAAACAAAAD7n///8zAAAAD0YKAAACAAAAD+j///80AAAAD0cKAAACAAAAD7v///81AAAAD0gKAAACAAAAD77///82AAAAD0kKAAACAAAAD/3///83AAAAD0oKAAACAAAAD+H///84AAAAD0sKAAACAAAAD+3///85AAAAD0wKAAACAAAAD+n///8wAAAAD00KAAACAAAADz0AAAAlAAAAD04KAAACAAAADycAAAB2AAAAD08KAAACAAAAD3EAAABRAAAAD1AKAAACAAAAD3cAAABXAAAAD1EKAAACAAAAD2UAAABFAAAAD1IKAAACAAAAD3IAAABSAAAAD1MKAAACAAAAD3QAAABUAAAAD1QKAAACAAAAD3kAAABZAAAAD1UKAAACAAAAD3UAAABVAAAAD1YKAAACAAAAD2kAAABJAAAAD1cKAAACAAAAD28AAABPAAAAD1gKAAACAAAAD3AAAABQAAAAD1kKAAACAAAAD/r///8vAAAAD1oKAAACAAAAD+T///8oAAAAD1sKAAACAAAAD2EAAABBAAAAD1wKAAACAAAAD3MAAABTAAAAD10KAAACAAAAD2QAAABEAAAAD14KAAACAAAAD2YAAABGAAAAD18KAAACAAAAD2cAAABHAAAAD2AKAAACAAAAD2gAAABIAAAAD2EKAAACAAAAD2oAAABKAAAAD2IKAAACAAAAD2sAAABLAAAAD2MKAAACAAAAD2wAAABMAAAAD2QKAAACAAAAD/T///8iAAAAD2UKAAACAAAAD6f///8hAAAAD2YKAAACAAAAD/L///8pAAAAD2cKAAACAAAAD3oAAABaAAAAD2gKAAACAAAAD3gAAABYAAAAD2kKAAACAAAAD2MAAABDAAAAD2oKAAACAAAAD3YAAABWAAAAD2sKAAACAAAAD2IAAABCAAAAD2wKAAACAAAAD24AAABOAAAAD20KAAACAAAAD20AAABNAAAAD24KAAACAAAADywAAAA/AAAAD28KAAACAAAADy4AAAA6AAAAD3AKAAACAAAADy0AAABfAAAAD3EKAAACAAAADzwAAAA+AAAAD3IKAAAAAAAADw9zCgAAAgAAAA9gAAAAfgAAAA90CgAAAgAAAA8xAAAAIQAAAA91CgAAAgAAAA8yAAAAQAAAAA92CgAAAgAAAA8zAAAAIwAAAA93CgAAAgAAAA80AAAAJAAAAA94CgAAAgAAAA81AAAAJQAAAA95CgAAAgAAAA82AAAAXgAAAA96CgAAAgAAAA83AAAAJgAAAA97CgAAAgAAAA84AAAAKgAAAA98CgAAAgAAAA85AAAAKAAAAA99CgAAAgAAAA8wAAAAKQAAAA9+CgAAAgAAAA8tAAAAXwAAAA9/CgAAAgAAAA89AAAAKwAAAA+ACgAABAAAAA9xAAAAUQAAAOT////E////D4EKAAAEAAAAD3cAAABXAAAA7P///8z///8PggoAAAQAAAAPZQAAAEUAAADp////yf///w+DCgAABAAAAA9yAAAAUgAAAPj////Y////D4QKAAAEAAAAD3QAAABUAAAAu////6v///8PhQoAAAQAAAAPeQAAAFkAAAD9////3f///w+GCgAABAAAAA91AAAAVQAAAPn////Z////D4cKAAAEAAAAD2kAAABJAAAA7f///83///8PiAoAAAQAAAAPbwAAAE8AAADz////0////w+JCgAABAAAAA9wAAAAUAAAAPb////W////D4oKAAACAAAAD1sAAAB7AAAAD4sKAAACAAAAD10AAAB9AAAAD4wKAAAEAAAAD2EAAABBAAAA4f///8H///8PjQoAAAQAAAAPcwAAAFMAAAC5////qf///w+OCgAABAAAAA9kAAAARAAAAO/////P////D48KAAAEAAAAD2YAAABGAAAA6////8v///8PkAoAAAQAAAAPZwAAAEcAAADg////wP///w+RCgAABAAAAA9oAAAASAAAAPr////a////D5IKAAAEAAAAD2oAAABKAAAA/P///9z///8PkwoAAAQAAAAPawAAAEsAAAD0////1P///w+UCgAABAAAAA9sAAAATAAAALX///+l////D5UKAAACAAAADzsAAAA6AAAAD5YKAAACAAAADycAAAAiAAAAD5cKAAACAAAAD1wAAAB8AAAAD5gKAAAEAAAAD3oAAABaAAAAvv///67///8PmQoAAAMAAAAPeAAAAFgAAACk////D5oKAAAEAAAAD2MAAABDAAAA6P///8j///8PmwoAAAQAAAAPdgAAAFYAAADn////x////w+cCgAAAgAAAA9iAAAAQgAAAA+dCgAABAAAAA9uAAAATgAAAPL////S////D54KAAAEAAAAD20AAABNAAAA5f///8X///8PnwoAAAIAAAAPLAAAADwAAAAPoAoAAAIAAAAPLgAAAD4AAAAPoQoAAAIAAAAPLwAAAD8AAAAPogoAAAIAAAAPPAAAAD4AAAAPowoAAAAAAAAPD6QKAAABAAAADzsAAAAPpQoAAAIAAAAPKwAAADEAAAAPpgoAAAIAAAAP7P///zIAAAAPpwoAAAIAAAAPuf///zMAAAAPqAoAAAIAAAAP6P///zQAAAAPqQoAAAIAAAAP+P///zUAAAAPqgoAAAIAAAAPvv///zYAAAAPqwoAAAIAAAAP/f///zcAAAAPrAoAAAIAAAAP4f///zgAAAAPrQoAAAIAAAAP7f///zkAAAAPrgoAAAQAAAAP6f///zAAAAC9////KQAAAA+vCgAAAgAAAA89AAAAJQAAAA+wCgAAAAAAAA8PsQoAAAMAAAAPcQAAAFEAAABcAAAAD7IKAAADAAAAD3cAAABXAAAAfAAAAA+zCgAAAgAAAA9lAAAARQAAAA+0CgAAAgAAAA9yAAAAUgAAAA+1CgAAAgAAAA90AAAAVAAAAA+2CgAAAgAAAA95AAAAWQAAAA+3CgAAAgAAAA91AAAAVQAAAA+4CgAAAgAAAA9pAAAASQAAAA+5CgAAAgAAAA9vAAAATwAAAA+6CgAAAgAAAA9wAAAAUAAAAA+7CgAABAAAAA/6////LwAAAFsAAAB7AAAAD7wKAAAEAAAADykAAAAoAAAAXQAAAH0AAAAPvQoAAAIAAAAPYQAAAEEAAAAPvgoAAAMAAAAPcwAAAFMAAADw////D78KAAADAAAAD2QAAABEAAAA0P///w/ACgAAAwAAAA9mAAAARgAAAFsAAAAPwQoAAAMAAAAPZwAAAEcAAABdAAAAD8IKAAACAAAAD2gAAABIAAAAD8MKAAACAAAAD2oAAABKAAAAD8QKAAADAAAAD2sAAABLAAAAs////w/FCgAAAwAAAA9sAAAATAAAAKP///8PxgoAAAMAAAAP+f///yIAAAAkAAAAD8cKAAADAAAAD6f///8hAAAA3////w/ICgAAAgAAAA+o////JwAAAA/JCgAAAwAAAA96AAAAWgAAAD4AAAAPygoAAAMAAAAPeAAAAFgAAAAjAAAAD8sKAAADAAAAD2MAAABDAAAAJgAAAA/MCgAAAwAAAA92AAAAVgAAAEAAAAAPzQoAAAMAAAAPYgAAAEIAAAB7AAAAD84KAAADAAAAD24AAABOAAAAfQAAAA/PCgAAAgAAAA9tAAAATQAAAA/QCgAAAwAAAA8sAAAAPwAAADwAAAAP0QoAAAMAAAAPLgAAADoAAAA+AAAAD9IKAAADAAAADy0AAABfAAAAKgAAAA/TCgAABAAAAA88AAAAPgAAAFwAAAB8AAAAD9QKAAAAAAAADw/VCgAAAQAAAA87AAAAD9YKAAACAAAADysAAAAxAAAAD9cKAAACAAAAD+z///8yAAAAD9gKAAACAAAAD7n///8zAAAAD9kKAAACAAAAD+j///80AAAAD9oKAAACAAAAD/j///81AAAAD9sKAAACAAAAD77///82AAAAD9wKAAACAAAAD/3///83AAAAD90KAAACAAAAD+H///84AAAAD94KAAACAAAAD+3///85AAAAD98KAAACAAAAD+n///8wAAAAD+AKAAACAAAADz0AAAAlAAAAD+EKAAACAAAAD7T///+3////D+IKAAACAAAAD3EAAABRAAAAD+MKAAACAAAAD3cAAABXAAAAD+QKAAACAAAAD2UAAABFAAAAD+UKAAACAAAAD3IAAABSAAAAD+YKAAACAAAAD3QAAABUAAAAD+cKAAACAAAAD3oAAABaAAAAD+gKAAACAAAAD3UAAABVAAAAD+kKAAACAAAAD2kAAABJAAAAD+oKAAACAAAAD28AAABPAAAAD+sKAAACAAAAD3AAAABQAAAAD+wKAAACAAAAD/r///8vAAAAD+0KAAACAAAADykAAAAoAAAAD+4KAAACAAAAD2EAAABBAAAAD+8KAAACAAAAD3MAAABTAAAAD/AKAAACAAAAD2QAAABEAAAAD/EKAAACAAAAD2YAAABGAAAAD/IKAAACAAAAD2cAAABHAAAAD/MKAAACAAAAD2gAAABIAAAAD/QKAAACAAAAD2oAAABKAAAAD/UKAAACAAAAD2sAAABLAAAAD/YKAAACAAAAD2wAAABMAAAAD/cKAAACAAAAD/n///8iAAAAD/gKAAACAAAAD6f///8hAAAAD/kKAAACAAAAD6j///8nAAAAD/oKAAACAAAAD3kAAABZAAAAD/sKAAACAAAAD3gAAABYAAAAD/wKAAACAAAAD2MAAABDAAAAD/0KAAACAAAAD3YAAABWAAAAD/4KAAACAAAAD2IAAABCAAAAD/8KAAACAAAAD24AAABOAAAADwALAAACAAAAD20AAABNAAAADwELAAACAAAADywAAAA/AAAADwILAAACAAAADy4AAAA6AAAADwMLAAACAAAADy0AAABfAAAADwQLAAABAAAAD1wAAAAPBQsAAAAAAAAPDwYLAAABAAAADzsAAAAPBwsAAAIAAAAPKwAAADEAAAAPCAsAAAIAAAAP7P///zIAAAAPCQsAAAIAAAAPuf///zMAAAAPCgsAAAIAAAAP6P///zQAAAAPCwsAAAIAAAAP+P///zUAAAAPDAsAAAIAAAAPvv///zYAAAAPDQsAAAIAAAAP/f///zcAAAAPDgsAAAIAAAAP4f///zgAAAAPDwsAAAIAAAAP7f///zkAAAAPEAsAAAIAAAAP6f///zAAAAAPEQsAAAIAAAAPPQAAACUAAAAPEgsAAAIAAAAPtP///7f///8PEwsAAAIAAAAPcQAAAFEAAAAPFAsAAAIAAAAPdwAAAFcAAAAPFQsAAAIAAAAPZQAAAEUAAAAPFgsAAAIAAAAPcgAAAFIAAAAPFwsAAAIAAAAPdAAAAFQAAAAPGAsAAAIAAAAPeQAAAFkAAAAPGQsAAAIAAAAPdQAAAFUAAAAPGgsAAAIAAAAPaQAAAEkAAAAPGwsAAAIAAAAPbwAAAE8AAAAPHAsAAAIAAAAPcAAAAFAAAAAPHQsAAAIAAAAP+v///y8AAAAPHgsAAAIAAAAPKQAAACgAAAAPHwsAAAIAAAAPYQAAAEEAAAAPIAsAAAIAAAAPcwAAAFMAAAAPIQsAAAIAAAAPZAAAAEQAAAAPIgsAAAIAAAAPZgAAAEYAAAAPIwsAAAIAAAAPZwAAAEcAAAAPJAsAAAIAAAAPaAAAAEgAAAAPJQsAAAIAAAAPagAAAEoAAAAPJgsAAAIAAAAPawAAAEsAAAAPJwsAAAIAAAAPbAAAAEwAAAAPKAsAAAIAAAAP+f///yIAAAAPKQsAAAIAAAAPp////yEAAAAPKgsAAAIAAAAPqP///ycAAAAPKwsAAAIAAAAPegAAAFoAAAAPLAsAAAIAAAAPeAAAAFgAAAAPLQsAAAIAAAAPYwAAAEMAAAAPLgsAAAIAAAAPdgAAAFYAAAAPLwsAAAIAAAAPYgAAAEIAAAAPMAsAAAIAAAAPbgAAAE4AAAAPMQsAAAIAAAAPbQAAAE0AAAAPMgsAAAIAAAAPLAAAAD8AAAAPMwsAAAIAAAAPLgAAADoAAAAPNAsAAAIAAAAPLQAAAF8AAAAPNQsAAAEAAAAPXAAAAA82CwAAAAAAAA8PNwsAAAIAAAAPfAAAALD///8POAsAAAIAAAAPMQAAACEAAAAPOQsAAAIAAAAPMgAAACIAAAAPOgsAAAIAAAAPMwAAACMAAAAPOwsAAAIAAAAPNAAAACQAAAAPPAsAAAIAAAAPNQAAACUAAAAPPQsAAAIAAAAPNgAAACYAAAAPPgsAAAIAAAAPNwAAAC8AAAAPPwsAAAIAAAAPOAAAACgAAAAPQAsAAAIAAAAPOQAAACkAAAAPQQsAAAIAAAAPMAAAAD0AAAAPQgsAAAIAAAAPJwAAAD8AAAAPQwsAAAIAAAAPv////6H///8PRAsAAAMAAAAPcQAAAFEAAABAAAAAD0ULAAACAAAAD3cAAABXAAAAD0YLAAACAAAAD2UAAABFAAAAD0cLAAACAAAAD3IAAABSAAAAD0gLAAACAAAAD3QAAABUAAAAD0kLAAACAAAAD3kAAABZAAAAD0oLAAACAAAAD3UAAABVAAAAD0sLAAACAAAAD2kAAABJAAAAD0wLAAACAAAAD28AAABPAAAAD00LAAACAAAAD3AAAABQAAAAD04LAAACAAAAD7T///+o////D08LAAACAAAADysAAAAqAAAAD1ALAAACAAAAD2EAAABBAAAAD1ELAAACAAAAD3MAAABTAAAAD1ILAAACAAAAD2QAAABEAAAAD1MLAAACAAAAD2YAAABGAAAAD1QLAAACAAAAD2cAAABHAAAAD1ULAAACAAAAD2gAAABIAAAAD1YLAAACAAAAD2oAAABKAAAAD1cLAAACAAAAD2sAAABLAAAAD1gLAAACAAAAD2wAAABMAAAAD1kLAAACAAAAD/H////R////D1oLAAADAAAAD3sAAABbAAAAXgAAAA9bCwAAAgAAAA99AAAAXQAAAA9cCwAAAgAAAA96AAAAWgAAAA9dCwAAAgAAAA94AAAAWAAAAA9eCwAAAgAAAA9jAAAAQwAAAA9fCwAAAgAAAA92AAAAVgAAAA9gCwAAAgAAAA9iAAAAQgAAAA9hCwAAAgAAAA9uAAAATgAAAA9iCwAAAgAAAA9tAAAATQAAAA9jCwAAAgAAAA8sAAAAOwAAAA9kCwAAAgAAAA8uAAAAOgAAAA9lCwAAAgAAAA8tAAAAXwAAAA9mCwAAAgAAAA88AAAAPgAAAA9nCwAAAAAAAA8PaAsAAAIAAAAPYAAAAH4AAAAPaQsAAAIAAAAP4P///8D///8PagsAAAIAAAAP6P///8j///8PawsAAAIAAAAP5v///8b///8PbAsAAAIAAAAP6////8v///8PbQsAAAIAAAAP4f///8H///8PbgsAAAIAAAAP8P///9D///8PbwsAAAIAAAAP+P///9j///8PcAsAAAIAAAAP+////9v///8PcQsAAAIAAAAPpf///ygAAAAPcgsAAAIAAAAPtP///ykAAAAPcwsAAAIAAAAPLQAAAF8AAAAPdAsAAAIAAAAP/v///97///8PdQsAAAIAAAAPXAAAAHwAAAAPdgsAAAIAAAAPcQAAAFEAAAAPdwsAAAIAAAAPdwAAAFcAAAAPeAsAAAIAAAAPZQAAAEUAAAAPeQsAAAIAAAAPcgAAAFIAAAAPegsAAAIAAAAPdAAAAFQAAAAPewsAAAIAAAAPeQAAAFkAAAAPfAsAAAIAAAAPdQAAAFUAAAAPfQsAAAIAAAAPaQAAAEkAAAAPfgsAAAIAAAAPbwAAAE8AAAAPfwsAAAIAAAAPcAAAAFAAAAAPgAsAAAIAAAAPWwAAAHsAAAAPgQsAAAIAAAAPXQAAAH0AAAAPggsAAAIAAAAPYQAAAEEAAAAPgwsAAAIAAAAPcwAAAFMAAAAPhAsAAAIAAAAPZAAAAEQAAAAPhQsAAAIAAAAPZgAAAEYAAAAPhgsAAAIAAAAPZwAAAEcAAAAPhwsAAAIAAAAPaAAAAEgAAAAPiAsAAAIAAAAPagAAAEoAAAAPiQsAAAIAAAAPawAAAEsAAAAPigsAAAIAAAAPbAAAAEwAAAAPiwsAAAIAAAAPOwAAADoAAAAPjAsAAAIAAAAPJwAAACIAAAAPjQsAAAIAAAAPegAAAFoAAAAPjgsAAAIAAAAPeAAAAFgAAAAPjwsAAAIAAAAPYwAAAEMAAAAPkAsAAAIAAAAPdgAAAFYAAAAPkQsAAAIAAAAPYgAAAEIAAAAPkgsAAAIAAAAPbgAAAE4AAAAPkwsAAAIAAAAPbQAAAE0AAAAPlAsAAAIAAAAPLAAAADwAAAAPlQsAAAIAAAAPLgAAAD4AAAAPlgsAAAIAAAAPLwAAAD8AAAAPlwsAAAAAAAAPD5gLAAAAAAAADw+ZCwAAAgAAAA8iAAAA6f///w+aCwAAAgAAAA8xAAAAIQAAAA+bCwAAAgAAAA8yAAAAJwAAAA+cCwAAAwAAAA8zAAAAXgAAACMAAAAPnQsAAAMAAAAPNAAAACsAAAAkAAAAD54LAAACAAAADzUAAAAlAAAAD58LAAACAAAADzYAAAAmAAAAD6ALAAADAAAADzcAAAAvAAAAewAAAA+hCwAAAwAAAA84AAAAKAAAAFsAAAAPogsAAAMAAAAPOQAAACkAAABdAAAAD6MLAAADAAAADzAAAAA9AAAAfQAAAA+kCwAAAwAAAA8qAAAAPwAAAFwAAAAPpQsAAAIAAAAPLQAAAF8AAAAPpgsAAAMAAAAPcQAAAFEAAABAAAAAD6cLAAACAAAAD3cAAABXAAAAD6gLAAACAAAAD2UAAABFAAAAD6kLAAACAAAAD3IAAABSAAAAD6oLAAACAAAAD3QAAABUAAAAD6sLAAACAAAAD3kAAABZAAAAD6wLAAACAAAAD3UAAABVAAAAD60LAAADAAAAD/3///9JAAAA7v///w+uCwAAAgAAAA9vAAAATwAAAA+vCwAAAgAAAA9wAAAAUAAAAA+wCwAAAgAAAA/w////0P///w+xCwAAAwAAAA/8////3P///34AAAAPsgsAAAMAAAAPYQAAAEEAAADm////D7MLAAADAAAAD3MAAABTAAAA3////w+0CwAAAgAAAA9kAAAARAAAAA+1CwAAAgAAAA9mAAAARgAAAA+2CwAAAgAAAA9nAAAARwAAAA+3CwAAAgAAAA9oAAAASAAAAA+4CwAAAgAAAA9qAAAASgAAAA+5CwAAAgAAAA9rAAAASwAAAA+6CwAAAgAAAA9sAAAATAAAAA+7CwAAAgAAAA/+////3v///w+8CwAAAgAAAA9pAAAA3f///w+9CwAAAwAAAA8sAAAAOwAAAGAAAAAPvgsAAAIAAAAPegAAAFoAAAAPvwsAAAIAAAAPeAAAAFgAAAAPwAsAAAIAAAAPYwAAAEMAAAAPwQsAAAIAAAAPdgAAAFYAAAAPwgsAAAIAAAAPYgAAAEIAAAAPwwsAAAIAAAAPbgAAAE4AAAAPxAsAAAIAAAAPbQAAAE0AAAAPxQsAAAIAAAAP9v///9b///8PxgsAAAIAAAAP5////8f///8PxwsAAAIAAAAPLgAAADoAAAAPyAsAAAAAAAAPD8kLAAAAAAAADw/KCwAAAgAAAA8iAAAAXAAAAA/LCwAAAgAAAA8xAAAAIQAAAA/MCwAAAgAAAA8yAAAAJwAAAA/NCwAAAgAAAA8zAAAAXgAAAA/OCwAAAgAAAA80AAAAKwAAAA/PCwAAAgAAAA81AAAAJQAAAA/QCwAAAgAAAA82AAAAJgAAAA/RCwAAAgAAAA83AAAALwAAAA/SCwAAAgAAAA84AAAAKAAAAA/TCwAAAgAAAA85AAAAKQAAAA/UCwAAAgAAAA8wAAAAPQAAAA/VCwAAAgAAAA8qAAAAPwAAAA/WCwAAAgAAAA8tAAAAXwAAAA/XCwAAAgAAAA9xAAAAUQAAAA/YCwAAAgAAAA93AAAAVwAAAA/ZCwAAAgAAAA9lAAAARQAAAA/aCwAAAgAAAA9yAAAAUgAAAA/bCwAAAgAAAA90AAAAVAAAAA/cCwAAAgAAAA95AAAAWQAAAA/dCwAAAgAAAA91AAAAVQAAAA/eCwAAAgAAAA+5////SQAAAA/fCwAAAgAAAA9vAAAATwAAAA/gCwAAAgAAAA9wAAAAUAAAAA/hCwAAAgAAAA+7////q////w/iCwAAAgAAAA/8////3P///w/jCwAAAgAAAA9hAAAAQQAAAA/kCwAAAgAAAA9zAAAAUwAAAA/lCwAAAgAAAA9kAAAARAAAAA/mCwAAAgAAAA9mAAAARgAAAA/nCwAAAgAAAA9nAAAARwAAAA/oCwAAAgAAAA9oAAAASAAAAA/pCwAAAgAAAA9qAAAASgAAAA/qCwAAAgAAAA9rAAAASwAAAA/rCwAAAgAAAA9sAAAATAAAAA/sCwAAAgAAAA+6////qv///w/tCwAAAQAAAA9pAAAAD+4LAAACAAAADywAAAA7AAAAD+8LAAACAAAAD3oAAABaAAAAD/ALAAACAAAAD3gAAABYAAAAD/ELAAACAAAAD2MAAABDAAAAD/ILAAACAAAAD3YAAABWAAAAD/MLAAACAAAAD2IAAABCAAAAD/QLAAACAAAAD24AAABOAAAAD/ULAAACAAAAD20AAABNAAAAD/YLAAACAAAAD/b////W////D/cLAAACAAAAD+f////H////D/gLAAACAAAADy4AAAA6AAAAD/kLAAACAAAADzwAAAA+AAAAD/oLAAAAAAAADw/7CwAAAgAAAA8rAAAAKgAAAA/8CwAAAgAAAA8xAAAAIQAAAA/9CwAAAgAAAA8yAAAAIgAAAA/+CwAAAwAAAA8zAAAAXgAAACMAAAAP/wsAAAIAAAAPNAAAACQAAAAPAAwAAAIAAAAPNQAAACUAAAAPAQwAAAIAAAAPNgAAACYAAAAPAgwAAAIAAAAPNwAAACcAAAAPAwwAAAIAAAAPOAAAACgAAAAPBAwAAAIAAAAPOQAAACkAAAAPBQwAAAIAAAAPMAAAAD0AAAAPBgwAAAIAAAAPLwAAAD8AAAAPBwwAAAIAAAAPLQAAAF8AAAAPCAwAAAIAAAAPZgAAAEYAAAAPCQwAAAIAAAAPZwAAAEcAAAAPCgwAAAIAAAAPu////6v///8PCwwAAAIAAAAPuf///0kAAAAPDAwAAAIAAAAPbwAAAE8AAAAPDQwAAAIAAAAPZAAAAEQAAAAPDgwAAAIAAAAPcgAAAFIAAAAPDwwAAAIAAAAPbgAAAE4AAAAPEAwAAAIAAAAPaAAAAEgAAAAPEQwAAAIAAAAPcAAAAFAAAAAPEgwAAAIAAAAPcQAAAFEAAAAPEwwAAAIAAAAPdwAAAFcAAAAPFAwAAAIAAAAPdQAAAFUAAAAPFQwAAAEAAAAPaQAAAA8WDAAAAgAAAA9lAAAARQAAAA8XDAAAAgAAAA9hAAAAQQAAAA8YDAAAAgAAAA/8////3P///w8ZDAAAAgAAAA90AAAAVAAAAA8aDAAAAgAAAA9rAAAASwAAAA8bDAAAAgAAAA9tAAAATQAAAA8cDAAAAgAAAA9sAAAATAAAAA8dDAAAAgAAAA95AAAAWQAAAA8eDAAAAgAAAA+6////qv///w8fDAAAAgAAAA94AAAAWAAAAA8gDAAAAgAAAA9qAAAASgAAAA8hDAAAAgAAAA/2////1v///w8iDAAAAgAAAA92AAAAVgAAAA8jDAAAAgAAAA9jAAAAQwAAAA8kDAAAAgAAAA/n////x////w8lDAAAAgAAAA96AAAAWgAAAA8mDAAAAgAAAA9zAAAAUwAAAA8nDAAAAgAAAA9iAAAAQgAAAA8oDAAAAgAAAA8uAAAAOgAAAA8pDAAAAgAAAA8sAAAAOwAAAA8qDAAAAgAAAA88AAAAPgAAAA8rDAAAAAAAAA8PLAwAAAMAAAAPYAAAAH4AAAA7AAAADy0MAAACAAAADzEAAAAhAAAADy4MAAACAAAADzIAAABAAAAADy8MAAACAAAADzMAAAAjAAAADzAMAAACAAAADzQAAAAkAAAADzEMAAACAAAADzUAAAAlAAAADzIMAAACAAAADzYAAABeAAAADzMMAAACAAAADzcAAAAmAAAADzQMAAACAAAADzgAAAAqAAAADzUMAAACAAAADzkAAAAoAAAADzYMAAACAAAADzAAAAApAAAADzcMAAACAAAADy0AAABfAAAADzgMAAACAAAADz0AAAArAAAADzkMAAADAAAAD3EAAABRAAAALwAAAA86DAAAAwAAAA93AAAAVwAAACcAAAAPOwwAAAMAAAAPZQAAAEUAAAD3////DzwMAAADAAAAD3IAAABSAAAA+P///w89DAAAAwAAAA90AAAAVAAAAOD///8PPgwAAAMAAAAPeQAAAFkAAADo////Dz8MAAADAAAAD3UAAABVAAAA5f///w9ADAAAAwAAAA9pAAAASQAAAO////8PQQwAAAMAAAAPbwAAAE8AAADt////D0IMAAADAAAAD3AAAABQAAAA9P///w9DDAAAAgAAAA9bAAAAewAAAA9EDAAAAgAAAA9dAAAAfQAAAA9FDAAAAwAAAA9hAAAAQQAAAPn///8PRgwAAAMAAAAPcwAAAFMAAADj////D0cMAAADAAAAD2QAAABEAAAA4v///w9IDAAAAwAAAA9mAAAARgAAAOv///8PSQwAAAMAAAAPZwAAAEcAAADy////D0oMAAADAAAAD2gAAABIAAAA6f///w9LDAAAAwAAAA9qAAAASgAAAOf///8PTAwAAAMAAAAPawAAAEsAAADs////D00MAAADAAAAD2wAAABMAAAA6v///w9ODAAAAwAAAA87AAAAOgAAAPP///8PTwwAAAMAAAAPJwAAACIAAAAsAAAAD1AMAAACAAAAD1wAAAB8AAAAD1EMAAADAAAAD3oAAABaAAAA5v///w9SDAAAAwAAAA94AAAAWAAAAPH///8PUwwAAAMAAAAPYwAAAEMAAADh////D1QMAAADAAAAD3YAAABWAAAA5P///w9VDAAAAwAAAA9iAAAAQgAAAPD///8PVgwAAAMAAAAPbgAAAE4AAADu////D1cMAAADAAAAD20AAABNAAAA9v///w9YDAAAAwAAAA8sAAAAPAAAAPr///8PWQwAAAMAAAAPLgAAAD4AAAD1////D1oMAAADAAAADy8AAAA/AAAALgAAAA9bDAAAAgAAAA88AAAAPgAAAA9cDAAAAAAAAA8PXQwAAAIAAAAPYAAAAH4AAAAPXgwAAAIAAAAPMQAAACEAAAAPXwwAAAIAAAAPMgAAAEAAAAAPYAwAAAIAAAAPMwAAACMAAAAPYQwAAAIAAAAPNAAAACQAAAAPYgwAAAIAAAAPNQAAACUAAAAPYwwAAAIAAAAPNgAAAF4AAAAPZAwAAAIAAAAPNwAAACYAAAAPZQwAAAIAAAAPOAAAACoAAAAPZgwAAAIAAAAPOQAAACgAAAAPZwwAAAIAAAAPMAAAACkAAAAPaAwAAAIAAAAPLQAAAF8AAAAPaQwAAAIAAAAPPQAAACsAAAAPagwAAAMAAAAPcQAAAFEAAAD3////D2sMAAADAAAAD3cAAABXAAAA5f///w9sDAAAAwAAAA9lAAAARQAAAOD///8PbQwAAAMAAAAPcgAAAFIAAAD4////D24MAAADAAAAD3QAAABUAAAA+v///w9vDAAAAwAAAA95AAAAWQAAAPL///8PcAwAAAMAAAAPdQAAAFUAAADl////D3EMAAADAAAAD2kAAABJAAAA6f///w9yDAAAAwAAAA9vAAAATwAAAPH///8PcwwAAAMAAAAPcAAAAFAAAAD0////D3QMAAACAAAAD1sAAAB7AAAAD3UMAAACAAAAD10AAAB9AAAAD3YMAAADAAAAD2EAAABBAAAA4P///w93DAAAAwAAAA9zAAAAUwAAAPn///8PeAwAAAMAAAAPZAAAAEQAAADj////D3kMAAADAAAAD2YAAABGAAAA9P///w96DAAAAwAAAA9nAAAARwAAAOL///8PewwAAAMAAAAPaAAAAEgAAADk////D3wMAAADAAAAD2oAAABKAAAA6f///w99DAAAAwAAAA9rAAAASwAAAOv///8PfgwAAAMAAAAPbAAAAEwAAADs////D38MAAACAAAADzsAAAA6AAAAD4AMAAACAAAADycAAAAiAAAAD4EMAAACAAAAD1wAAAB8AAAAD4IMAAADAAAAD3oAAABaAAAA5v///w+DDAAAAwAAAA94AAAAWAAAAOf///8PhAwAAAMAAAAPYwAAAEMAAAD2////D4UMAAADAAAAD3YAAABWAAAA5f///w+GDAAAAwAAAA9iAAAAQgAAAOH///8PhwwAAAMAAAAPbgAAAE4AAADw////D4gMAAADAAAAD20AAABNAAAA7v///w+JDAAAAgAAAA8sAAAAPAAAAA+KDAAAAgAAAA8uAAAAPgAAAA+LDAAAAgAAAA8vAAAAPwAAAA+MDAAAAgAAAA88AAAAPgAAAA+NDAAAAAAAAA8PjgwAAAIAAAAPYAAAAH4AAAAPjwwAAAIAAAAPMQAAACEAAAAPkAwAAAIAAAAPMgAAAEAAAAAPkQwAAAIAAAAPMwAAACMAAAAPkgwAAAIAAAAPNAAAACQAAAAPkwwAAAIAAAAPNQAAACUAAAAPlAwAAAIAAAAPNgAAAF4AAAAPlQwAAAIAAAAPNwAAACYAAAAPlgwAAAIAAAAPOAAAACoAAAAPlwwAAAIAAAAPOQAAACgAAAAPmAwAAAIAAAAPMAAAACkAAAAPmQwAAAIAAAAPLQAAAF8AAAAPmgwAAAIAAAAPPQAAACsAAAAPmwwAAAMAAAAPcQAAAFEAAAD3////D5wMAAADAAAAD3cAAABXAAAA8f///w+dDAAAAgAAAA9lAAAARQAAAA+eDAAAAwAAAA9yAAAAUgAAAPj///8PnwwAAAMAAAAPdAAAAFQAAADo////D6AMAAADAAAAD3kAAABZAAAA4////w+hDAAAAgAAAA91AAAAVQAAAA+iDAAAAgAAAA9pAAAASQAAAA+jDAAAAgAAAA9vAAAATwAAAA+kDAAAAwAAAA9wAAAAUAAAAPT///8PpQwAAAIAAAAPWwAAAHsAAAAPpgwAAAIAAAAPXQAAAH0AAAAPpwwAAAMAAAAPYQAAAEEAAADg////D6gMAAADAAAAD3MAAABTAAAA5f///w+pDAAAAwAAAA9kAAAARAAAAOz///8PqgwAAAMAAAAPZgAAAEYAAAD6////D6sMAAADAAAAD2cAAABHAAAA4v///w+sDAAAAwAAAA9oAAAASAAAAOT///8PrQwAAAMAAAAPagAAAEoAAAD5////D64MAAADAAAAD2sAAABLAAAA6////w+vDAAAAwAAAA9sAAAATAAAAOn///8PsAwAAAIAAAAPOwAAADoAAAAPsQwAAAIAAAAPJwAAACIAAAAPsgwAAAIAAAAPXAAAAHwAAAAPswwAAAMAAAAPegAAAFoAAADm////D7QMAAADAAAAD3gAAABYAAAA5////w+1DAAAAwAAAA9jAAAAQwAAAPb///8PtgwAAAMAAAAPdgAAAFYAAADy////D7cMAAADAAAAD2IAAABCAAAA4f///w+4DAAAAwAAAA9uAAAATgAAAPD///8PuQwAAAMAAAAPbQAAAE0AAADu////D7oMAAACAAAADywAAAA8AAAAD7sMAAACAAAADy4AAAA+AAAAD7wMAAACAAAADy8AAAA/AAAAD70MAAACAAAADzwAAAA+AAAAD74MAAAAAAAADw+/DAAAAgAAAA8xAAAAIQAAAA/ADAAAAgAAAA8yAAAAQAAAAA/BDAAAAgAAAA8zAAAAIwAAAA/CDAAAAgAAAA80AAAAJAAAAA/DDAAAAgAAAA81AAAAJQAAAA/EDAAAAgAAAA82AAAAXgAAAA/FDAAAAgAAAA83AAAAJgAAAA/GDAAAAgAAAA84AAAAKgAAAA/HDAAAAgAAAA85AAAAKAAAAA/IDAAAAgAAAA8wAAAAKQAAAA/JDAAAAgAAAA8tAAAAXwAAAA/KDAAAAgAAAA89AAAAKwAAAA/LDAAAAgAAAA9bAAAAewAAAA/MDAAAAgAAAA9dAAAAfQAAAA/NDAAAAgAAAA87AAAAOgAAAA/ODAAAAgAAAA8nAAAAIgAAAA/PDAAAAgAAAA9gAAAAfgAAAA/QDAAAAgAAAA8sAAAAPAAAAA/RDAAAAgAAAA8uAAAAPgAAAA/SDAAAAgAAAA8vAAAAPwAAAA/TDAAAAgAAAA9cAAAAfAAAAA/UDAAAAgAAAA9hAAAAQQAAAA/VDAAAAgAAAA9iAAAAQgAAAA/WDAAAAgAAAA9jAAAAQwAAAA/XDAAAAgAAAA9kAAAARAAAAA/YDAAAAgAAAA9lAAAARQAAAA/ZDAAAAgAAAA9mAAAARgAAAA/aDAAAAgAAAA9nAAAARwAAAA/bDAAAAgAAAA9oAAAASAAAAA/cDAAAAgAAAA9pAAAASQAAAA/dDAAAAgAAAA9qAAAASgAAAA/eDAAAAgAAAA9rAAAASwAAAA/fDAAAAgAAAA9sAAAATAAAAA/gDAAAAgAAAA9tAAAATQAAAA/hDAAAAgAAAA9uAAAATgAAAA/iDAAAAgAAAA9vAAAATwAAAA/jDAAAAgAAAA9wAAAAUAAAAA/kDAAAAgAAAA9xAAAAUQAAAA/lDAAAAgAAAA9yAAAAUgAAAA/mDAAAAgAAAA9zAAAAUwAAAA/nDAAAAgAAAA90AAAAVAAAAA/oDAAAAgAAAA91AAAAVQAAAA/pDAAAAgAAAA92AAAAVgAAAA/qDAAAAgAAAA93AAAAVwAAAA/rDAAAAgAAAA94AAAAWAAAAA/sDAAAAgAAAA95AAAAWQAAAA/tDAAAAgAAAA96AAAAWgAAAA/uDAAAAAAAAA8P7wwAAAAAAAAPD/AMAAACAAAAD2AAAAB+AAAAD/EMAAACAAAADzEAAAAhAAAAD/IMAAACAAAADzIAAABAAAAAD/MMAAACAAAADzMAAAAjAAAAD/QMAAACAAAADzQAAAAkAAAAD/UMAAACAAAADzUAAAAlAAAAD/YMAAACAAAADzYAAABeAAAAD/cMAAACAAAADzcAAAAmAAAAD/gMAAACAAAADzgAAAAqAAAAD/kMAAACAAAADzkAAAAoAAAAD/oMAAACAAAADzAAAAApAAAAD/sMAAACAAAADy0AAABfAAAAD/wMAAACAAAADz0AAAArAAAAD/0MAAAEAAAAD3EAAABRAAAAOwAAADoAAAAP/gwAAAIAAAAPdwAAAFcAAAAP/wwAAAQAAAAPZQAAAEUAAADl////xf///w8ADQAABAAAAA9yAAAAUgAAAPH////R////DwENAAAEAAAAD3QAAABUAAAA9P///9T///8PAg0AAAQAAAAPeQAAAFkAAAD1////1f///w8DDQAABAAAAA91AAAAVQAAAOj////I////DwQNAAAEAAAAD2kAAABJAAAA6f///8n///8PBQ0AAAQAAAAPbwAAAE8AAADv////z////w8GDQAABAAAAA9wAAAAUAAAAPD////Q////DwcNAAACAAAAD1sAAAB7AAAADwgNAAACAAAAD10AAAB9AAAADwkNAAAEAAAAD2EAAABBAAAA4f///8H///8PCg0AAAIAAAAPcwAAAFMAAAAPCw0AAAQAAAAPZAAAAEQAAADk////xP///w8MDQAABAAAAA9mAAAARgAAAPb////W////Dw0NAAAEAAAAD2cAAABHAAAA4////8P///8PDg0AAAQAAAAPaAAAAEgAAADn////x////w8PDQAABAAAAA9qAAAASgAAAO7////O////DxANAAAEAAAAD2sAAABLAAAA6v///8r///8PEQ0AAAQAAAAPbAAAAEwAAADr////y////w8SDQAABAAAAA87AAAAOgAAALT///+o////DxMNAAACAAAADycAAAAiAAAADxQNAAACAAAAD1wAAAB8AAAADxUNAAAEAAAAD3oAAABaAAAA5v///8b///8PFg0AAAQAAAAPeAAAAFgAAAD3////1////w8XDQAABAAAAA9jAAAAQwAAAPj////Y////DxgNAAAEAAAAD3YAAABWAAAA+f///9n///8PGQ0AAAQAAAAPYgAAAEIAAADi////wv///w8aDQAABAAAAA9uAAAATgAAAO3////N////DxsNAAAEAAAAD20AAABNAAAA7P///8z///8PHA0AAAIAAAAPLAAAADwAAAAPHQ0AAAIAAAAPLgAAAD4AAAAPHg0AAAIAAAAPLwAAAD8AAAAPHw0AAAIAAAAPPAAAAD4AAAAPIA0AAAAAAAAPDyENAAAEAAAAD2AAAAB+AAAAXwAAACUAAAAPIg0AAAQAAAAPMQAAACEAAADl////KwAAAA8jDQAABAAAAA8yAAAAQAAAAC8AAADx////DyQNAAAEAAAADzMAAAAjAAAALQAAAPL///8PJQ0AAAQAAAAPNAAAACQAAADA////8////w8mDQAABAAAAA81AAAAJQAAALb////0////DycNAAAEAAAADzYAAABeAAAA2P///9n///8PKA0AAAQAAAAPNwAAACYAAADW////3////w8pDQAABAAAAA84AAAAKgAAAKT////1////DyoNAAAEAAAADzkAAAAoAAAAtf////b///8PKw0AAAQAAAAPMAAAACkAAACo////9////w8sDQAABAAAAA8tAAAAXwAAAKL////4////Dy0NAAAEAAAADz0AAAArAAAAqv////n///8PLg0AAAQAAAAPcQAAAFEAAADm////8P///w8vDQAABAAAAA93AAAAVwAAAOT///8iAAAADzANAAAEAAAAD2UAAABFAAAA0////67///8PMQ0AAAQAAAAPcgAAAFIAAAC+////sf///w8yDQAABAAAAA90AAAAVAAAAND///+4////DzMNAAAEAAAAD3kAAABZAAAA0f///+3///8PNA0AAAQAAAAPdQAAAFUAAADV////6v///w81DQAABAAAAA9pAAAASQAAAMP///+z////DzYNAAAEAAAAD28AAABPAAAAuf///8////8PNw0AAAQAAAAPcAAAAFAAAADC////rf///w84DQAABAAAAA9bAAAAewAAALr///+w////DzkNAAAEAAAAD10AAAB9AAAAxf///ywAAAAPOg0AAAQAAAAPYQAAAEEAAAC/////xP///w87DQAABAAAAA9zAAAAUwAAAMv///+m////DzwNAAAEAAAAD2QAAABEAAAAof///6////8PPQ0AAAQAAAAPZgAAAEYAAAC0////4v///w8+DQAABAAAAA9nAAAARwAAAOD///+s////Dz8NAAAEAAAAD2gAAABIAAAA6f///+f///8PQA0AAAQAAAAPagAAAEoAAADo////6////w9BDQAABAAAAA9rAAAASwAAANL////J////D0INAAAEAAAAD2wAAABMAAAAyv///8j///8PQw0AAAQAAAAPOwAAADoAAADH////q////w9EDQAABAAAAA8nAAAAIgAAAKf///8uAAAAD0UNAAAEAAAAD1wAAAB8AAAAo////6X///8PRg0AAAQAAAAPegAAAFoAAAC8////KAAAAA9HDQAABAAAAA94AAAAWAAAALv///8pAAAAD0gNAAAEAAAAD2MAAABDAAAA4f///6n///8PSQ0AAAQAAAAPdgAAAFYAAADN////zv///w9KDQAAAwAAAA9iAAAAQgAAANr///8PSw0AAAQAAAAPbgAAAE4AAADX////7P///w9MDQAABAAAAA9tAAAATQAAALf///8/AAAAD00NAAAEAAAADywAAAA8AAAAwf///7L///8PTg0AAAQAAAAPLgAAAD4AAADj////zP///w9PDQAABAAAAA8vAAAAPwAAAL3////G////D1ANAAAAAAAADw9RDQAAAAAAAA8PUg0AAAIAAAAPQAAAAKf///8PUw0AAAIAAAAPMQAAACEAAAAPVA0AAAIAAAAPMgAAACIAAAAPVQ0AAAIAAAAPMwAAACMAAAAPVg0AAAIAAAAPNAAAACQAAAAPVw0AAAIAAAAPNQAAACUAAAAPWA0AAAIAAAAPNgAAACYAAAAPWQ0AAAIAAAAPNwAAAF8AAAAPWg0AAAIAAAAPOAAAACgAAAAPWw0AAAIAAAAPOQAAACkAAAAPXA0AAAIAAAAPMAAAACcAAAAPXQ0AAAIAAAAPLwAAAD8AAAAPXg0AAAIAAAAPsP///34AAAAPXw0AAAIAAAAPcQAAAFEAAAAPYA0AAAIAAAAPdwAAAFcAAAAPYQ0AAAIAAAAPZQAAAEUAAAAPYg0AAAIAAAAPcgAAAFIAAAAPYw0AAAIAAAAPdAAAAFQAAAAPZA0AAAIAAAAPeQAAAFkAAAAPZQ0AAAIAAAAPdQAAAFUAAAAPZg0AAAIAAAAPaQAAAEkAAAAPZw0AAAIAAAAPbwAAAE8AAAAPaA0AAAIAAAAPcAAAAFAAAAAPaQ0AAAIAAAAPqP///34AAAAPag0AAAIAAAAPKgAAAHwAAAAPaw0AAAIAAAAPYQAAAEEAAAAPbA0AAAIAAAAPcwAAAFMAAAAPbQ0AAAIAAAAPZAAAAEQAAAAPbg0AAAIAAAAPZgAAAEYAAAAPbw0AAAIAAAAPZwAAAEcAAAAPcA0AAAIAAAAPaAAAAEgAAAAPcQ0AAAIAAAAPagAAAEoAAAAPcg0AAAIAAAAPawAAAEsAAAAPcw0AAAIAAAAPbAAAAEwAAAAPdA0AAAIAAAAPKwAAALH///8PdQ0AAAIAAAAPJwAAAGAAAAAPdg0AAAIAAAAPPAAAAD4AAAAPdw0AAAIAAAAPegAAAFoAAAAPeA0AAAIAAAAPeAAAAFgAAAAPeQ0AAAIAAAAPYwAAAEMAAAAPeg0AAAIAAAAPdgAAAFYAAAAPew0AAAIAAAAPYgAAAEIAAAAPfA0AAAIAAAAPbgAAAE4AAAAPfQ0AAAIAAAAPbQAAAE0AAAAPfg0AAAIAAAAPLAAAADsAAAAPfw0AAAIAAAAPLgAAADoAAAAPgA0AAAIAAAAPLQAAAD0AAAAPgQ0AAAIAAAAPWwAAAF0AAAAPgg0AAAAAAAAPCw== diff --git a/source/ShiftUI/Resources/scan_table.bin b/source/ShiftUI/Resources/scan_table.bin new file mode 100644 index 0000000..66faa57 --- /dev/null +++ b/source/ShiftUI/Resources/scan_table.bin @@ -0,0 +1,10 @@ +AAEAAAD/////AQAAAAAAAAAHAQAAAAEBAAAABQAAAAcHCQIAAAAJAwAAAAkEAAAACQUAAAAJBgAAAA8C + AAAAMAAAAAcpAAIAAwAEAAUABgAHAAgACQAKAAsADAANABAAEQASABMAFAAVABYAFwAYABkAGgAbAB4A + HwAgACEAIgAjACQAJQAmACcAKAArACwALQAuAC8AMAAxADIAMwA0ADUAVgAPAwAAADAAAAAHKQACAAMA + BAAFAAYABwAIAAkACgALABoAGwAoADMANAAZABUAIQAiAC4AEwAmADUADQAeABgAEgAWABcAIAAjABQA + MQAfAAwAKwAnABAAJAAlAC0AMAAyABEALwAsAFYADwQAAAAyAAAABykAAgADAAQABQAGAAcACAAJAAoA + CwAMAA0AEAARABIAEwAUABUAFgAXABgAGQAaABsAHgAfACAAIQAiACMAJAAlACYAJwAoACsAXgAsAC0A + LgAvADAAMQAyADMANAA1AFYANQAPBQAAADAAAAAHAgADAAQABQAGAAcACAAJAAoACwAMAA0AKQAQABEA + EgATABQAFQAWABcAGAAZABoAGwAeAB8AIAAhACIAIwAkACUAJgAnACgAKwAsAC0ALgAvADAAMQAyADMA + NAA1AFYADwYAAAAwAAAABwIAAwAEAAUABgAHAAgACQAKAAsADAANABoAGwAnACgAKQAzADQANQArAB4A + MAAuACAAEgAhACIAIwAXACQAJQAmADIAMQAYABkAEAATAB8AFAAWAC8AEQAtABUALABWAAs= \ No newline at end of file diff --git a/source/ShiftUI/Resources/vkey_table.txt b/source/ShiftUI/Resources/vkey_table.txt new file mode 100644 index 0000000..7eb61ed --- /dev/null +++ b/source/ShiftUI/Resources/vkey_table.txt @@ -0,0 +1,33 @@ +AAEAAAD/////AQAAAAAAAAAHAQAAAAEBAAAACQAAAAcICQIAAAAJAwAAAAkEAAAACQUAAAAJBgAAAAkH + AAAACQgAAAAJCQAAAAkKAAAADwIAAAAwAAAACMAAAAAxAAAAMgAAADMAAAA0AAAANQAAADYAAAA3AAAA + OAAAADkAAAAwAAAAvQAAALsAAABRAAAAVwAAAEUAAABSAAAAVAAAAFkAAABVAAAASQAAAE8AAABQAAAA + 2wAAAN0AAABBAAAAUwAAAEQAAABGAAAARwAAAEgAAABKAAAASwAAAEwAAAC6AAAA3gAAANwAAABaAAAA + WAAAAEMAAABWAAAAQgAAAE4AAABNAAAAvAAAAL4AAAC/AAAA4gAAAA8DAAAAMAAAAAjAAAAAMQAAADIA + AAAzAAAANAAAADUAAAA2AAAANwAAADgAAAA5AAAAMAAAAL0AAAC7AAAAUQAAAFcAAABFAAAAUgAAAFQA + AABaAAAAVQAAAEkAAABPAAAAUAAAANsAAADdAAAAQQAAAFMAAABEAAAARgAAAEcAAABIAAAASgAAAEsA + AABMAAAAugAAAN4AAADcAAAAWQAAAFgAAABDAAAAVgAAAEIAAABOAAAATQAAALwAAAC+AAAAvwAAAOIA + AAAPBAAAADAAAAAIwAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADAAAADbAAAA + 3QAAAN4AAAC8AAAAvgAAAFAAAABZAAAARgAAAEcAAABDAAAAUgAAAEwAAAC/AAAAuwAAAEEAAABPAAAA + RQAAAFUAAABJAAAARAAAAEgAAABUAAAATgAAAFMAAAC9AAAA3AAAALoAAABRAAAASgAAAEsAAABYAAAA + QgAAAE0AAABXAAAAVgAAAFoAAADiAAAADwUAAAAwAAAACN4AAAAxAAAAMgAAADMAAAA0AAAANQAAADYA + AAA3AAAAOAAAADkAAAAwAAAA2wAAALsAAABBAAAAWgAAAEUAAABSAAAAVAAAAFkAAABVAAAASQAAAE8A + AABQAAAA3QAAALoAAABRAAAAUwAAAEQAAABGAAAARwAAAEgAAABKAAAASwAAAEwAAABNAAAAwAAAANwA + AABXAAAAWAAAAEMAAABWAAAAQgAAAE4AAAC8AAAAvgAAAL8AAADfAAAA4gAAAA8GAAAAMAAAAAjeAAAA + MQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAAAA5AAAAMAAAANsAAAC7AAAAQQAAAFoAAABFAAAA + UgAAAFQAAABZAAAAVQAAAEkAAABPAAAAUAAAAN0AAAC6AAAAUQAAAFMAAABEAAAARgAAAEcAAABIAAAA + SgAAAEsAAABMAAAATQAAAMAAAADcAAAAVwAAAFgAAABDAAAAVgAAAEIAAABOAAAAvAAAAL4AAAC/AAAA + 3wAAAOIAAAAPBwAAADAAAAAI3gAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADAA + AADbAAAAuwAAAEEAAABaAAAARQAAAFIAAABUAAAAWQAAAFUAAABJAAAATwAAAFAAAADdAAAAugAAAFEA + AABTAAAARAAAAEYAAABHAAAASAAAAEoAAABLAAAATAAAAE0AAADAAAAA3AAAAFcAAABYAAAAQwAAAFYA + AABCAAAATgAAALwAAAC+AAAAvwAAAN8AAADiAAAADwgAAAAxAAAACN4AAAAxAAAAMgAAADMAAAA0AAAA + NQAAADYAAAA3AAAAOAAAADkAAAAwAAAAvQAAALsAAABRAAAAVwAAAEUAAABSAAAAVAAAAFkAAABVAAAA + SQAAAE8AAABQAAAAwAAAANsAAABBAAAAUwAAAEQAAABGAAAARwAAAEgAAABKAAAASwAAAEwAAADfAAAA + 4gAAAN0AAABaAAAAWAAAAEMAAABWAAAAQgAAAE4AAABNAAAAvAAAAL4AAAC6AAAAvwAAANwAAAAPCQAA + ADUAAAAI3gAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADAAAADbAAAAuwAAAEEA + AABaAAAARQAAAFIAAABUAAAAWQAAAFUAAABJAAAATwAAAFAAAADdAAAAugAAAFEAAABTAAAARAAAAEYA + AABHAAAASAAAAEoAAABLAAAATAAAAE0AAADAAAAA3AAAAFcAAABYAAAAQwAAAFYAAABCAAAATgAAALwA + AAC+AAAAvwAAAN8AAADwAAAA4gAAAPIAAADzAAAA9AAAAPUAAAAPCgAAADAAAAAIMQAAADIAAAAzAAAA + NAAAADUAAAA2AAAANwAAADgAAAA5AAAAMAAAAL0AAAC7AAAA2wAAAN0AAAC6AAAA3gAAAMAAAAC8AAAA + vgAAAL8AAADcAAAAQQAAAEIAAABDAAAARAAAAEUAAABGAAAARwAAAEgAAABJAAAASgAAAEsAAABMAAAA + TQAAAE4AAABPAAAAUAAAAFEAAABSAAAAUwAAAFQAAABVAAAAVgAAAFcAAABYAAAAWQAAAFoAAADiAAAA + Cw== \ No newline at end of file diff --git a/source/ShiftUI/ScrollableControl.cs b/source/ShiftUI/ScrollableControl.cs new file mode 100644 index 0000000..811ce20 --- /dev/null +++ b/source/ShiftUI/ScrollableControl.cs @@ -0,0 +1,1024 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace ShiftUI { + //[Designer ("ShiftUI.Design.ScrollableWidgetDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + public class ScrollableWidget : Widget { + #region Local Variables + private bool force_hscroll_visible; + private bool force_vscroll_visible; + private bool auto_scroll; + private Size auto_scroll_margin; + private Size auto_scroll_min_size; + private Point scroll_position; + private DockPaddingEdges dock_padding; + private SizeGrip sizegrip; + internal ImplicitHScrollBar hscrollbar; + internal ImplicitVScrollBar vscrollbar; + internal Size canvas_size; + private Rectangle display_rectangle; + private Widget old_parent; + private HScrollProperties horizontalScroll; + private VScrollProperties verticalScroll; + private bool autosized_child; + #endregion // Local Variables + + [TypeConverter(typeof(ScrollableWidget.DockPaddingEdgesConverter))] + #region Subclass DockPaddingEdges + public class DockPaddingEdges : ICloneable + { + private Widget owner; + + internal DockPaddingEdges (Widget owner) + { + this.owner = owner; + } + + #region DockPaddingEdges Public Instance Properties + [RefreshProperties (RefreshProperties.All)] + public int All { + get { return owner.Padding.All; } + set { owner.Padding = new Padding (value); } + } + + [RefreshProperties (RefreshProperties.All)] + public int Bottom { + get { return owner.Padding.Bottom; } + set { owner.Padding = new Padding (Left, Top, Right, value); } + } + + [RefreshProperties (RefreshProperties.All)] + public int Left { + get { return owner.Padding.Left; } + set { owner.Padding = new Padding (value, Top, Right, Bottom); } + } + + [RefreshProperties (RefreshProperties.All)] + public int Right { + get { return owner.Padding.Right; } + set { owner.Padding = new Padding (Left, Top, value, Bottom); } + } + + [RefreshProperties (RefreshProperties.All)] + public int Top { + get { return owner.Padding.Top; } + set { owner.Padding = new Padding (Left, value, Right, Bottom); } + } + #endregion // DockPaddingEdges Public Instance Properties + + // Public Instance Methods + public override bool Equals (object other) + { + if (!(other is DockPaddingEdges)) { + return false; + } + + if ((this.All == ((DockPaddingEdges)other).All) && (this.Left == ((DockPaddingEdges)other).Left) && + (this.Right == ((DockPaddingEdges)other).Right) && (this.Top == ((DockPaddingEdges)other).Top) && + (this.Bottom == ((DockPaddingEdges)other).Bottom)) { + return true; + } + + return false; + } + + public override int GetHashCode () + { + return All * Top * Bottom * Right * Left; + } + + public override string ToString () + { + return "All = " + All.ToString () + " Top = " + Top.ToString () + " Left = " + Left.ToString () + " Bottom = " + Bottom.ToString () + " Right = " + Right.ToString (); + } + + internal void Scale (float dx, float dy) + { + Left = (int)(Left * dx); + Right = (int)(Right * dx); + Top = (int)(Top * dy); + Bottom = (int)(Bottom * dy); + } + + object ICloneable.Clone () + { + return new DockPaddingEdges (owner); + } + } + #endregion // Subclass DockPaddingEdges + + #region Subclass DockPaddingEdgesConverter + public class DockPaddingEdgesConverter : System.ComponentModel.TypeConverter { + // Public Constructors + public DockPaddingEdgesConverter() { + } + + // Public Instance Methods + public override PropertyDescriptorCollection GetProperties(System.ComponentModel.ITypeDescriptorContext context, object value, Attribute[] attributes) { + return TypeDescriptor.GetProperties(typeof(DockPaddingEdges), attributes); + } + + public override bool GetPropertiesSupported(System.ComponentModel.ITypeDescriptorContext context) { + return true; + } + } + #endregion // Subclass DockPaddingEdgesConverter + + #region Public Constructors + public ScrollableWidget() { + SetStyle(Widgetstyles.ContainerWidget, true); + SetStyle(Widgetstyles.AllPaintingInWmPaint, false); + + auto_scroll = false; + force_hscroll_visible = false; + force_vscroll_visible = false; + auto_scroll_margin = new Size(0, 0); + auto_scroll_min_size = new Size(0, 0); + scroll_position = new Point(0, 0); + SizeChanged +=new EventHandler(Recalculate); + VisibleChanged += new EventHandler (VisibleChangedHandler); + LocationChanged += new EventHandler (LocationChangedHandler); + ParentChanged += new EventHandler (ParentChangedHandler); + HandleCreated += new EventHandler (AddScrollbars); + + CreateScrollbars (); + + horizontalScroll = new HScrollProperties (this); + verticalScroll = new VScrollProperties (this); + } + + void VisibleChangedHandler (object sender, EventArgs e) + { + Recalculate (false); + } + + void LocationChangedHandler (object sender, EventArgs e) + { + UpdateSizeGripVisible (); + } + + void ParentChangedHandler (object sender, EventArgs e) + { + + if (old_parent == Parent) + return; + + if (old_parent != null) { + old_parent.SizeChanged -= new EventHandler (Parent_SizeChanged); + old_parent.PaddingChanged -= new EventHandler (Parent_PaddingChanged); + } + + if (Parent != null) { + Parent.SizeChanged += new EventHandler (Parent_SizeChanged); + Parent.PaddingChanged += new EventHandler (Parent_PaddingChanged); + } + + old_parent = Parent; + } + + void Parent_PaddingChanged (object sender, EventArgs e) + { + UpdateSizeGripVisible (); + } + + void Parent_SizeChanged (object sender, EventArgs e) + { + UpdateSizeGripVisible (); + } + #endregion // Public Constructors + + #region Protected Static Fields + protected const int ScrollStateAutoScrolling = 1; + protected const int ScrollStateFullDrag = 16; + protected const int ScrollStateHScrollVisible = 2; + protected const int ScrollStateUserHasScrolled = 8; + protected const int ScrollStateVScrollVisible = 4; + #endregion // Protected Static Fields + + #region Public Instance Properties + [DefaultValue(false)] + [Localizable(true)] + [MWFCategory("Layout")] + public virtual bool AutoScroll { + get { + return auto_scroll; + } + + set { + if (auto_scroll != value) { + auto_scroll = value; + PerformLayout (this, "AutoScroll"); + } + } + } + + [Localizable(true)] + [MWFCategory("Layout")] + public Size AutoScrollMargin { + get { + return auto_scroll_margin; + } + + set { + if (value.Width < 0) { + throw new ArgumentException("Width is assigned less than 0", "value.Width"); + } + + if (value.Height < 0) { + throw new ArgumentException("Height is assigned less than 0", "value.Height"); + } + + auto_scroll_margin = value; + } + } + + internal bool ShouldSerializeAutoScrollMargin () + { + return this.AutoScrollMargin != new Size (0, 0); + } + + [Localizable(true)] + [MWFCategory("Layout")] + public Size AutoScrollMinSize { + get { + return auto_scroll_min_size; + } + + set { + if (value != auto_scroll_min_size) { + auto_scroll_min_size = value; + AutoScroll = true; + PerformLayout (this, "AutoScrollMinSize"); + } + } + } + + internal bool ShouldSerializeAutoScrollMinSize () + { + return this.AutoScrollMinSize != new Size (0, 0); + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Point AutoScrollPosition { + get { + return DisplayRectangle.Location; + } + + set { + if (value != AutoScrollPosition) { + int shift_x; + int shift_y; + + shift_x = 0; + shift_y = 0; + if (hscrollbar.VisibleInternal) { + int max = hscrollbar.Maximum - hscrollbar.LargeChange + 1; + value.X = value.X < hscrollbar.Minimum ? hscrollbar.Minimum : value.X; + value.X = value.X > max ? max : value.X; + shift_x = value.X - scroll_position.X; + } + + if (vscrollbar.VisibleInternal) { + int max = vscrollbar.Maximum - vscrollbar.LargeChange + 1; + value.Y = value.Y < vscrollbar.Minimum ? vscrollbar.Minimum : value.Y; + value.Y = value.Y > max ? max : value.Y; + shift_y = value.Y - scroll_position.Y; + } + + ScrollWindow(shift_x, shift_y); + + if (hscrollbar.VisibleInternal) { + if (scroll_position.X >= hscrollbar.Minimum && scroll_position.X <= hscrollbar.Maximum) + hscrollbar.Value = scroll_position.X; + } + + if (vscrollbar.VisibleInternal) { + if (scroll_position.Y >= vscrollbar.Minimum && scroll_position.Y <= vscrollbar.Maximum) + vscrollbar.Value = scroll_position.Y; + } + + } + } + } + + public override Rectangle DisplayRectangle { + get { + if (auto_scroll) { + int width; + int height; + + if (canvas_size.Width <= base.DisplayRectangle.Width) { + width = base.DisplayRectangle.Width; + if (vscrollbar.VisibleInternal) { + width -= vscrollbar.Width; + } + } else { + width = canvas_size.Width; + } + + if (canvas_size.Height <= base.DisplayRectangle.Height) { + height = base.DisplayRectangle.Height; + if (hscrollbar.VisibleInternal) { + height -= hscrollbar.Height; + } + } else { + height = canvas_size.Height; + } + + display_rectangle.X = -scroll_position.X; + display_rectangle.Y = -scroll_position.Y; + display_rectangle.Width = Math.Max(auto_scroll_min_size.Width, width); + display_rectangle.Height = Math.Max(auto_scroll_min_size.Height, height); + } + else { + display_rectangle = base.DisplayRectangle; + } + + // DockPadding is the same as Padding (according to documentation) but is + // calculated lazily, so we use Padding here instead. + if (Padding != Padding.Empty) { + display_rectangle.X += Padding.Left; + display_rectangle.Y += Padding.Top; + display_rectangle.Width -= Padding.Horizontal; + display_rectangle.Height -= Padding.Vertical; + } + + return display_rectangle; + } + } + + [MWFCategory("Layout")] + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public DockPaddingEdges DockPadding { + get { + if (dock_padding == null) + CreateDockPadding (); + + return dock_padding; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public HScrollProperties HorizontalScroll { + get { return horizontalScroll; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public VScrollProperties VerticalScroll { + get { return verticalScroll; } + } + #endregion // Public Instance Properties + + #region Protected Instance Methods + protected override CreateParams CreateParams { + get { + return base.CreateParams; + } + } + + protected bool HScroll { + get { + return hscrollbar.VisibleInternal; + } + + set { + if (!AutoScroll && hscrollbar.VisibleInternal != value) { + force_hscroll_visible = value; + Recalculate (false); + } + } + } + + protected bool VScroll { + get { + return vscrollbar.VisibleInternal; + } + + set { + if (!AutoScroll && vscrollbar.VisibleInternal != value) { + force_vscroll_visible = value; + Recalculate (false); + } + } + } + #endregion // Protected Instance Methods + + #region Public Instance Methods + public void ScrollWidgetIntoView(Widget activeWidget) { + int corner_x; + int corner_y; + + Rectangle within = new Rectangle (); + within.Size = ClientSize; + + if (!AutoScroll || (!hscrollbar.VisibleInternal && !vscrollbar.VisibleInternal)) { + return; + } + + if (!Contains(activeWidget)) { + return; + } + + if (vscrollbar.Visible) { + within.Width -= vscrollbar.Width; + } + if (hscrollbar.Visible) { + within.Height -= hscrollbar.Height; + } + + // Don't scroll if already visible + if (within.Contains (activeWidget.Location) && within.Contains (activeWidget.Right, activeWidget.Bottom)) { + return; + } + + // If the Widget is above the top or the left, move it down and right until it aligns + // with the top/left. + // If the Widget is below the bottom or to the right, move it up/left until it aligns + // with the bottom/right, but do never move it further than the top/left side. + int x_diff = 0, y_diff = 0; + if (activeWidget.Top <= 0 || activeWidget.Height >= within.Height) { + y_diff = -activeWidget.Top; + } else if (activeWidget.Bottom > within.Height) { + y_diff = within.Height - activeWidget.Bottom; + } + if (activeWidget.Left <= 0 || activeWidget.Width >= within.Width) { + x_diff = -activeWidget.Left; + } else if (activeWidget.Right > within.Width) { + x_diff = within.Width - activeWidget.Right; + } + corner_x = hscrollbar.Value - x_diff; + corner_y = vscrollbar.Value - y_diff; + + if (hscrollbar.VisibleInternal) { + if (corner_x > hscrollbar.Maximum) { + corner_x = hscrollbar.Maximum; + } else if (corner_x < hscrollbar.Minimum) { + corner_x = hscrollbar.Minimum; + } + if (corner_x != hscrollbar.Value) { + hscrollbar.Value = corner_x; + } + } + + if (vscrollbar.VisibleInternal) { + if (corner_y > vscrollbar.Maximum) { + corner_y = vscrollbar.Maximum; + } else if (corner_y < vscrollbar.Minimum) { + corner_y = vscrollbar.Minimum; + } + if (corner_y != vscrollbar.Value) { + vscrollbar.Value = corner_y; + } + } + } + + public void SetAutoScrollMargin(int x, int y) { + if (x < 0) { + x = 0; + } + + if (y < 0) { + y = 0; + } + + auto_scroll_margin = new Size(x, y); + Recalculate (false); + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void AdjustFormScrollbars(bool displayScrollbars) { + Recalculate (false); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected bool GetScrollState(int bit) { + // Internal MS + return false; + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void OnLayout(LayoutEventArgs levent) { + CalculateCanvasSize (true); + + AdjustFormScrollbars(AutoScroll); // Dunno what the logic is. Passing AutoScroll seems to match MS behaviour + base.OnLayout(levent); + + // The first time through, we just set the canvas to clientsize + // so we could re-layout everything according to the flow. + // This time we want to actually calculate the canvas. + // If a child is autosized, we need to rethink scrollbars as well. (Xamarin bug 18874) + if (this is FlowLayoutPanel || autosized_child) { + CalculateCanvasSize (false); + AdjustFormScrollbars (AutoScroll); + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void OnMouseWheel(MouseEventArgs e) { + if (vscrollbar.VisibleInternal) { + if (e.Delta > 0) { + if (vscrollbar.Minimum < (vscrollbar.Value - vscrollbar.LargeChange)) { + vscrollbar.Value -= vscrollbar.LargeChange; + } else { + vscrollbar.Value = vscrollbar.Minimum; + } + } else { + int maximum_scrollbar_value = vscrollbar.Maximum - vscrollbar.LargeChange + 1; + if (maximum_scrollbar_value > (vscrollbar.Value + vscrollbar.LargeChange)) { + vscrollbar.Value += vscrollbar.LargeChange; + } else { + vscrollbar.Value = maximum_scrollbar_value; + } + } + } + base.OnMouseWheel(e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void OnVisibleChanged(EventArgs e) { + if (Visible) { + UpdateChildrenZOrder (); + PerformLayout(this, "Visible"); + } + base.OnVisibleChanged(e); + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + protected override void ScaleCore(float dx, float dy) { + if (dock_padding != null) + dock_padding.Scale(dx, dy); + + base.ScaleCore(dx, dy); + } + + protected override void ScaleWidget (SizeF factor, BoundsSpecified specified) + { + base.ScaleWidget (factor, specified); + } + + protected virtual Point ScrollToWidget (Widget activeWidget) + { + int corner_x; + int corner_y; + + Rectangle within = new Rectangle (); + within.Size = ClientSize; + + if (vscrollbar.Visible) + within.Width -= vscrollbar.Width; + + if (hscrollbar.Visible) + within.Height -= hscrollbar.Height; + + // If the Widget is above the top or the left, move it down and right until it aligns + // with the top/left. + // If the Widget is below the bottom or to the right, move it up/left until it aligns + // with the bottom/right, but do never move it further than the top/left side. + int x_diff = 0, y_diff = 0; + + if (activeWidget.Top <= 0 || activeWidget.Height >= within.Height) + y_diff = -activeWidget.Top; + else if (activeWidget.Bottom > within.Height) + y_diff = within.Height - activeWidget.Bottom; + + if (activeWidget.Left <= 0 || activeWidget.Width >= within.Width) + x_diff = -activeWidget.Left; + else if (activeWidget.Right > within.Width) + x_diff = within.Width - activeWidget.Right; + + corner_x = AutoScrollPosition.X + x_diff; + corner_y = AutoScrollPosition.Y + y_diff; + + return new Point (corner_x, corner_y); + } + + protected void SetDisplayRectLocation(int x, int y) { + // This method is weird. MS documents that the scrollbars are not + // updated. We need to move stuff, but leave the scrollbars as is + + if (x > 0) { + x = 0; + } + + if (y > 0) { + y = 0; + } + + ScrollWindow(scroll_position.X - x , scroll_position.Y - y); + } + + protected void SetScrollState(int bit, bool value) { + //throw new NotImplementedException(); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void WndProc(ref Message m) { + base.WndProc(ref m); + } + #endregion // Protected Instance Methods + + #region Internal & Private Methods + internal override IntPtr AfterTopMostWidget () + { + // order of scrollbars: + // top = vertical + // sizegrid + // bottom = horizontal + if (hscrollbar != null && hscrollbar.Visible) + return hscrollbar.Handle; + // no need to check for sizegrip since it will only + // be visible if hbar is visible. + if (vscrollbar != null && vscrollbar.Visible) + return hscrollbar.Handle; + + return base.AfterTopMostWidget (); + } + + internal virtual void CalculateCanvasSize (bool canOverride) { + Widget child; + int num_of_children; + int width; + int height; + int extra_width; + int extra_height; + + num_of_children = Widgets.Count; + width = 0; + height = 0; + extra_width = hscrollbar.Value; + extra_height = vscrollbar.Value; + if (dock_padding != null) { + extra_width += dock_padding.Right; + extra_height += dock_padding.Bottom; + } + + autosized_child = false; + for (int i = 0; i < num_of_children; i++) { + child = Widgets[i]; + if (child.AutoSize) + autosized_child = true; + if (child.Dock == DockStyle.Right) { + extra_width += child.Width; + } else if (child.Dock == DockStyle.Bottom) { + extra_height += child.Height; + } + } + + if (!auto_scroll_min_size.IsEmpty) { + width = auto_scroll_min_size.Width; + height = auto_scroll_min_size.Height; + } + + for (int i = 0; i < num_of_children; i++) { + child = Widgets[i]; + + switch(child.Dock) { + case DockStyle.Left: { + if ((child.Right + extra_width) > width) { + width = child.Right + extra_width; + } + continue; + } + + case DockStyle.Top: { + if ((child.Bottom + extra_height) > height) { + height = child.Bottom + extra_height; + } + continue; + } + + case DockStyle.Fill: + case DockStyle.Right: + case DockStyle.Bottom: { + continue; + } + + default: { + AnchorStyles anchor; + + anchor = child.Anchor; + + if (((anchor & AnchorStyles.Left) != 0) && ((anchor & AnchorStyles.Right) == 0)) { + if ((child.Right + extra_width) > width) { + width = child.Right + extra_width; + } + } + + if (((anchor & AnchorStyles.Top) != 0) || ((anchor & AnchorStyles.Bottom) == 0)) { + if ((child.Bottom + extra_height) > height) { + height = child.Bottom + extra_height; + } + } + continue; + } + } + } + + canvas_size.Width = width; + canvas_size.Height = height; + } + + // Normally DockPadding is created lazyly, as observed in the test cases, but some children + // may need to have it always. + internal void CreateDockPadding () + { + if (dock_padding == null) + dock_padding = new DockPaddingEdges (this); + } + + private void Recalculate (object sender, EventArgs e) { + Recalculate (true); + } + + private void Recalculate (bool doLayout) { + if (!IsHandleCreated) { + return; + } + + Size canvas = canvas_size; + Size client = ClientSize; + + canvas.Width += auto_scroll_margin.Width; + canvas.Height += auto_scroll_margin.Height; + + int right_edge = client.Width; + int bottom_edge = client.Height; + int prev_right_edge; + int prev_bottom_edge; + + bool hscroll_visible; + bool vscroll_visible; + + do { + prev_right_edge = right_edge; + prev_bottom_edge = bottom_edge; + + if ((force_hscroll_visible || (canvas.Width > right_edge && auto_scroll)) && client.Width > 0) { + hscroll_visible = true; + bottom_edge = client.Height - SystemInformation.HorizontalScrollBarHeight; + } else { + hscroll_visible = false; + bottom_edge = client.Height; + } + + if ((force_vscroll_visible || (canvas.Height > bottom_edge && auto_scroll)) && client.Height > 0) { + vscroll_visible = true; + right_edge = client.Width - SystemInformation.VerticalScrollBarWidth; + } else { + vscroll_visible = false; + right_edge = client.Width; + } + + } while (right_edge != prev_right_edge || bottom_edge != prev_bottom_edge); + + if (right_edge < 0) right_edge = 0; + if (bottom_edge < 0) bottom_edge = 0; + + Rectangle hscroll_bounds; + Rectangle vscroll_bounds; + + hscroll_bounds = new Rectangle (0, client.Height - SystemInformation.HorizontalScrollBarHeight, + ClientRectangle.Width, SystemInformation.HorizontalScrollBarHeight); + vscroll_bounds = new Rectangle (client.Width - SystemInformation.VerticalScrollBarWidth, 0, + SystemInformation.VerticalScrollBarWidth, ClientRectangle.Height); + + /* the ScrollWindow calls here are needed + * because (this explanation sucks): + * + * when we transition from having a scrollbar to + * not having one, we won't receive a scrollbar + * moved (value changed) event, so we need to + * manually scroll the canvas. + * + * if you can fix this without requiring the + * ScrollWindow calls, pdb and toshok will each + * pay you $5. + */ + + if (!vscrollbar.Visible) { + vscrollbar.Value = 0; + } + if (!hscrollbar.Visible) { + hscrollbar.Value = 0; + } + + /* Manually setting the size of the thumb should be done before + * the other assignments */ + if (hscroll_visible) { + hscrollbar.manual_thumb_size = right_edge; + hscrollbar.LargeChange = right_edge; + hscrollbar.SmallChange = 5; + hscrollbar.Maximum = canvas.Width - 1; + } else { + if (hscrollbar != null && hscrollbar.VisibleInternal) { + ScrollWindow (- scroll_position.X, 0); + } + scroll_position.X = 0; + } + + if (vscroll_visible) { + vscrollbar.manual_thumb_size = bottom_edge; + vscrollbar.LargeChange = bottom_edge; + vscrollbar.SmallChange = 5; + vscrollbar.Maximum = canvas.Height - 1; + } else { + if (vscrollbar != null && vscrollbar.VisibleInternal) { + ScrollWindow (0, - scroll_position.Y); + } + scroll_position.Y = 0; + } + + if (hscroll_visible && vscroll_visible) { + hscroll_bounds.Width -= SystemInformation.VerticalScrollBarWidth; + vscroll_bounds.Height -= SystemInformation.HorizontalScrollBarHeight; + + sizegrip.Bounds = new Rectangle (hscroll_bounds.Right, + vscroll_bounds.Bottom, + SystemInformation.VerticalScrollBarWidth, + SystemInformation.HorizontalScrollBarHeight); + } + + SuspendLayout (); + + hscrollbar.SetBoundsInternal (hscroll_bounds.X, hscroll_bounds.Y, hscroll_bounds.Width, hscroll_bounds.Height, BoundsSpecified.None); + hscrollbar.Visible = hscroll_visible; + if (hscrollbar.Visible) + XplatUI.SetZOrder (hscrollbar.Handle, IntPtr.Zero, true, false); + + vscrollbar.SetBoundsInternal (vscroll_bounds.X, vscroll_bounds.Y, vscroll_bounds.Width, vscroll_bounds.Height, BoundsSpecified.None); + vscrollbar.Visible = vscroll_visible; + if (vscrollbar.Visible) + XplatUI.SetZOrder (vscrollbar.Handle, IntPtr.Zero, true, false); + + UpdateSizeGripVisible (); + + ResumeLayout (doLayout); + + // We should now scroll the active Widget into view, + // the funny part is that ScrollableWidget does not have + // the concept of active Widget. + ContainerWidget container = this as ContainerWidget; + if (container != null && container.ActiveWidget != null) { + ScrollWidgetIntoView (container.ActiveWidget); + } + } + + internal void UpdateSizeGripVisible () + { + if (!IsHandleCreated) { + return; + } + + sizegrip.CapturedWidget = Parent; + // This is really wierd, the size grip is only showing up + // if the bottom right corner of the scrollable Widget is within + // two pixels from the bottom right corner of its parent. + bool show_sizegrip = hscrollbar.VisibleInternal && vscrollbar.VisibleInternal; + bool enable_sizegrip = false; + if (show_sizegrip && Parent != null) { + Point diff = new Point (Parent.ClientRectangle.Bottom - Bottom, Parent.ClientRectangle.Right - Right); + enable_sizegrip = diff.X <= 2 && diff.X >= 0 && diff.Y <= 2 && diff.Y >= 0; + } + sizegrip.Visible = show_sizegrip; + sizegrip.Enabled = enable_sizegrip || sizegrip.Capture; + if (sizegrip.Visible) + XplatUI.SetZOrder (sizegrip.Handle, vscrollbar.Handle, false, false); + } + + private void HandleScrollBar(object sender, EventArgs e) { + if (sender == vscrollbar) { + if (!vscrollbar.Visible) + return; + ScrollWindow(0, vscrollbar.Value- scroll_position.Y); + } else { + if (!hscrollbar.Visible) + return; + ScrollWindow(hscrollbar.Value - scroll_position.X, 0); + } + } + + private void HandleScrollEvent (object sender, ScrollEventArgs args) + { + OnScroll (args); + } + + private void AddScrollbars (object o, EventArgs e) + { + Widgets.AddRangeImplicit (new Widget[] {hscrollbar, vscrollbar, sizegrip}); + HandleCreated -= new EventHandler (AddScrollbars); + } + + private void CreateScrollbars () + { + hscrollbar = new ImplicitHScrollBar (); + hscrollbar.Visible = false; + hscrollbar.ValueChanged += new EventHandler (HandleScrollBar); + hscrollbar.Height = SystemInformation.HorizontalScrollBarHeight; + hscrollbar.use_manual_thumb_size = true; + hscrollbar.Scroll += new ScrollEventHandler (HandleScrollEvent); + + vscrollbar = new ImplicitVScrollBar (); + vscrollbar.Visible = false; + vscrollbar.ValueChanged += new EventHandler (HandleScrollBar); + vscrollbar.Width = SystemInformation.VerticalScrollBarWidth; + vscrollbar.use_manual_thumb_size = true; + vscrollbar.Scroll += new ScrollEventHandler (HandleScrollEvent); + + sizegrip = new SizeGrip (this); + sizegrip.Visible = false; + } + + private void ScrollWindow(int XOffset, int YOffset) { + int num_of_children; + + if (XOffset == 0 && YOffset == 0) { + return; + } + + SuspendLayout(); + + num_of_children = Widgets.Count; + + for (int i = 0; i < num_of_children; i++) { + Widgets[i].Location = new Point (Widgets[i].Left - XOffset, Widgets[i].Top - YOffset); + //Widgets[i].Left -= XOffset; + //Widgets[i].Top -= YOffset; + // Is this faster? Widgets[i].Location -= new Size(XOffset, YOffset); + } + + scroll_position.X += XOffset; + scroll_position.Y += YOffset; + + XplatUI.ScrollWindow (Handle, ClientRectangle, -XOffset, -YOffset, false); + ResumeLayout(false); + } + #endregion // Internal & Private Methods + + static object OnScrollEvent = new object (); + + protected virtual void OnScroll (ScrollEventArgs se) + { + ScrollEventHandler eh = (ScrollEventHandler) (Events [OnScrollEvent]); + if (eh != null) + eh (this, se); + } + + protected override void OnPaddingChanged (EventArgs e) + { + base.OnPaddingChanged (e); + } + + protected override void OnPaintBackground (PaintEventArgs e) + { + base.OnPaintBackground (e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void OnRightToLeftChanged (EventArgs e) + { + base.OnRightToLeftChanged (e); + } + + public event ScrollEventHandler Scroll { + add { Events.AddHandler (OnScrollEvent, value); } + remove { Events.RemoveHandler (OnScrollEvent, value); } + } + } +} diff --git a/source/ShiftUI/ShiftUI.csproj b/source/ShiftUI/ShiftUI.csproj new file mode 100644 index 0000000..9161113 --- /dev/null +++ b/source/ShiftUI/ShiftUI.csproj @@ -0,0 +1,978 @@ + + + + Debug + AnyCPU + {C56E34D0-4749-4A73-9469-BCCD063569CD} + Library + ShiftUI + ShiftUI + v4.5.2 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + true + + + full + true + bin\Release + prompt + 4 + false + true + + + + + + + + + + + + monodevelop-core-addins + + + monodevelop-core-addins + + + + + + + ..\..\..\mono\mcs\class\System.Windows.Forms\resources\create-keyboards.exe + + + + + + + + + + + + + + + + + + + + + Component + + + + + + + + + + + + + + + + + + Form + + + Form + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Component + + + True + True + Resources.resx + + + + + + + + Component + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Component + + + + + + + + + + + + + Component + + + + + Component + + + Component + + + Component + + + Component + + + + + Component + + + Component + + + Component + + + + + + + + + Component + + + + Component + + + + + + + Component + + + + + + + + + + + + + + + + + + + + Component + + + + + + Component + + + Component + + + Component + + + Component + + + + + Component + + + + Component + + + + + + + Component + + + + + Component + + + + Component + + + + + Component + + + + + Form + + + Component + + + + + + + + + + + + + + Component + + + + + + + Component + + + Component + + + Component + + + + + Component + + + + Component + + + Component + + + + UserWidget + + + Component + + + Component + + + + + Component + + + + + + Component + + + + + Component + + + Component + + + Component + + + Component + + + + Component + + + Component + + + Form + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Component + + + + + Component + + + + Component + + + + + + + + + Component + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Component + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Component + + + Component + + + + Component + + + + Component + + + + + + Component + + + + + + + + + + + + + + + + + Component + + + + + + + Component + + + + + + + + + + + + + + + + + + + + + + + + + + + Component + + + + + + + + + + + Component + + + Component + + + Component + + + Component + + + Component + + + Component + + + Component + + + + + + + + + + + + + + + + + + + + Component + + + + + + + + + + + + + Component + + + + Component + + + + Component + + + Component + + + Component + + + Component + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Component + + + + + + + + + + Component + + + Component + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Component + + + Component + + + + + + + + + + + + + + + Component + + + + + + + + + Component + + + + + + + + + + + Form + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PublicResXFileCodeGenerator + Designer + Resources.Designer.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/BackgroundType.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/BackgroundType.cs new file mode 100644 index 0000000..69a233a --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/BackgroundType.cs @@ -0,0 +1,37 @@ +// +// BackgroundType.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum BackgroundType + { + ImageFile = 0, + BorderFill = 1, + None = 2 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/BooleanProperty.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/BooleanProperty.cs new file mode 100644 index 0000000..7044ecb --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/BooleanProperty.cs @@ -0,0 +1,47 @@ +// +// BooleanProperty.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum BooleanProperty + { + Transparent = 2201, + AutoSize = 2202, + BorderOnly = 2203, + Composited = 2204, + BackgroundFill = 2205, + GlyphTransparent = 2206, + GlyphOnly = 2207, + AlwaysShowSizingBar = 2208, + MirrorImage = 2209, + UniformSizing = 2210, + IntegralSizing = 2211, + SourceGrow = 2212, + SourceShrink = 2213 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/BorderType.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/BorderType.cs new file mode 100644 index 0000000..34eccbd --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/BorderType.cs @@ -0,0 +1,37 @@ +// +// BorderType.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum BorderType + { + Rectangle = 0, + RoundedRectangle = 1, + Ellipse = 2 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/CheckBoxState.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/CheckBoxState.cs new file mode 100644 index 0000000..0724874 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/CheckBoxState.cs @@ -0,0 +1,46 @@ +// +// CheckBoxState.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum CheckBoxState + { + UncheckedNormal = 1, + UncheckedHot = 2, + UncheckedPressed = 3, + UncheckedDisabled = 4, + CheckedNormal = 5, + CheckedHot = 6, + CheckedPressed = 7, + CheckedDisabled = 8, + MixedNormal = 9, + MixedHot = 10, + MixedPressed = 11, + MixedDisabled = 12 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/ColorProperty.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/ColorProperty.cs new file mode 100644 index 0000000..21442c8 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/ColorProperty.cs @@ -0,0 +1,57 @@ +// +// ColorProperty.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum ColorProperty + { + BorderColor = 3801, + FillColor = 3802, + TextColor = 3803, + EdgeLightColor = 3804, + EdgeHighlightColor = 3805, + EdgeShadowColor = 3806, + EdgeDarkShadowColor = 3807, + EdgeFillColor = 3808, + TransparentColor = 3809, + GradientColor1 = 3810, + GradientColor2 = 3811, + GradientColor3 = 3812, + GradientColor4 = 3813, + GradientColor5 = 3814, + ShadowColor = 3815, + GlowColor = 3816, + TextBorderColor = 3817, + TextShadowColor = 3818, + GlyphTextColor = 3819, + GlyphTransparentColor = 3820, + FillColorHint = 3821, + BorderColorHint = 3822, + AccentColorHint = 3823 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/ComboBoxState.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/ComboBoxState.cs new file mode 100644 index 0000000..30b801a --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/ComboBoxState.cs @@ -0,0 +1,38 @@ +// +// ComboBoxState.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum ComboBoxState + { + Normal = 1, + Hot = 2, + Pressed = 3, + Disabled = 4 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/ContentAlignment.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/ContentAlignment.cs new file mode 100644 index 0000000..31e6d8f --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/ContentAlignment.cs @@ -0,0 +1,37 @@ +// +// ContentAlignment.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum ContentAlignment + { + Left = 0, + Center = 1, + Right = 2 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/EdgeEffects.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/EdgeEffects.cs new file mode 100644 index 0000000..539210e --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/EdgeEffects.cs @@ -0,0 +1,41 @@ +// +// EdgeEffects.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI.VisualStyles +{ + [Flags] + public enum EdgeEffects + { + None = 0, + FillInterior = 2048, + Flat = 4096, + Soft = 16384, + Mono = 32768 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/EdgeStyle.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/EdgeStyle.cs new file mode 100644 index 0000000..dc3229b --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/EdgeStyle.cs @@ -0,0 +1,38 @@ +// +// EdgeStyle.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum EdgeStyle + { + Raised = 5, + Etched = 6, + Bump = 9, + Sunken = 10 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/Edges.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/Edges.cs new file mode 100644 index 0000000..9bef611 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/Edges.cs @@ -0,0 +1,41 @@ +// +// Edges.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI.VisualStyles +{ + [Flags] + public enum Edges + { + Left = 1, + Top = 2, + Right = 4, + Bottom = 8, + Diagonal = 16 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/EnumProperty.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/EnumProperty.cs new file mode 100644 index 0000000..b2c1ca1 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/EnumProperty.cs @@ -0,0 +1,49 @@ +// +// EnumProperty.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum EnumProperty + { + BackgroundType = 4001, + BorderType = 4002, + FillType = 4003, + SizingType = 4004, + HorizontalAlignment = 4005, + ContentAlignment = 4006, + VerticalAlignment = 4007, + OffsetType = 4008, + IconEffect = 4009, + TextShadowType = 4010, + ImageLayout = 4011, + GlyphType = 4012, + ImageSelectType = 4013, + GlyphFontSizingType = 4014, + TrueSizeScalingType = 4015 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/FilenameProperty.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/FilenameProperty.cs new file mode 100644 index 0000000..773ddcc --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/FilenameProperty.cs @@ -0,0 +1,42 @@ +// +// FilenameProperty.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum FilenameProperty + { + ImageFile = 3001, + ImageFile1 = 3002, + ImageFile2 = 3003, + ImageFile3 = 3004, + ImageFile4 = 3005, + ImageFile5 = 3006, + StockImageFile = 3007, + GlyphImageFile = 3008 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/FillType.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/FillType.cs new file mode 100644 index 0000000..2a2e30d --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/FillType.cs @@ -0,0 +1,39 @@ +// +// FillType.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum FillType + { + Solid = 0, + VerticalGradient = 1, + HorizontalGradient = 2, + RadialGradient = 3, + TileImage = 4 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/FontProperty.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/FontProperty.cs new file mode 100644 index 0000000..83e48fe --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/FontProperty.cs @@ -0,0 +1,35 @@ +// +// FontProperty.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum FontProperty + { + GlyphFont = 2601 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/GlyphFontSizingType.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/GlyphFontSizingType.cs new file mode 100644 index 0000000..3d3c1db --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/GlyphFontSizingType.cs @@ -0,0 +1,37 @@ +// +// GlyphFontSizingType.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum GlyphFontSizingType + { + None = 0, + Size = 1, + Dpi = 2 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/GlyphType.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/GlyphType.cs new file mode 100644 index 0000000..877bc41 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/GlyphType.cs @@ -0,0 +1,37 @@ +// +// GlyphType.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum GlyphType + { + None = 0, + ImageGlyph = 1, + FontGlyph = 2 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/GroupBoxState.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/GroupBoxState.cs new file mode 100644 index 0000000..da0e2bd --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/GroupBoxState.cs @@ -0,0 +1,36 @@ +// +// GroupBoxState.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum GroupBoxState + { + Normal = 1, + Disabled = 2 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/GtkPlus.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/GtkPlus.cs new file mode 100644 index 0000000..ea5fb88 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/GtkPlus.cs @@ -0,0 +1,1774 @@ +// +// GtkPlus.cs: Wraps GTK+, exposing its Widget painting features to code +// that uses System.Drawing types (such as IDeviceContext, Rectangle). +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2008 George Giolfan +// +// Authors: +// George Giolfan (georgegiolfan@yahoo.com) +// + +using gpointer = System.IntPtr; +using gboolean = System.Boolean; +using gint = System.Int32; +using guint = System.UInt32; +using guint8 = System.Byte; +using guint16 = System.UInt16; +using guint32 = System.UInt32; +using gfloat = System.Single; +using gdouble = System.Double; + +using PangoFontDescriptionPointer = System.IntPtr; + +using GDataPointer = System.IntPtr; +using GObjectPointer = System.IntPtr; +using GSListPointer = System.IntPtr; +using GType = System.IntPtr; +using GTypeClassPointer = System.IntPtr; +using GTypeInstancePointer = System.IntPtr; + +using GdkColormapPointer = System.IntPtr; +using GdkDrawablePointer = System.IntPtr; +using GdkGCPointer = System.IntPtr; +using GdkNativeWindowPointer = System.IntPtr; +using GdkPixbufPointer = System.IntPtr; +using GdkPixmapPointer = System.IntPtr; +using GdkWindowPointer = System.IntPtr; + +using GtkAdjustmentPointer = System.IntPtr; +using GtkBinPointer = System.IntPtr; +using GtkContainerPointer = System.IntPtr; +using GtkObjectPointer = System.IntPtr; +using GtkStylePointer = System.IntPtr; +using GtkToolbarPointer = System.IntPtr; +using GtkToolItemPointer = System.IntPtr; +using GtkTreeViewPointer = System.IntPtr; +using GtkTreeViewColumnPointer = System.IntPtr; +using GtkWidgetPointer = System.IntPtr; +using GtkWindowPointer = System.IntPtr; + +using GtkAllocation = ShiftUI.VisualStyles.GtkPlus.GdkRectangle; +using GInitiallyUnowned = ShiftUI.VisualStyles.GtkPlus.GObject; + +using System.Collections; +using System.Drawing; +using System.Drawing.Imaging; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI.VisualStyles +{ + /// + /// + /// + /// Inspired by ThemeGtk and QGtkStyle (http://labs.trolltech.com/page/Projects/Styles/GtkStyle). Tries to use the exact GTK+ logic in order to be compatible with all its themes. + /// + class GtkPlus + { + #region Instance + static GtkPlus instance; + public static GtkPlus Instance { + get { return instance; } + } + #endregion + #region GTK+ initialization + public static bool Initialize () + { + try { + if (gtk_check_version (2, 10, 0) != IntPtr.Zero) + return false; + //TODO: If we need to pass the actual arguments, duplicate the required code from GTK#. + int argc = 0; + string [] argv = new string [1]; + bool result = gtk_init_check (ref argc, ref argv); + if (result) + instance = new GtkPlus (); + return result; + } catch (DllNotFoundException) { + return false; + } + } + #endregion + + #region Fields + readonly int WidgetTypeCount = Enum.GetNames (typeof (WidgetType)).Length; + readonly GtkWidgetPointer [] widgets; + readonly GtkWidgetPointer window; + readonly GtkWidgetPointer @fixed; + readonly GtkStylePointer [] styles; + #region ComboBox + readonly GtkWidgetPointer combo_box_drop_down_toggle_button; + readonly GtkWidgetPointer combo_box_drop_down_arrow; + GtkStylePointer combo_box_drop_down_toggle_button_style; + GtkStylePointer combo_box_drop_down_arrow_style; + #endregion + #region ToolBar + readonly GtkWidgetPointer tool_bar_button; + readonly GtkWidgetPointer tool_bar_toggle_button; + GtkStylePointer tool_bar_button_style; + GtkStylePointer tool_bar_toggle_button_style; + #endregion + #region TreeView + readonly GtkTreeViewColumnPointer tree_view_column; + readonly GtkWidgetPointer tree_view_column_button; + GtkStylePointer tree_view_column_button_style; + #endregion + #region Painters + readonly ButtonPainter button_painter = new ButtonPainter (); + readonly CheckBoxPainter check_box_painter = new CheckBoxPainter (); + readonly RadioButtonPainter radio_button_painter = new RadioButtonPainter (); + #region ComboBox + readonly ComboBoxDropDownButtonPainter combo_box_drop_down_button_painter = new ComboBoxDropDownButtonPainter (); + readonly ComboBoxBorderPainter combo_box_border_painter = new ComboBoxBorderPainter (); + #endregion + #region GroupBox + readonly GroupBoxPainter group_box_painter = new GroupBoxPainter (); + #endregion + #region Header + readonly HeaderPainter header_painter = new HeaderPainter (); + #endregion + #region ProgressBar + readonly ProgressBarBarPainter progress_bar_bar_painter = new ProgressBarBarPainter (); + readonly ProgressBarChunkPainter progress_bar_chunk_painter = new ProgressBarChunkPainter (); + #endregion + #region ScrollBar + readonly ScrollBarArrowButtonPainter scroll_bar_arrow_button_painter = new ScrollBarArrowButtonPainter (); + readonly ScrollBarThumbButtonPainter scroll_bar_thumb_button_painter = new ScrollBarThumbButtonPainter (); + readonly ScrollBarTrackPainter scroll_bar_track_painter = new ScrollBarTrackPainter (); + #endregion + #region StatusBar + readonly StatusBarGripperPainter status_bar_gripper_painter = new StatusBarGripperPainter (); + #endregion + #region TabWidget + readonly TabWidgetPanePainter tab_Widget_pane_painter = new TabWidgetPanePainter (); + readonly TabWidgetTabItemPainter tab_Widget_tab_item_painter = new TabWidgetTabItemPainter (); + #endregion + readonly TextBoxPainter text_box_painter = new TextBoxPainter (); + #region ToolBar + readonly ToolBarPainter tool_bar_painter = new ToolBarPainter (); + readonly ToolBarButtonPainter tool_bar_button_painter = new ToolBarButtonPainter (); + readonly ToolBarCheckedButtonPainter tool_bar_checked_button_painter = new ToolBarCheckedButtonPainter (); + #endregion + #region TrackBar + readonly TrackBarTrackPainter track_bar_track_painter = new TrackBarTrackPainter (); + readonly TrackBarThumbPainter track_bar_thumb_painter = new TrackBarThumbPainter (); + #endregion + readonly TreeViewGlyphPainter tree_view_glyph_painter = new TreeViewGlyphPainter (); + readonly UpDownPainter up_down_painter = new UpDownPainter (); + #endregion + #endregion + #region Constructor and finalizer + protected GtkPlus () + { + widgets = new GtkWidgetPointer [WidgetTypeCount]; + styles = new GtkStylePointer [WidgetTypeCount]; + window = gtk_window_new (GtkWindowType.GTK_WINDOW_TOPLEVEL); + @fixed = gtk_fixed_new (); + gtk_container_add (window, @fixed); + #region Widget types + #region Button + gtk_container_add (@fixed, widgets [(int)WidgetType.Button] = gtk_button_new ()); + GTK_WIDGET_SET_FLAGS (widgets [(int)WidgetType.Button], GtkWidgetFlags.GTK_CAN_DEFAULT); + #endregion + #region CheckBox + gtk_container_add (@fixed, widgets [(int)WidgetType.CheckBox] = gtk_check_button_new ()); + #endregion + #region ComboBox + gtk_container_add (@fixed, widgets [(int)WidgetType.ComboBox] = gtk_combo_box_entry_new ()); + gtk_widget_realize (widgets [(int)WidgetType.ComboBox]); + combo_box_drop_down_toggle_button = GetFirstChildWidgetOfType.Get (widgets [(int)WidgetType.ComboBox], gtk_toggle_button_get_type ()); + gtk_widget_realize (combo_box_drop_down_toggle_button); + combo_box_drop_down_arrow = GetFirstChildWidgetOfType.Get (combo_box_drop_down_toggle_button, gtk_arrow_get_type ()); + g_object_ref (combo_box_drop_down_toggle_button_style = GetWidgetStyle (combo_box_drop_down_toggle_button)); + g_object_ref (combo_box_drop_down_arrow_style = GetWidgetStyle (combo_box_drop_down_arrow)); + #endregion + #region GroupBox + gtk_container_add (@fixed, widgets [(int)WidgetType.GroupBox] = gtk_frame_new (null)); + #endregion + #region ProgressBar + gtk_container_add (@fixed, widgets [(int)WidgetType.ProgressBar] = gtk_progress_bar_new ()); + #endregion + #region RadioButton + gtk_container_add (@fixed, widgets [(int)WidgetType.RadioButton] = gtk_radio_button_new (IntPtr.Zero)); + #endregion + #region ScrollBar + gtk_container_add (@fixed, widgets [(int)WidgetType.HScrollBar] = gtk_hscrollbar_new (IntPtr.Zero)); + gtk_container_add (@fixed, widgets [(int)WidgetType.VScrollBar] = gtk_vscrollbar_new (IntPtr.Zero)); + #endregion + #region StatusBar + gtk_container_add (@fixed, widgets [(int)WidgetType.StatusBar] = gtk_statusbar_new ()); + #endregion + #region TabWidget + gtk_container_add (@fixed, widgets [(int)WidgetType.TabWidget] = gtk_notebook_new ()); + #endregion + #region TextBox + gtk_container_add (@fixed, widgets [(int)WidgetType.TextBox] = gtk_entry_new ()); + #endregion + #region ToolBar + gtk_container_add (@fixed, widgets [(int)WidgetType.ToolBar] = gtk_toolbar_new ()); + + GtkToolItemPointer tool_button = gtk_tool_button_new (IntPtr.Zero, null); + gtk_toolbar_insert (widgets [(int)WidgetType.ToolBar], tool_button, -1); + tool_bar_button = gtk_bin_get_child (tool_button); + g_object_ref (tool_bar_button_style = GetWidgetStyle (tool_bar_button)); + + GtkToolItemPointer toggle_tool_button = gtk_toggle_tool_button_new (); + gtk_toolbar_insert (widgets [(int)WidgetType.ToolBar], toggle_tool_button, -1); + tool_bar_toggle_button = gtk_bin_get_child (toggle_tool_button); + g_object_ref (tool_bar_toggle_button_style = GetWidgetStyle (tool_bar_toggle_button)); + #endregion + #region TrackBar + gtk_container_add (@fixed, widgets [(int)WidgetType.HorizontalTrackBar] = gtk_hscale_new_with_range (0, 1, 1)); + gtk_container_add (@fixed, widgets [(int)WidgetType.VerticalTrackBar] = gtk_vscale_new_with_range (0, 1, 1)); + #endregion + #region TreeView + gtk_container_add (@fixed, widgets [(int)WidgetType.TreeView] = gtk_tree_view_new ()); + tree_view_column = gtk_tree_view_column_new (); + gtk_tree_view_insert_column (widgets [(int)WidgetType.TreeView], tree_view_column, -1); + GtkTreeViewColumn column_structure = (GtkTreeViewColumn)Marshal.PtrToStructure (tree_view_column, typeof (GtkTreeViewColumn)); + tree_view_column_button = column_structure.button; + g_object_ref (tree_view_column_button_style = GetWidgetStyle (tree_view_column_button)); + #endregion + #region UpDown + GtkAdjustmentPointer adjustment = gtk_adjustment_new (0, 0, 0, 0, 0, 0); + gtk_container_add (@fixed, widgets [(int)WidgetType.UpDown] = gtk_spin_button_new (adjustment, 0, 0)); + #endregion + #endregion + for (int widget_index = 0; widget_index < WidgetTypeCount; widget_index++) + g_object_ref (styles [widget_index] = GetWidgetStyle (widgets [widget_index])); + } + ~GtkPlus () + { + gtk_object_destroy (window); + for (int widget_index = 0; widget_index < WidgetTypeCount; widget_index++) + g_object_unref (styles [widget_index]); + #region ComboBox + g_object_unref (combo_box_drop_down_toggle_button_style); + g_object_unref (combo_box_drop_down_arrow_style); + #endregion + #region ToolBar + g_object_unref (tool_bar_button_style); + g_object_unref (tool_bar_toggle_button_style); + #endregion + #region TreeView + g_object_unref (tree_view_column_button_style); + #endregion + } + #endregion + #region Widgets + #region Button + public void ButtonPaint (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea, bool @default, GtkPlusState state) + { + button_painter.Configure (@default, state); + Paint (WidgetType.Button, bounds, dc, clippingArea, button_painter); + } + #endregion + #region CheckBox + public void CheckBoxPaint (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea, GtkPlusState state, GtkPlusToggleButtonValue value) + { + check_box_painter.Configure (state, value); + Paint (WidgetType.CheckBox, bounds, dc, clippingArea, check_box_painter); + } + Size GetGtkCheckButtonIndicatorSize (WidgetType widgetType) + { + int indicator_size = GetWidgetStyleInteger (widgets [(int)widgetType], "indicator-size"); + return new Size (indicator_size, indicator_size); + } + public Size CheckBoxGetSize () + { + return GetGtkCheckButtonIndicatorSize (WidgetType.CheckBox); + } + #endregion + #region ComboBox + public void ComboBoxPaintDropDownButton (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea, GtkPlusState state) + { + combo_box_drop_down_button_painter.Configure (state); + Paint (WidgetType.ComboBox, bounds, dc, clippingArea, combo_box_drop_down_button_painter); + } + public void ComboBoxPaintBorder (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea) + { + Paint (WidgetType.ComboBox, bounds, dc, clippingArea, combo_box_border_painter); + } + #endregion + #region GroupBox + public void GroupBoxPaint (IDeviceContext dc, Rectangle bounds, Rectangle excludedArea, GtkPlusState state) + { + group_box_painter.Configure (state); + PaintExcludingArea (WidgetType.GroupBox, bounds, dc, excludedArea, group_box_painter); + } + #endregion + #region Header + public void HeaderPaint (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea, GtkPlusState state) + { + header_painter.Configure (state); + Paint (WidgetType.TreeView, bounds, dc, clippingArea, header_painter); + } + #endregion + #region ProgressBar + public void ProgressBarPaintBar (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea) + { + Paint (WidgetType.ProgressBar, bounds, dc, clippingArea, progress_bar_bar_painter); + } + public void ProgressBarPaintChunk (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea) + { + Paint (WidgetType.ProgressBar, bounds, dc, clippingArea, progress_bar_chunk_painter); + } + public Rectangle ProgressBarGetBackgroundContentRectagle (Rectangle bounds) + { + GtkStyle style = (GtkStyle)Marshal.PtrToStructure (gtk_widget_get_style (widgets [(int)WidgetType.ProgressBar]), typeof(GtkStyle)); + bounds.Inflate (-style.xthickness, -style.ythickness); + return bounds; + } + #endregion + #region RadioButton + public void RadioButtonPaint (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea, GtkPlusState state, GtkPlusToggleButtonValue value) + { + radio_button_painter.Configure (state, value); + Paint (WidgetType.RadioButton, bounds, dc, clippingArea, radio_button_painter); + } + public Size RadioButtonGetSize () + { + return GetGtkCheckButtonIndicatorSize (WidgetType.RadioButton); + } + #endregion + #region ScrollBar + public void ScrollBarPaintArrowButton (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea, GtkPlusState state, bool horizontal, bool upOrLeft) + { + scroll_bar_arrow_button_painter.Configure (state, horizontal, upOrLeft); + Paint (horizontal ? WidgetType.HScrollBar : WidgetType.VScrollBar, bounds, dc, clippingArea, scroll_bar_arrow_button_painter); + } + public void ScrollBarPaintThumbButton (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea, GtkPlusState state, bool horizontal) + { + scroll_bar_thumb_button_painter.Configure (state, horizontal); + Paint (horizontal ? WidgetType.HScrollBar : WidgetType.VScrollBar, bounds, dc, clippingArea, scroll_bar_thumb_button_painter); + } + public void ScrollBarPaintTrack (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea, GtkPlusState state, bool horizontal, bool upOrLeft) + { + scroll_bar_track_painter.Configure (state, upOrLeft); + Paint (horizontal ? WidgetType.HScrollBar : WidgetType.VScrollBar, bounds, dc, clippingArea, scroll_bar_track_painter); + } + #endregion + #region StatusBar + public void StatusBarPaintGripper (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea) + { + Paint (WidgetType.StatusBar, bounds, dc, clippingArea, status_bar_gripper_painter); + } + #endregion + #region TabWidget + public void TabWidgetPaintPane (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea) + { + Paint (WidgetType.TabWidget, bounds, dc, clippingArea, tab_Widget_pane_painter); + } + public void TabWidgetPaintTabItem (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea, GtkPlusState state) + { + tab_Widget_tab_item_painter.Configure (state); + Paint (WidgetType.TabWidget, bounds, dc, clippingArea, tab_Widget_tab_item_painter); + } + #endregion + #region TextBox + public void TextBoxPaint (IDeviceContext dc, Rectangle bounds, Rectangle excludedArea, GtkPlusState state) + { + text_box_painter.Configure (state); + PaintExcludingArea (WidgetType.TextBox, bounds, dc, excludedArea, text_box_painter); + } + #endregion + #region ToolBar + public void ToolBarPaint (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea) + { + Paint (WidgetType.ToolBar, bounds, dc, clippingArea, tool_bar_painter); + } + public void ToolBarPaintButton (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea, GtkPlusState state) + { + tool_bar_button_painter.Configure (state); + Paint (WidgetTypeNotNeeded, bounds, dc, clippingArea, tool_bar_button_painter); + } + public void ToolBarPaintCheckedButton (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea) + { + Paint (WidgetTypeNotNeeded, bounds, dc, clippingArea, tool_bar_checked_button_painter); + } + #endregion + #region TrackBar + public void TrackBarPaintTrack (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea, bool horizontal) + { + Paint (horizontal ? WidgetType.HorizontalTrackBar : WidgetType.VerticalTrackBar, bounds, dc, clippingArea, track_bar_track_painter); + } + public void TrackBarPaintThumb (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea, GtkPlusState state, bool horizontal) + { + track_bar_thumb_painter.Configure (state, horizontal); + Paint (horizontal ? WidgetType.HorizontalTrackBar : WidgetType.VerticalTrackBar, bounds, dc, clippingArea, track_bar_thumb_painter); + } + #endregion + #region TreeView + public void TreeViewPaintGlyph (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea, bool closed) + { + tree_view_glyph_painter.Configure (closed); + Paint (WidgetType.TreeView, bounds, dc, clippingArea, tree_view_glyph_painter); + } + #endregion + #region UpDown + public void UpDownPaint (IDeviceContext dc, Rectangle bounds, Rectangle clippingArea, bool up, GtkPlusState state) + { + up_down_painter.Configure (up, state); + Paint (WidgetType.UpDown, bounds, dc, clippingArea, up_down_painter); + } + #endregion + #endregion + #region Painting + void Paint (WidgetType widgetType, Rectangle bounds, IDeviceContext dc, Rectangle clippingArea, Painter painter) + { + Paint (widgetType, bounds, dc, TransparencyType.Alpha, Color.Black, DeviceContextType.Native, clippingArea, painter, Rectangle.Empty); + } + void PaintExcludingArea (WidgetType widgetType, Rectangle bounds, IDeviceContext dc, Rectangle excludedArea, Painter painter) + { + Paint (widgetType, bounds, dc, TransparencyType.Alpha, Color.Black, DeviceContextType.Native, bounds, painter, excludedArea); + } + void Paint (WidgetType widgetType, Rectangle bounds, IDeviceContext dc, TransparencyType transparencyType, Color background, DeviceContextType deviceContextType, Rectangle clippingArea, Painter painter, Rectangle excludedArea) + { + Rectangle painted_area = Rectangle.Intersect (bounds, clippingArea); + if (painted_area.Width == 0 || painted_area.Height == 0) + return; + painted_area.Offset (-bounds.X, -bounds.Y); + excludedArea.Offset (-bounds.X, -bounds.Y); + GdkDrawablePointer drawable = gdk_pixmap_new (IntPtr.Zero, bounds.Width, bounds.Height, 24); + painter.AttachStyle (widgetType, drawable, this); + GdkPixbufPointer pixbuf; + IntPtr pixel_data; + int rowstride; + GdkGCPointer gc = gdk_gc_new (drawable); + GdkColor color = new GdkColor (background); + gdk_gc_set_rgb_fg_color (gc, ref color); + Paint (drawable, gc, bounds, widgetType, out pixbuf, out pixel_data, out rowstride, painted_area, painter, excludedArea); + GdkPixbufPointer white_pixbuf = IntPtr.Zero; + IntPtr white_pixel_data = IntPtr.Zero; + int white_rowstride = 0; + GdkColor white_color = new GdkColor(); + if (transparencyType == TransparencyType.Alpha) { + white_color.red = guint16.MaxValue; + white_color.green = guint16.MaxValue; + white_color.blue = guint16.MaxValue; + gdk_gc_set_rgb_fg_color (gc, ref white_color); + Paint (drawable, gc, bounds, widgetType, out white_pixbuf, out white_pixel_data, out white_rowstride, painted_area, painter, excludedArea); + } + g_object_unref (gc); + unsafe { + byte* row = (byte*)pixel_data; + byte* pixel; + byte* white_row = (byte*)white_pixel_data; + byte* white_pixel; + + for (int row_index = 0; row_index < painted_area.Height; row_index++) { + pixel = row; + white_pixel = white_row; + for (int pixel_index = 0; pixel_index < painted_area.Width; pixel_index++) { + const int GdkRedOffset = 0; + const int GdkGreenOffset = 1; + const int GdkBlueOffset = 2; + const int BitmapAlphaOffset = 3; + const int BitmapRedOffset = 2; + const int BitmapBlueOffset = 0; + switch (transparencyType) { + case TransparencyType.Alpha: + pixel [BitmapAlphaOffset] = (byte)(pixel [GdkRedOffset] - white_pixel [GdkRedOffset] + byte.MaxValue); + break; + case TransparencyType.Color: + if ( + pixel [GdkRedOffset] == background.R && + pixel [GdkGreenOffset] == background.G && + pixel [GdkBlueOffset] == background.B) { + const int AlphaFullyTransparent = 0; + pixel [BitmapAlphaOffset] = AlphaFullyTransparent; + } + break; + } + + byte temporary = pixel [GdkRedOffset]; + pixel [BitmapBlueOffset] = pixel [GdkBlueOffset]; + pixel [BitmapRedOffset] = temporary; + + const int PixelSize = 4; + pixel += PixelSize; + white_pixel += PixelSize; + } + row += rowstride; + white_row += white_rowstride; + } + } + if (transparencyType == TransparencyType.Alpha) + g_object_unref (white_pixbuf); + g_object_unref (drawable); + Bitmap bitmap = new Bitmap (painted_area.Width, painted_area.Height, rowstride, PixelFormat.Format32bppPArgb, pixel_data); + Graphics g; + bool graphics_is_from_hdc = false; + switch (deviceContextType) { + case DeviceContextType.Graphics: + g = (Graphics)dc; + break; + case DeviceContextType.Native: + g = Graphics.FromHdc (dc.GetHdc ()); + break; + default: + g = dc as Graphics; + if (g == null) { + graphics_is_from_hdc = true; + g = Graphics.FromHdc (dc.GetHdc ()); + } else + graphics_is_from_hdc = false; + break; + } + painted_area.Offset (bounds.X, bounds.Y); + g.DrawImage (bitmap, painted_area.Location); + switch (deviceContextType) { + case DeviceContextType.Graphics: + break; + case DeviceContextType.Native: + g.Dispose (); + dc.ReleaseHdc (); + break; + default: + if (graphics_is_from_hdc) { + g.Dispose (); + dc.ReleaseHdc (); + } + break; + } + bitmap.Dispose (); + g_object_unref (pixbuf); + } + void Paint (GdkDrawablePointer drawable, GdkGCPointer gc, Rectangle rectangle, WidgetType widgetType, out GdkPixbufPointer pixbuf, out IntPtr pixelData, out int rowstride, Rectangle clippingArea, Painter painter, Rectangle excludedArea) + { + gdk_draw_rectangle (drawable, gc, true, clippingArea.X, clippingArea.Y, clippingArea.Width, clippingArea.Height); + painter.Paint (styles [(int)widgetType], drawable, new GdkRectangle(clippingArea), widgets [(int)widgetType], 0, 0, rectangle.Width, rectangle.Height, this); + if (excludedArea.Width != 0) + gdk_draw_rectangle (drawable, gc, true, excludedArea.X, excludedArea.Y, excludedArea.Width, excludedArea.Height); + if ( + (pixbuf = gdk_pixbuf_new (GdkColorspace.GDK_COLORSPACE_RGB, true, 8, clippingArea.Width, clippingArea.Height)) == IntPtr.Zero || + gdk_pixbuf_get_from_drawable (pixbuf, drawable, IntPtr.Zero, clippingArea.X, clippingArea.Y, 0, 0, clippingArea.Width, clippingArea.Height) == IntPtr.Zero) + throw new OutOfMemoryException (); + pixelData = gdk_pixbuf_get_pixels (pixbuf); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + } + abstract class Painter + { + public virtual void AttachStyle (WidgetType widgetType, GdkDrawablePointer drawable, GtkPlus gtkPlus) + { + gtkPlus.styles [(int)widgetType] = gtk_style_attach (gtkPlus.styles [(int)widgetType], drawable); + } + public abstract void Paint (GtkStylePointer style, GdkWindowPointer window, GdkRectangle area, GtkWidgetPointer widget, gint x, gint y, gint width, gint height, GtkPlus gtkPlus); + } + enum TransparencyType + { + None, + Color, + Alpha + } + enum DeviceContextType + { + Unknown, + Graphics, + Native + } + #endregion + #region Painters + #region Button + class ButtonPainter : Painter + { + bool @default; + GtkPlusState state; + public void Configure (bool @default, GtkPlusState state) { + this.@default = @default; + this.state = state; + } + public override void Paint (GtkStylePointer style, GdkWindowPointer window, GdkRectangle area, GtkWidgetPointer widget, gint x, gint y, gint width, gint height, GtkPlus gtkPlus) + { + if (@default) { + gtk_window_set_default (gtkPlus.window, widget); + gtk_paint_box ( + style, + window, + GtkStateType.GTK_STATE_NORMAL, + GtkShadowType.GTK_SHADOW_IN, + ref area, + widget, + "buttondefault", + x, y, width, height); + gtk_window_set_default (gtkPlus.window, IntPtr.Zero); + } else + gtk_paint_box ( + style, + window, + (GtkStateType)state, + state == GtkPlusState.Pressed ? GtkShadowType.GTK_SHADOW_IN : GtkShadowType.GTK_SHADOW_OUT, + ref area, + widget, + "button", + x, y, width, height); + } + } + #endregion + #region CheckBox, RadioButton + abstract class ToggleButtonPainter : Painter + { + GtkPlusState state; + GtkPlusToggleButtonValue value; + public void Configure (GtkPlusState state, GtkPlusToggleButtonValue value) + { + this.state = state; + this.value = value; + } + public override void Paint (GtkStylePointer style, GdkWindowPointer window, GdkRectangle area, GtkWidgetPointer widget, gint x, gint y, gint width, gint height, GtkPlus gtkPlus) + { + PaintFunction ( + style, + window, + (GtkStateType)state, + (GtkShadowType)value, + ref area, + widget, + Detail, + x, y, width,height); + } + protected abstract string Detail { get; } + protected abstract ToggleButtonPaintFunction PaintFunction { get; } + } + delegate void ToggleButtonPaintFunction (GtkStylePointer style, GdkWindowPointer window, GtkStateType state_type, GtkShadowType shadow_type, ref GdkRectangle area, GtkWidgetPointer widget, string detail, gint x, gint y, gint width, gint height); + class CheckBoxPainter : ToggleButtonPainter + { + protected override string Detail { + get { + return "checkbutton"; + } + } + protected override ToggleButtonPaintFunction PaintFunction { + get { + return gtk_paint_check; + } + } + } + class RadioButtonPainter : ToggleButtonPainter + { + protected override string Detail { + get { + return "radiobutton"; + } + } + protected override ToggleButtonPaintFunction PaintFunction { + get { + return gtk_paint_option; + } + } + } + #endregion + #region ComboBox + class ComboBoxDropDownButtonPainter : Painter + { + GtkPlusState state; + public void Configure (GtkPlusState state) + { + this.state = state; + } + public override void AttachStyle (WidgetType widgetType, IntPtr drawable, GtkPlus gtkPlus) + { + gtkPlus.combo_box_drop_down_toggle_button_style = gtk_style_attach (gtkPlus.combo_box_drop_down_toggle_button_style, drawable); + gtkPlus.combo_box_drop_down_arrow_style = gtk_style_attach (gtkPlus.combo_box_drop_down_arrow_style, drawable); + } + public override void Paint (IntPtr style, IntPtr window, GdkRectangle area, IntPtr widget, int x, int y, int width, int height, GtkPlus gtkPlus) + { + GtkShadowType shadow_type; + switch (state) { + case GtkPlusState.Disabled: + shadow_type = GtkShadowType.GTK_SHADOW_ETCHED_IN; + break; + case GtkPlusState.Pressed: + shadow_type = GtkShadowType.GTK_SHADOW_IN; + break; + default: + shadow_type = GtkShadowType.GTK_SHADOW_OUT; + break; + } + gtk_paint_box ( + gtkPlus.combo_box_drop_down_toggle_button_style, + window, + (GtkStateType)state, + shadow_type, + ref area, + gtkPlus.combo_box_drop_down_toggle_button, + "button", + x, y, width, height); + GtkMisc misc = (GtkMisc)Marshal.PtrToStructure (gtkPlus.combo_box_drop_down_arrow, typeof (GtkMisc)); + int extent = (int)(Math.Min (width - misc.xpad * 2, height - misc.ypad * 2) * GetWidgetStyleSingle (gtkPlus.combo_box_drop_down_arrow, "arrow-scaling")); + gtk_paint_arrow ( + gtkPlus.combo_box_drop_down_arrow_style, + window, + (GtkStateType)state, + GtkShadowType.GTK_SHADOW_NONE, + ref area, + gtkPlus.combo_box_drop_down_arrow, + "arrow", + GtkArrowType.GTK_ARROW_DOWN, + true, + (int)Math.Floor (x + misc.xpad + (width - extent) * misc.xalign), + (int)Math.Floor (y + misc.ypad + (height - extent) * misc.yalign), + extent, extent); + } + } + class ComboBoxBorderPainter : Painter + { + public override void Paint (IntPtr style, IntPtr window, GdkRectangle area, IntPtr widget, int x, int y, int width, int height, GtkPlus gtkPlus) + { + gtk_paint_shadow ( + style, + window, + GtkStateType.GTK_STATE_NORMAL, + GtkShadowType.GTK_SHADOW_IN, + ref area, + widget, + "combobox", + x, y, width, height); + } + } + #endregion + #region GroupBox + class GroupBoxPainter : Painter + { + GtkPlusState state; + public void Configure (GtkPlusState state) + { + this.state = state; + } + public override void Paint (IntPtr style, IntPtr window, GdkRectangle area, IntPtr widget, int x, int y, int width, int height, GtkPlus gtkPlus) + { + gtk_paint_shadow ( + style, + window, + (GtkStateType)state, + GtkShadowType.GTK_SHADOW_ETCHED_IN, + ref area, + widget, + "frame", + x, y, width, height); + + } + } + #endregion + #region Header + class HeaderPainter : Painter + { + GtkPlusState state; + public void Configure (GtkPlusState state) + { + this.state = state; + } + public override void AttachStyle (WidgetType widgetType, IntPtr drawable, GtkPlus gtkPlus) + { + gtkPlus.tree_view_column_button_style = gtk_style_attach (gtkPlus.tree_view_column_button_style, drawable); + } + public override void Paint (IntPtr style, IntPtr window, GdkRectangle area, IntPtr widget, int x, int y, int width, int height, GtkPlus gtkPlus) + { + gtk_paint_box ( + gtkPlus.tree_view_column_button_style, + window, + (GtkStateType)state, + state == GtkPlusState.Pressed ? GtkShadowType.GTK_SHADOW_IN : GtkShadowType.GTK_SHADOW_OUT, + ref area, + gtkPlus.tree_view_column_button, + "button", + x, y, width, height); + } + } + #endregion + #region ProgressBar + class ProgressBarBarPainter : Painter + { + public override void Paint (IntPtr style, IntPtr window, GdkRectangle area, IntPtr widget, int x, int y, int width, int height, GtkPlus gtkPlus) + { + gtk_paint_box ( + style, + window, + GtkStateType.GTK_STATE_NORMAL, + GtkShadowType.GTK_SHADOW_IN, + ref area, + widget, + "trough", + x, y, width, height); + } + } + class ProgressBarChunkPainter : Painter + { + public override void Paint (IntPtr style, IntPtr window, GdkRectangle area, IntPtr widget, int x, int y, int width, int height, GtkPlus gtkPlus) + { + gtk_paint_box ( + style, + window, + GtkStateType.GTK_STATE_PRELIGHT, + GtkShadowType.GTK_SHADOW_OUT, + ref area, + widget, + "bar", + x, y, width, height); + } + } + #endregion + #region ScrollBar + class ScrollBarArrowButtonPainter : Painter + { + GtkPlusState state; + bool horizontal; + bool up_or_left; + public void Configure (GtkPlusState state, bool horizontal, bool upOrLeft) + { + this.state = state; + this.horizontal = horizontal; + up_or_left = upOrLeft; + } + public override void Paint (IntPtr style, IntPtr window, GdkRectangle area, IntPtr widget, int x, int y, int width, int height, GtkPlus gtkPlus) + { + gboolean can_focus; + g_object_get (widget, "can-focus", out can_focus, IntPtr.Zero); + if (can_focus) { + int focus_line_width; + int focus_padding; + gtk_widget_style_get (widget, + "focus-line-width", out focus_line_width, + "focus-padding", out focus_padding, + IntPtr.Zero); + int focus_width = focus_line_width + focus_padding; + if (horizontal) { + y -= focus_width; + height -= 2 * focus_width; + } else { + x -= focus_width; + width -= 2 * focus_width; + } + } + GtkShadowType shadow_type = state == GtkPlusState.Pressed ? GtkShadowType.GTK_SHADOW_IN : GtkShadowType.GTK_SHADOW_OUT; + string detail = horizontal ? "hscrollbar" : "vscrollbar"; + gtk_paint_box ( + style, + window, + (GtkStateType)state, + shadow_type, + ref area, + widget, + detail, + x, y, width, height); + width /= 2; + height /= 2; + x += width / 2; + y += height / 2; + if (state == GtkPlusState.Pressed) { + int arrow_displacement_x; + int arrow_displacement_y; + gtk_widget_style_get (widget, + "arrow-displacement-x", out arrow_displacement_x, + "arrow-displacement-y", out arrow_displacement_y, + IntPtr.Zero); + x += arrow_displacement_x; + y += arrow_displacement_y; + } + gtk_paint_arrow ( + style, + window, + (GtkStateType)state, + shadow_type, + ref area, + widget, + detail, + horizontal ? up_or_left ? GtkArrowType.GTK_ARROW_LEFT : GtkArrowType.GTK_ARROW_RIGHT : up_or_left ? GtkArrowType.GTK_ARROW_UP : GtkArrowType.GTK_ARROW_DOWN, + true, + x, y, width, height); + } + } + abstract class RangeThumbButtonPainter : Painter + { + GtkPlusState state; + bool horizontal; + protected bool Horizontal { + get { return horizontal; } + } + public void Configure (GtkPlusState state, bool horizontal) + { + this.state = state; + this.horizontal = horizontal; + } + public override void Paint (IntPtr style, IntPtr window, GdkRectangle area, IntPtr widget, int x, int y, int width, int height, GtkPlus gtkPlus) + { + gtk_paint_slider ( + style, + window, + (GtkStateType)state, + state == GtkPlusState.Pressed && GetWidgetStyleBoolean (widget, "activate-slider") ? GtkShadowType.GTK_SHADOW_IN : GtkShadowType.GTK_SHADOW_OUT, + ref area, + widget, + Detail, + x, y, width, height, + horizontal ? GtkOrientation.GTK_ORIENTATION_HORIZONTAL : GtkOrientation.GTK_ORIENTATION_VERTICAL); + } + protected abstract string Detail { get; } + } + class ScrollBarThumbButtonPainter : RangeThumbButtonPainter + { + protected override string Detail { + get { + return "slider"; + } + } + } + class ScrollBarTrackPainter : Painter + { + GtkPlusState state; + bool up_or_left; + public void Configure (GtkPlusState state, bool upOrLeft) + { + this.state = state; + up_or_left = upOrLeft; + } + public override void Paint (IntPtr style, IntPtr window, GdkRectangle area, IntPtr widget, int x, int y, int width, int height, GtkPlus gtkPlus) + { + gtk_paint_box ( + style, + window, + state == GtkPlusState.Pressed ? GtkStateType.GTK_STATE_ACTIVE : GtkStateType.GTK_STATE_INSENSITIVE, + GtkShadowType.GTK_SHADOW_IN, + ref area, + widget, + GetWidgetStyleBoolean (widget, "trough-side-details") ? + up_or_left ? "trough-upper" : "trough-lower" : + "trough", + x, y, width, height); + } + } + #endregion + #region StatusBar + class StatusBarGripperPainter : Painter + { + public override void Paint (IntPtr style, IntPtr window, GdkRectangle area, IntPtr widget, int x, int y, int width, int height, GtkPlus gtkPlus) + { + gtk_paint_resize_grip ( + style, + window, + GtkStateType.GTK_STATE_NORMAL, + ref area, + widget, + "statusbar", + GdkWindowEdge.GDK_WINDOW_EDGE_SOUTH_EAST, + x, y, width, height); + } + } + #endregion + #region TabWidget + class TabWidgetPanePainter : Painter + { + public override void Paint (IntPtr style, IntPtr window, GdkRectangle area, IntPtr widget, int x, int y, int width, int height, GtkPlus gtkPlus) + { + gtk_paint_box_gap ( + style, + window, + GtkStateType.GTK_STATE_NORMAL, + GtkShadowType.GTK_SHADOW_OUT, + ref area, + widget, + "notebook", + x, y, width, height, + GtkPositionType.GTK_POS_TOP, + 0, + 0); + } + } + class TabWidgetTabItemPainter : Painter + { + GtkPlusState state; + public void Configure (GtkPlusState state) + { + this.state = state; + } + public override void Paint (IntPtr style, IntPtr window, GdkRectangle area, IntPtr widget, int x, int y, int width, int height, GtkPlus gtkPlus) + { + gtk_paint_extension ( + style, + window, + (GtkStateType)state, + GtkShadowType.GTK_SHADOW_OUT, + ref area, + widget, + "tab", + x, y, width, height, + GtkPositionType.GTK_POS_BOTTOM); + } + } + #endregion + #region TextBox + class TextBoxPainter : Painter + { + GtkPlusState state; + public void Configure (GtkPlusState state) + { + this.state = state; + } + public override void Paint (IntPtr style, IntPtr window, GdkRectangle area, IntPtr widget, int x, int y, int width, int height, GtkPlus gtkPlus) + { + gtk_paint_shadow ( + style, + window, + GtkStateType.GTK_STATE_NORMAL, + GtkShadowType.GTK_SHADOW_IN, + ref area, + widget, + "entry", + x, y, width, height); + GtkStyle style_structure = (GtkStyle)Marshal.PtrToStructure (style, typeof (GtkStyle)); + x += style_structure.xthickness; + y += style_structure.ythickness; + width -= 2 * style_structure.xthickness; + height -= 2 * style_structure.ythickness; + gtk_paint_flat_box ( + style, + window, + (GtkStateType)state, + GtkShadowType.GTK_SHADOW_NONE, + ref area, + widget, + "entry_bg", + x, y, width, height); + } + } + #endregion + #region ToolBar + class ToolBarPainter : Painter + { + public override void Paint (IntPtr style, IntPtr window, GdkRectangle area, IntPtr widget, int x, int y, int width, int height, GtkPlus gtkPlus) + { + gtk_paint_box ( + style, + window, + GtkStateType.GTK_STATE_NORMAL, + GetWidgetStyleShadowType (widget), + ref area, + widget, + "toolbar", + x, y, width, height); + } + } + class ToolBarButtonPainter : Painter + { + GtkPlusState state; + public void Configure (GtkPlusState state) { + this.state = state; + } + public override void AttachStyle (WidgetType widgetType, IntPtr drawable, GtkPlus gtkPlus) + { + gtkPlus.tool_bar_button_style = gtk_style_attach (gtkPlus.tool_bar_button_style, drawable); + } + public override void Paint (GtkStylePointer style, GdkWindowPointer window, GdkRectangle area, GtkWidgetPointer widget, gint x, gint y, gint width, gint height, GtkPlus gtkPlus) + { + gtk_paint_box ( + gtkPlus.tool_bar_button_style, + window, + (GtkStateType)state, + state == GtkPlusState.Pressed ? GtkShadowType.GTK_SHADOW_IN : GtkShadowType.GTK_SHADOW_OUT, + ref area, + gtkPlus.tool_bar_button, + "button", + x, y, width, height); + } + } + class ToolBarCheckedButtonPainter : Painter + { + public override void AttachStyle (WidgetType widgetType, IntPtr drawable, GtkPlus gtkPlus) + { + gtkPlus.tool_bar_toggle_button_style = gtk_style_attach (gtkPlus.tool_bar_toggle_button_style, drawable); + } + public override void Paint (GtkStylePointer style, GdkWindowPointer window, GdkRectangle area, GtkWidgetPointer widget, gint x, gint y, gint width, gint height, GtkPlus gtkPlus) + { + gtk_paint_box ( + gtkPlus.tool_bar_toggle_button_style, + window, + GtkStateType.GTK_STATE_ACTIVE, + GtkShadowType.GTK_SHADOW_IN, + ref area, + gtkPlus.tool_bar_toggle_button, + "button", + x, y, width, height); + } + } + #endregion + #region TrackBar + class TrackBarTrackPainter : Painter + { + public override void Paint (IntPtr style, IntPtr window, GdkRectangle area, IntPtr widget, int x, int y, int width, int height, GtkPlus gtkPlus) + { + gtk_paint_box ( + style, + window, + GtkStateType.GTK_STATE_ACTIVE, + GtkShadowType.GTK_SHADOW_IN, + ref area, + widget, + "trough", + x, y, width, height); + } + } + class TrackBarThumbPainter : RangeThumbButtonPainter + { + protected override string Detail { + get { + return Horizontal ? "hscale" : "vscale"; + } + } + } + #endregion + #region TreeView + class TreeViewGlyphPainter : Painter + { + bool closed; + public void Configure (bool closed) + { + this.closed = closed; + } + public override void Paint (IntPtr style, IntPtr window, GdkRectangle area, IntPtr widget, int x, int y, int width, int height, GtkPlus gtkPlus) + { + gtk_paint_expander ( + style, + window, + GtkStateType.GTK_STATE_NORMAL, + ref area, + widget, + "treeview", + x + width / 2, + y + height / 2, + closed ? GtkExpanderStyle.GTK_EXPANDER_COLLAPSED : GtkExpanderStyle.GTK_EXPANDER_EXPANDED); + } + } + #endregion + #region UpDown + class UpDownPainter : Painter + { + bool up; + GtkPlusState state; + public void Configure (bool up, GtkPlusState state) + { + this.up = up; + this.state = state; + } + public override void Paint (IntPtr style, IntPtr window, GdkRectangle area, IntPtr widget, int x, int y, int width, int height, GtkPlus gtkPlus) + { + GtkShadowType shadow_type = GetWidgetStyleShadowType (widget); + if (shadow_type != GtkShadowType.GTK_SHADOW_NONE) + gtk_paint_box ( + style, + window, + GtkStateType.GTK_STATE_NORMAL, + shadow_type, + ref area, + widget, + "spinbutton", + x, y - (up ? 0 : height), width, height * 2); + shadow_type = state == GtkPlusState.Pressed ? GtkShadowType.GTK_SHADOW_IN : GtkShadowType.GTK_SHADOW_OUT; + gtk_paint_box ( + style, + window, + (GtkStateType)state, + shadow_type, + ref area, + widget, + up ? "spinbutton_up" : "spinbutton_down", + x, y, width, height); + if (up) + y += 2; + height -= 2; + width -= 3; + x += 1; + int w = width / 2; + w -= w % 2 - 1; + int h = (w + 1) / 2; + x += (width - w) / 2; + y += (height - h) / 2; + height = h; + width = w; + gtk_paint_arrow ( + style, + window, + (GtkStateType)state, + shadow_type, + ref area, + widget, + "spinbutton", + up ? GtkArrowType.GTK_ARROW_UP : GtkArrowType.GTK_ARROW_DOWN, + true, + x, y, width, height); + } + } + #endregion + #endregion + #region Widget types + const WidgetType WidgetTypeNotNeeded = (WidgetType)0; + enum WidgetType + { + Button, + CheckBox, + ComboBox, + GroupBox, + ProgressBar, + RadioButton, + #region ScrollBar + HScrollBar, + VScrollBar, + #endregion + StatusBar, + TabWidget, + TextBox, + ToolBar, + #region TrackBar + HorizontalTrackBar, + VerticalTrackBar, + #endregion + TreeView, + UpDown, + } + #endregion + #region GTK+ utility methods + static GtkShadowType GetWidgetStyleShadowType (GtkWidgetPointer widget) + { + GtkShadowType result; + gtk_widget_style_get (widget, "shadow-type", out result, IntPtr.Zero); + return result; + } + static int GetWidgetStyleInteger (GtkWidgetPointer widget, string propertyName) + { + gint result; + gtk_widget_style_get (widget, propertyName, out result, IntPtr.Zero); + return result; + } + static float GetWidgetStyleSingle (GtkWidgetPointer widget, string propertyName) + { + gfloat result; + gtk_widget_style_get (widget, propertyName, out result, IntPtr.Zero); + return result; + } + static bool GetWidgetStyleBoolean (GtkWidgetPointer widget, string propertyName) + { + gboolean result; + gtk_widget_style_get (widget, propertyName, out result, IntPtr.Zero); + return result; + } + #region GetFirstChildWidgetOfType + static class GetFirstChildWidgetOfType + { + public static GtkWidgetPointer Get (GtkContainerPointer parent, GType childType) + { + Type = childType; + Result = GtkWidgetPointer.Zero; + ContainersToSearch = new ArrayList (); + ContainersToSearch.Add (parent); + while (true) { + ArrayList containers_to_search = ContainersToSearch; + ContainersToSearch = new ArrayList (); + foreach (GtkContainerPointer container in containers_to_search) { + gtk_widget_realize (container); + gtk_container_forall (container, Callback, gpointer.Zero); + if (Result != GtkWidgetPointer.Zero) + return Result; + } + if (ContainersToSearch.Count == 0) + return GtkWidgetPointer.Zero; + } + } + static void Callback (GtkWidgetPointer widget, gpointer data) + { + if (Result != IntPtr.Zero) + return; + if (g_type_check_instance_is_a (widget, Type)) + Result = widget; + else if (g_type_check_instance_is_a (widget, gtk_container_get_type ())) + ContainersToSearch.Add (widget); + } + static GType Type; + static GtkWidgetPointer Result; + static ArrayList ContainersToSearch; + } + #endregion + static GtkStylePointer GetWidgetStyle (GtkWidgetPointer widget) + { + return gtk_rc_get_style (widget); + } + #endregion + #region Platform Invoke + #region Library names +#if VISUAL_STYLES_USE_GTKPLUS_ON_WINDOWS + const string GobjectLibraryName = "libgobject-2.0-0.dll"; + const string GdkLibraryName = "libgdk-win32-2.0-0.dll"; + const string GdkPixbufLibraryName = "libgdk_pixbuf-2.0-0.dll"; + const string GtkLibraryName = "libgtk-win32-2.0-0.dll"; +#else + const string GobjectLibraryName = "libgobject-2.0.so"; + const string GdkLibraryName = "libgdk-x11-2.0.so"; + const string GdkPixbufLibraryName = "libgdk_pixbuf-2.0.so"; + const string GtkLibraryName = "libgtk-x11-2.0.so"; +#endif + #endregion + #region GDK + [DllImport (GdkLibraryName)] + static extern void gdk_draw_rectangle (GdkDrawablePointer drawable, GdkGCPointer gc, gboolean filled, gint x, gint y, gint width, gint height); + [DllImport (GdkLibraryName)] + static extern GdkGCPointer gdk_gc_new (GdkDrawablePointer drawable); + [DllImport (GdkLibraryName)] + static extern void gdk_gc_set_rgb_fg_color (GdkGCPointer gc, ref GdkColor color); + [DllImport (GdkLibraryName)] + static extern GdkPixbufPointer gdk_pixbuf_get_from_drawable (GdkPixbufPointer dest, GdkDrawablePointer src, GdkColormapPointer cmap, int src_x, int src_y, int dest_x, int dest_y, int width, int height); + [DllImport (GdkLibraryName)] + static extern GdkPixmapPointer gdk_pixmap_new (GdkDrawablePointer drawable, gint width, gint height, gint depth); + struct GdkColor{ + public guint32 pixel; + public guint16 red; + public guint16 green; + public guint16 blue; + public GdkColor (Color value) + { + pixel = 0; + red = (guint16)(value.R << 8); + green = (guint16)(value.G << 8); + blue = (guint16)(value.B << 8); + } + } + internal struct GdkRectangle { + public gint x; + public gint y; + public gint width; + public gint height; + public GdkRectangle (Rectangle value) + { + x = value.X; + y = value.Y; + width = value.Width; + height = value.Height; + } + } + #endregion + #region GdkPixbuf + [DllImport (GdkPixbufLibraryName)] + static extern IntPtr gdk_pixbuf_get_pixels (GdkPixbufPointer pixbuf); + [DllImport (GdkPixbufLibraryName)] + static extern int gdk_pixbuf_get_rowstride (GdkPixbufPointer pixbuf); + [DllImport (GdkPixbufLibraryName)] + static extern GdkPixbufPointer gdk_pixbuf_new (GdkColorspace colorspace, gboolean has_alpha, int bits_per_sample, int width, int height); + enum GdkColorspace + { + GDK_COLORSPACE_RGB + } + #endregion + #region GTK + #region Functions + [DllImport (GtkLibraryName)] + static extern gboolean gtk_init_check (ref int argc, ref string[] argv); + [DllImport (GtkLibraryName)] + static extern IntPtr gtk_check_version (guint required_major, guint required_minor, guint required_micro); + [DllImport (GtkLibraryName)] + static extern void gtk_container_add (GtkContainerPointer container, GtkWidgetPointer widget); + [DllImport (GtkLibraryName)] + static extern void gtk_container_forall (GtkContainerPointer container, GtkCallback callback, gpointer callback_data); + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + delegate void GtkCallback (GtkWidgetPointer widget, gpointer data); + [DllImport (GtkLibraryName)] + static extern void gtk_object_destroy (GtkObjectPointer @object); + [DllImport (GtkLibraryName)] + static extern GtkStylePointer gtk_rc_get_style (GtkWidgetPointer widget); + [DllImport (GtkLibraryName)] + static extern GtkStylePointer gtk_style_attach (GtkStylePointer style, GdkWindowPointer window); + [DllImport (GtkLibraryName)] + static extern void gtk_widget_realize (GtkWidgetPointer widget); + [DllImport (GtkLibraryName)] + static extern void gtk_widget_style_get (GtkWidgetPointer widget, string property, out gint value, IntPtr nullTerminator); + [DllImport (GtkLibraryName)] + static extern void gtk_widget_style_get (GtkWidgetPointer widget, string property, out gfloat value, IntPtr nullTerminator); + [DllImport (GtkLibraryName)] + static extern void gtk_widget_style_get (GtkWidgetPointer widget, string property1, out gint value1, string property2, out gint value2, IntPtr nullTerminator); + [DllImport (GtkLibraryName)] + static extern void gtk_widget_style_get (GtkWidgetPointer widget, string property, out GtkShadowType value, IntPtr nullTerminator); + [DllImport (GtkLibraryName)] + static extern void gtk_widget_style_get (GtkWidgetPointer widget, string property, out gboolean value, IntPtr nullTerminator); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_window_new (GtkWindowType type); + [DllImport (GtkLibraryName)] + static extern void gtk_window_set_default (GtkWindowPointer window, GtkWidgetPointer default_widget); + [DllImport (GtkLibraryName)] + static extern GtkObjectPointer gtk_adjustment_new (gdouble value, gdouble lower, gdouble upper, gdouble step_increment, gdouble page_increment, gdouble page_size); + [DllImport (GtkLibraryName)] + static extern GtkStylePointer gtk_widget_get_style (GtkWidgetPointer widget); + [DllImport (GtkLibraryName)] + static extern GtkTreeViewColumnPointer gtk_tree_view_column_new (); + [DllImport (GtkLibraryName)] + static extern gint gtk_tree_view_insert_column ( + GtkTreeViewPointer tree_view, + GtkTreeViewColumnPointer column, + gint position); + [DllImport (GtkLibraryName)] + static extern void gtk_toolbar_insert ( + GtkToolbarPointer toolbar, + GtkToolItemPointer item, + gint pos); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_bin_get_child (GtkBinPointer bin); + #region Widget type + [DllImport (GtkLibraryName)] + static extern GType gtk_arrow_get_type (); + [DllImport (GtkLibraryName)] + static extern GType gtk_container_get_type (); + [DllImport (GtkLibraryName)] + static extern GType gtk_toggle_button_get_type (); + #endregion + #region Widget creation + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_button_new (); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_check_button_new (); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_combo_box_entry_new (); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_entry_new (); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_fixed_new (); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_frame_new (string label); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_hscale_new_with_range (gdouble min, gdouble max, gdouble step); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_hscrollbar_new (GtkAdjustmentPointer adjustment); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_notebook_new (); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_progress_bar_new (); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_radio_button_new (GSListPointer group); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_spin_button_new (GtkAdjustmentPointer adjustment, gdouble climb_rate, guint digits); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_statusbar_new (); + [DllImport (GtkLibraryName)] + static extern GtkToolItemPointer gtk_toggle_tool_button_new (); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_toolbar_new (); + [DllImport (GtkLibraryName)] + static extern GtkToolItemPointer gtk_tool_button_new ( + GtkWidgetPointer icon_widget, + string label); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_tree_view_new (); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_vscale_new_with_range (gdouble min, gdouble max, gdouble step); + [DllImport (GtkLibraryName)] + static extern GtkWidgetPointer gtk_vscrollbar_new (GtkAdjustmentPointer adjustment); + #endregion + #region Painting + [DllImport (GtkLibraryName)] + static extern void gtk_paint_arrow (GtkStylePointer style, GdkWindowPointer window, GtkStateType state_type, GtkShadowType shadow_type, ref GdkRectangle area, GtkWidgetPointer widget, string detail, GtkArrowType arrow_type, gboolean fill, gint x, gint y, gint width, gint height); + [DllImport (GtkLibraryName)] + static extern void gtk_paint_box (GtkStylePointer style, GdkWindowPointer window, GtkStateType state_type, GtkShadowType shadow_type, ref GdkRectangle area, GtkWidgetPointer widget, string detail, gint x, gint y, gint width, gint height); + [DllImport (GtkLibraryName)] + static extern void gtk_paint_box_gap ( + GtkStylePointer style, + GdkWindowPointer window, + GtkStateType state_type, + GtkShadowType shadow_type, + ref GdkRectangle area, + GtkWidgetPointer widget, + string detail, + gint x, + gint y, + gint width, + gint height, + GtkPositionType gap_side, + gint gap_x, + gint gap_width); + [DllImport (GtkLibraryName)] + static extern void gtk_paint_check (GtkStylePointer style, GdkWindowPointer window, GtkStateType state_type, GtkShadowType shadow_type, ref GdkRectangle area, GtkWidgetPointer widget, string detail, gint x, gint y, gint width, gint height); + [DllImport (GtkLibraryName)] + static extern void gtk_paint_expander ( + GtkStylePointer style, + GdkWindowPointer window, + GtkStateType state_type, + ref GdkRectangle area, + GtkWidgetPointer widget, + string detail, + gint x, + gint y, + GtkExpanderStyle expander_style); + [DllImport (GtkLibraryName)] + static extern void gtk_paint_extension ( + GtkStylePointer style, + GdkWindowPointer window, + GtkStateType state_type, + GtkShadowType shadow_type, + ref GdkRectangle area, + GtkWidgetPointer widget, + string detail, + gint x, + gint y, + gint width, + gint height, + GtkPositionType gap_side); + [DllImport (GtkLibraryName)] + static extern void gtk_paint_flat_box ( + GtkStylePointer style, + GdkWindowPointer window, + GtkStateType state_type, + GtkShadowType shadow_type, + ref GdkRectangle area, + GtkWidgetPointer widget, + string detail, + gint x, + gint y, + gint width, + gint height); + [DllImport (GtkLibraryName)] + static extern void gtk_paint_option (GtkStylePointer style, GdkWindowPointer window, GtkStateType state_type, GtkShadowType shadow_type, ref GdkRectangle area, GtkWidgetPointer widget, string detail, gint x, gint y, gint width, gint height); + [DllImport (GtkLibraryName)] + static extern void gtk_paint_resize_grip ( + GtkStylePointer style, + GdkWindowPointer window, + GtkStateType state_type, + ref GdkRectangle area, + GtkWidgetPointer widget, + string detail, + GdkWindowEdge edge, + gint x, + gint y, + gint width, + gint height); + [DllImport (GtkLibraryName)] + static extern void gtk_paint_shadow (GtkStylePointer style, GdkWindowPointer window, GtkStateType state_type, GtkShadowType shadow_type, ref GdkRectangle area, GtkWidgetPointer widget, string detail, gint x, gint y, gint width, gint height); + [DllImport (GtkLibraryName)] + static extern void gtk_paint_slider ( + GtkStylePointer style, + GdkWindowPointer window, + GtkStateType state_type, + GtkShadowType shadow_type, + ref GdkRectangle area, + GtkWidgetPointer widget, + string detail, + gint x, + gint y, + gint width, + gint height, + GtkOrientation orientation); + #endregion + #endregion + #region Enumerations + internal enum GtkShadowType + { + GTK_SHADOW_NONE, + GTK_SHADOW_IN, + GTK_SHADOW_OUT, + GTK_SHADOW_ETCHED_IN, + GTK_SHADOW_ETCHED_OUT + } + enum GtkStateType + { + GTK_STATE_NORMAL, + GTK_STATE_ACTIVE, + GTK_STATE_PRELIGHT, + GTK_STATE_SELECTED, + GTK_STATE_INSENSITIVE + } + enum GtkWindowType + { + GTK_WINDOW_TOPLEVEL, + GTK_WINDOW_POPUP + } + enum GtkArrowType + { + GTK_ARROW_UP, + GTK_ARROW_DOWN, + GTK_ARROW_LEFT, + GTK_ARROW_RIGHT, + GTK_ARROW_NONE + } + enum GtkOrientation + { + GTK_ORIENTATION_HORIZONTAL, + GTK_ORIENTATION_VERTICAL + } + enum GtkExpanderStyle + { + GTK_EXPANDER_COLLAPSED, + GTK_EXPANDER_SEMI_COLLAPSED, + GTK_EXPANDER_SEMI_EXPANDED, + GTK_EXPANDER_EXPANDED + } + enum GtkPositionType + { + GTK_POS_LEFT, + GTK_POS_RIGHT, + GTK_POS_TOP, + GTK_POS_BOTTOM + } + enum GtkWidgetFlags : uint + { + GTK_CAN_DEFAULT = 1 << 13, + } + enum GdkWindowEdge + { + GDK_WINDOW_EDGE_NORTH_WEST, + GDK_WINDOW_EDGE_NORTH, + GDK_WINDOW_EDGE_NORTH_EAST, + GDK_WINDOW_EDGE_WEST, + GDK_WINDOW_EDGE_EAST, + GDK_WINDOW_EDGE_SOUTH_WEST, + GDK_WINDOW_EDGE_SOUTH, + GDK_WINDOW_EDGE_SOUTH_EAST + } + #endregion + #region Structures + struct GtkStyle + { +#pragma warning disable 169 + GObject parent_instance; + [MarshalAs(UnmanagedType.ByValArray, SizeConst=5)] + GdkColor[] fg; + [MarshalAs(UnmanagedType.ByValArray, SizeConst=5)] + GdkColor[] bg; + [MarshalAs(UnmanagedType.ByValArray, SizeConst=5)] + GdkColor[] light; + [MarshalAs(UnmanagedType.ByValArray, SizeConst=5)] + GdkColor[] dark; + [MarshalAs(UnmanagedType.ByValArray, SizeConst=5)] + GdkColor[] mid; + [MarshalAs(UnmanagedType.ByValArray, SizeConst=5)] + GdkColor[] text; + [MarshalAs(UnmanagedType.ByValArray, SizeConst=5)] + GdkColor[] @base; + [MarshalAs(UnmanagedType.ByValArray, SizeConst=5)] + GdkColor[] text_aa; + GdkColor black; + GdkColor white; + PangoFontDescriptionPointer font_desc; +#pragma warning restore 169 + public gint xthickness; + public gint ythickness; + } + struct GtkWidget + { +#pragma warning disable 169 + GtkObject @object; + guint16 private_flags; + guint8 state; + guint8 saved_state; + string name; + GtkStylePointer style; + GtkRequisition requisition; +#pragma warning restore 169 + public GtkAllocation allocation; +#pragma warning disable 169 + GdkWindowPointer window; + GtkWidgetPointer parent; +#pragma warning restore 169 + } + struct GtkObject + { +#pragma warning disable 169 + GInitiallyUnowned parent_instance; +#pragma warning restore 169 + public guint32 flags; + } + struct GtkRequisition + { +#pragma warning disable 169 + gint width; + gint height; +#pragma warning restore 169 + } + struct GtkMisc + { +#pragma warning disable 169 + GtkWidget widget; +#pragma warning restore 169 + public gfloat xalign; + public gfloat yalign; + public guint16 xpad; + public guint16 ypad; + } + struct GtkTreeViewColumn + { +#pragma warning disable 169 + GtkObject parent; + GtkWidgetPointer tree_view; +#pragma warning restore 169 + public GtkWidgetPointer button; + } + #endregion + #region Macros + static void GTK_WIDGET_SET_FLAGS (GtkWidgetPointer wid, GtkWidgetFlags flag) + { + GtkObject @object = (GtkObject)Marshal.PtrToStructure (wid, typeof (GtkObject)); + @object.flags |= (guint32)flag; + Marshal.StructureToPtr (@object, wid, false); + } + #endregion + #endregion + #region GObject + [DllImport (GobjectLibraryName)] + static extern gpointer g_object_ref (gpointer @object); + [DllImport (GobjectLibraryName)] + static extern void g_object_unref (gpointer @object); + [DllImport (GobjectLibraryName)] + static extern gboolean g_type_check_instance_is_a (GTypeInstancePointer type_instance, GType iface_type); + [DllImport (GobjectLibraryName)] + static extern void g_object_get (gpointer @object, string property_name, out gboolean value, IntPtr nullTerminator); + const int G_TYPE_FUNDAMENTAL_SHIFT = 2; + enum G_TYPE + { + } + struct GTypeInstance + { +#pragma warning disable 169 + GTypeClassPointer g_class; +#pragma warning restore 169 + } + internal struct GObject + { +#pragma warning disable 169 + GTypeInstance g_type_instance; + guint ref_count; + GDataPointer qdata; +#pragma warning restore 169 + } + #endregion + #endregion + } + #region Exposed constants + enum GtkPlusToggleButtonValue + { + Unchecked = GtkPlus.GtkShadowType.GTK_SHADOW_OUT, + Mixed = GtkPlus.GtkShadowType.GTK_SHADOW_ETCHED_IN, + Checked = GtkPlus.GtkShadowType.GTK_SHADOW_IN + } + enum GtkPlusState + { + Normal, + Pressed, + Hot, + Selected, + Disabled + } + #endregion +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/HitTestCode.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/HitTestCode.cs new file mode 100644 index 0000000..ec873c5 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/HitTestCode.cs @@ -0,0 +1,44 @@ +// +// HitTestCode.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum HitTestCode + { + Nowhere = 0, + Client = 1, + Left = 10, + Right = 11, + Top = 12, + TopLeft = 13, + TopRight = 14, + Bottom = 15, + BottomLeft = 16, + BottomRight = 17 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/HitTestOptions.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/HitTestOptions.cs new file mode 100644 index 0000000..4dd9e55 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/HitTestOptions.cs @@ -0,0 +1,46 @@ +// +// HitTestOptions.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI.VisualStyles +{ + [Flags] + public enum HitTestOptions + { + BackgroundSegment = 0, + FixedBorder = 2, + Caption = 4, + ResizingBorderLeft = 16, + ResizingBorderTop = 32, + ResizingBorderRight = 64, + ResizingBorderBottom = 128, + ResizingBorder = 240, + SizingTemplate = 256, + SystemSizingMargins = 512 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/HorizontalAlign.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/HorizontalAlign.cs new file mode 100644 index 0000000..7070d13 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/HorizontalAlign.cs @@ -0,0 +1,37 @@ +// +// HorizontalAlign.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum HorizontalAlign + { + Left = 0, + Center = 1, + Right = 2 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/IVisualStyles.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/IVisualStyles.cs new file mode 100644 index 0000000..ad0e1b5 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/IVisualStyles.cs @@ -0,0 +1,90 @@ +// +// IVisualStyles.cs: An implementation of VisualStyleRenderer and +// VisualStyleInformation. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2008 George Giolfan +// +// Authors: +// George Giolfan (georgegiolfan@yahoo.com) +// + +using HRESULT = System.Int32; +using System.Drawing; +using System; + + +namespace ShiftUI.VisualStyles +{ + interface IVisualStyles + { + #region UxTheme + HRESULT UxThemeCloseThemeData (IntPtr hTheme); + HRESULT UxThemeDrawThemeBackground (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds); + HRESULT UxThemeDrawThemeBackground (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, Rectangle clipRectangle); + HRESULT UxThemeDrawThemeEdge (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds,Edges edges, EdgeStyle style, EdgeEffects effects, out Rectangle result); + HRESULT UxThemeDrawThemeParentBackground (IDeviceContext dc, Rectangle bounds, Widget childWidget); + HRESULT UxThemeDrawThemeText (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, String text, TextFormatFlags textFlags, Rectangle bounds); + HRESULT UxThemeGetThemeBackgroundContentRect (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, out Rectangle result); + HRESULT UxThemeGetThemeBackgroundExtent (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle contentBounds, out Rectangle result); + HRESULT UxThemeGetThemeBackgroundRegion (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, out Region result); + HRESULT UxThemeGetThemeBool (IntPtr hTheme, int iPartId, int iStateId, BooleanProperty prop, out bool result); + HRESULT UxThemeGetThemeColor (IntPtr hTheme, int iPartId, int iStateId, ColorProperty prop, out Color result); + HRESULT UxThemeGetThemeEnumValue (IntPtr hTheme, int iPartId, int iStateId, EnumProperty prop, out int result); + HRESULT UxThemeGetThemeFilename (IntPtr hTheme, int iPartId, int iStateId, FilenameProperty prop, out string result); + HRESULT UxThemeGetThemeInt (IntPtr hTheme, int iPartId, int iStateId, IntegerProperty prop, out int result); + HRESULT UxThemeGetThemeMargins (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, MarginProperty prop, out Padding result); + HRESULT UxThemeGetThemePartSize (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, ThemeSizeType type, out Size result); + HRESULT UxThemeGetThemePartSize (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, ThemeSizeType type, out Size result); + HRESULT UxThemeGetThemePosition (IntPtr hTheme, int iPartId, int iStateId, PointProperty prop, out Point result); + HRESULT UxThemeGetThemeString (IntPtr hTheme, int iPartId, int iStateId, StringProperty prop, out string result); + HRESULT UxThemeGetThemeTextExtent (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, string textToDraw, TextFormatFlags flags, Rectangle bounds, out Rectangle result); + HRESULT UxThemeGetThemeTextExtent (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, string textToDraw, TextFormatFlags flags, out Rectangle result); + HRESULT UxThemeGetThemeTextMetrics (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, out TextMetrics result); + HRESULT UxThemeHitTestThemeBackground (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, HitTestOptions options, Rectangle backgroundRectangle, IntPtr hrgn, Point pt, out HitTestCode result); + bool UxThemeIsAppThemed (); + bool UxThemeIsThemeActive (); + bool UxThemeIsThemeBackgroundPartiallyTransparent (IntPtr hTheme, int iPartId, int iStateId); + bool UxThemeIsThemePartDefined (IntPtr hTheme, int iPartId); + IntPtr UxThemeOpenThemeData (IntPtr hWnd, String classList); + #endregion + #region VisualStyleInformation + string VisualStyleInformationAuthor { get; } + string VisualStyleInformationColorScheme { get; } + string VisualStyleInformationCompany { get; } + Color VisualStyleInformationWidgetHighlightHot { get; } + string VisualStyleInformationCopyright { get; } + string VisualStyleInformationDescription { get; } + string VisualStyleInformationDisplayName { get; } + string VisualStyleInformationFileName { get; } + bool VisualStyleInformationIsSupportedByOS { get; } + int VisualStyleInformationMinimumColorDepth { get; } + string VisualStyleInformationSize { get; } + bool VisualStyleInformationSupportsFlatMenus { get; } + Color VisualStyleInformationTextWidgetBorder { get; } + string VisualStyleInformationUrl { get; } + string VisualStyleInformationVersion { get; } + #endregion + #region VisualStyleRenderer + void VisualStyleRendererDrawBackgroundExcludingArea (IntPtr theme, IDeviceContext dc, int part, int state, Rectangle bounds, Rectangle excludedArea); + #endregion + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/IconEffect.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/IconEffect.cs new file mode 100644 index 0000000..c6fe225 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/IconEffect.cs @@ -0,0 +1,39 @@ +// +// IconEffect.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum IconEffect + { + None = 0, + Glow = 1, + Shadow = 2, + Pulse = 3, + Alpha = 4 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/ImageOrientation.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/ImageOrientation.cs new file mode 100644 index 0000000..7a96c9f --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/ImageOrientation.cs @@ -0,0 +1,36 @@ +// +// ImageOrientation.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum ImageOrientation + { + Vertical = 0, + Horizontal = 1 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/ImageSelectType.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/ImageSelectType.cs new file mode 100644 index 0000000..ee0adec --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/ImageSelectType.cs @@ -0,0 +1,37 @@ +// +// ImageSelectType.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum ImageSelectType + { + None = 0, + Size = 1, + Dpi = 2 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/IntegerProperty.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/IntegerProperty.cs new file mode 100644 index 0000000..bd07c13 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/IntegerProperty.cs @@ -0,0 +1,58 @@ +// +// IntegerProperty.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum IntegerProperty + { + ImageCount = 2401, + AlphaLevel = 2402, + BorderSize = 2403, + RoundCornerWidth = 2404, + RoundCornerHeight = 2405, + GradientRatio1 = 2406, + GradientRatio2 = 2407, + GradientRatio3 = 2408, + GradientRatio4 = 2409, + GradientRatio5 = 2410, + ProgressChunkSize = 2411, + ProgressSpaceSize = 2412, + Saturation = 2413, + TextBorderSize = 2414, + AlphaThreshold = 2415, + Width = 2416, + Height = 2417, + GlyphIndex = 2418, + TrueSizeStretchMark = 2419, + MinDpi1 = 2420, + MinDpi2 = 2421, + MinDpi3 = 2422, + MinDpi4 = 2423, + MinDpi5 = 2424 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/MarginProperty.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/MarginProperty.cs new file mode 100644 index 0000000..4bd1115 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/MarginProperty.cs @@ -0,0 +1,37 @@ +// +// MarginProperty.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum MarginProperty + { + SizingMargins = 3601, + ContentMargins = 3602, + CaptionMargins = 3603 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/OffsetType.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/OffsetType.cs new file mode 100644 index 0000000..1facddc --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/OffsetType.cs @@ -0,0 +1,48 @@ +// +// OffsetType.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum OffsetType + { + TopLeft = 0, + TopRight = 1, + TopMiddle = 2, + BottomLeft = 3, + BottomRight = 4, + BottomMiddle = 5, + MiddleLeft = 6, + MiddleRight = 7, + LeftOfCaption = 8, + RightOfCaption = 9, + LeftOfLastButton = 10, + RightOfLastButton = 11, + AboveLastButton = 12, + BelowLastButton = 13 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/PointProperty.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/PointProperty.cs new file mode 100644 index 0000000..fe6aa62 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/PointProperty.cs @@ -0,0 +1,42 @@ +// +// PointProperty.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum PointProperty + { + Offset = 3401, + TextShadowOffset = 3402, + MinSize = 3403, + MinSize1 = 3404, + MinSize2 = 3405, + MinSize3 = 3406, + MinSize4 = 3407, + MinSize5 = 3408 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/PushButtonState.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/PushButtonState.cs new file mode 100644 index 0000000..8fff333 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/PushButtonState.cs @@ -0,0 +1,39 @@ +// +// PushButtonState.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum PushButtonState + { + Normal = 1, + Hot = 2, + Pressed = 3, + Disabled = 4, + Default = 5 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/RadioButtonState.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/RadioButtonState.cs new file mode 100644 index 0000000..328712f --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/RadioButtonState.cs @@ -0,0 +1,42 @@ +// +// RadioButtonState.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum RadioButtonState + { + UncheckedNormal = 1, + UncheckedHot = 2, + UncheckedPressed = 3, + UncheckedDisabled = 4, + CheckedNormal = 5, + CheckedHot = 6, + CheckedPressed = 7, + CheckedDisabled = 8 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/ScrollBarArrowButtonState.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/ScrollBarArrowButtonState.cs new file mode 100644 index 0000000..85872a0 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/ScrollBarArrowButtonState.cs @@ -0,0 +1,50 @@ +// +// ScrollBarArrowButtonState.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum ScrollBarArrowButtonState + { + UpNormal = 1, + UpHot = 2, + UpPressed = 3, + UpDisabled = 4, + DownNormal = 5, + DownHot = 6, + DownPressed = 7, + DownDisabled = 8, + LeftNormal = 9, + LeftHot = 10, + LeftPressed = 11, + LeftDisabled = 12, + RightNormal = 13, + RightHot = 14, + RightPressed = 15, + RightDisabled = 16 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/ScrollBarSizeBoxState.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/ScrollBarSizeBoxState.cs new file mode 100644 index 0000000..17f974b --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/ScrollBarSizeBoxState.cs @@ -0,0 +1,36 @@ +// +// ScrollBarSizeBoxState.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum ScrollBarSizeBoxState + { + RightAlign = 1, + LeftAlign = 2 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/ScrollBarState.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/ScrollBarState.cs new file mode 100644 index 0000000..b362609 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/ScrollBarState.cs @@ -0,0 +1,38 @@ +// +// ScrollBarState.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum ScrollBarState + { + Normal = 1, + Hot = 2, + Pressed = 3, + Disabled = 4 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/SizingType.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/SizingType.cs new file mode 100644 index 0000000..194763f --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/SizingType.cs @@ -0,0 +1,37 @@ +// +// SizingType.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum SizingType + { + FixedSize = 0, + Stretch = 1, + Tile = 2 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/StringProperty.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/StringProperty.cs new file mode 100644 index 0000000..652916a --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/StringProperty.cs @@ -0,0 +1,35 @@ +// +// StringProperty.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum StringProperty + { + Text = 3201 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/TabItemState.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/TabItemState.cs new file mode 100644 index 0000000..b9ed0aa --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/TabItemState.cs @@ -0,0 +1,38 @@ +// +// TabItemState.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum TabItemState + { + Normal = 1, + Hot = 2, + Selected = 3, + Disabled = 4 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/TextBoxState.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/TextBoxState.cs new file mode 100644 index 0000000..0ec064c --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/TextBoxState.cs @@ -0,0 +1,40 @@ +// +// TextBoxState.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum TextBoxState + { + Normal = 1, + Hot = 2, + Selected = 3, + Disabled = 4, + Readonly = 6, + Assist = 7 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/TextMetrics.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/TextMetrics.cs new file mode 100644 index 0000000..2e25adf --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/TextMetrics.cs @@ -0,0 +1,158 @@ +// +// TextMetrics.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public struct TextMetrics + { + #region Private Variables + private int ascent; + private int average_char_width; + private char break_char; + private TextMetricsCharacterSet char_set; + private char default_char; + private int descent; + private int digitized_aspect_x; + private int digitized_aspect_y; + private int external_leading; + private char first_char; + private int height; + private int internal_leading; + private bool italic; + private char last_char; + private int max_char_width; + private int overhang; + private TextMetricsPitchAndFamilyValues pitch_and_family; + private bool struck_out; + private bool underlined; + private int weight; + #endregion + + #region Public Properties + public int Ascent { + get { return this.ascent; } + set { this.ascent = value; } + } + + public int AverageCharWidth { + get { return this.average_char_width; } + set { this.average_char_width = value; } + } + + public char BreakChar { + get { return this.break_char; } + set { this.break_char = value; } + } + + public TextMetricsCharacterSet CharSet { + get { return this.char_set; } + set { this.char_set = value; } + } + + public char DefaultChar { + get { return this.default_char; } + set { this.default_char = value; } + } + + public int Descent { + get { return this.descent; } + set { this.descent = value; } + } + + public int DigitizedAspectX { + get { return this.digitized_aspect_x; } + set { this.digitized_aspect_x = value; } + } + + public int DigitizedAspectY { + get { return this.digitized_aspect_y; } + set { this.digitized_aspect_y = value; } + } + + public int ExternalLeading { + get { return this.external_leading; } + set { this.external_leading = value; } + } + + public char FirstChar { + get { return this.first_char; } + set { this.first_char = value; } + } + + public int Height { + get { return this.height; } + set { this.height = value; } + } + + public int InternalLeading { + get { return this.internal_leading; } + set { this.internal_leading = value; } + } + + public bool Italic { + get { return this.italic; } + set { this.italic = value; } + } + + public char LastChar { + get { return this.last_char; } + set { this.last_char = value; } + } + + public int MaxCharWidth { + get { return this.max_char_width; } + set { this.max_char_width = value; } + } + + public int Overhang { + get { return this.overhang; } + set { this.overhang = value; } + } + + public TextMetricsPitchAndFamilyValues PitchAndFamily { + get { return this.pitch_and_family; } + set { this.pitch_and_family = value; } + } + + public bool StruckOut { + get { return this.struck_out; } + set { this.struck_out = value; } + } + + public bool Underlined { + get { return this.underlined; } + set { this.underlined = value; } + } + + public int Weight { + get { return this.weight; } + set { this.weight = value; } + } + #endregion + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/TextMetricsCharacterSet.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/TextMetricsCharacterSet.cs new file mode 100644 index 0000000..b512078 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/TextMetricsCharacterSet.cs @@ -0,0 +1,53 @@ +// +// TextMetricsCharacterSet.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum TextMetricsCharacterSet + { + Ansi = 0, + Default = 1, + Symbol = 2, + Mac = 77, + ShiftJis = 128, + Hangul = 129, + Johab = 130, + Gb2312 = 134, + ChineseBig5 = 136, + Greek = 161, + Turkish = 162, + Vietnamese = 163, + Hebrew = 177, + Arabic = 178, + Baltic = 186, + Russian = 204, + Thai = 222, + EastEurope = 238, + Oem = 255 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/TextMetricsPitchAndFamilyValues.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/TextMetricsPitchAndFamilyValues.cs new file mode 100644 index 0000000..dbfa5dc --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/TextMetricsPitchAndFamilyValues.cs @@ -0,0 +1,40 @@ +// +// TextMetricsPitchAndFamilyValues.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI.VisualStyles +{ + [Flags] + public enum TextMetricsPitchAndFamilyValues + { + FixedPitch = 1, + Vector = 2, + TrueType = 4, + Device = 8 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/TextShadowType.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/TextShadowType.cs new file mode 100644 index 0000000..10fb885 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/TextShadowType.cs @@ -0,0 +1,37 @@ +// +// TextShadowType.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum TextShadowType + { + None = 0, + Single = 1, + Continuous = 2 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/ThemeSizeType.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/ThemeSizeType.cs new file mode 100644 index 0000000..46175dd --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/ThemeSizeType.cs @@ -0,0 +1,37 @@ +// +// ThemeSizeType.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum ThemeSizeType + { + Minimum = 0, + True = 1, + Draw = 2 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/ToolBarState.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/ToolBarState.cs new file mode 100644 index 0000000..b38c7df --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/ToolBarState.cs @@ -0,0 +1,40 @@ +// +// ToolBarState.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum ToolBarState + { + Normal = 1, + Hot = 2, + Pressed = 3, + Disabled = 4, + Checked = 5, + HotChecked = 6 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/TrackBarThumbState.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/TrackBarThumbState.cs new file mode 100644 index 0000000..fd45443 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/TrackBarThumbState.cs @@ -0,0 +1,38 @@ +// +// TrackBarThumbState.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum TrackBarThumbState + { + Normal = 1, + Hot = 2, + Pressed = 3, + Disabled = 5 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/TrueSizeScalingType.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/TrueSizeScalingType.cs new file mode 100644 index 0000000..09126ff --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/TrueSizeScalingType.cs @@ -0,0 +1,37 @@ +// +// TrueSizeScalingType.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum TrueSizeScalingType + { + None = 0, + Size = 1, + Dpi = 2 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/UXTheme.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/UXTheme.cs new file mode 100644 index 0000000..1f88409 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/UXTheme.cs @@ -0,0 +1,216 @@ +// +// UXTheme.cs +// - Internal class for P/Invokes to uxtheme.dll +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Runtime.InteropServices; +using System.Drawing; +using System.Text; +using ShiftUI; +using System; + +namespace ShiftUI.VisualStyles +{ + internal class UXTheme + { + #region DllImports + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 CloseThemeData (IntPtr hTheme); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 DrawThemeBackground (IntPtr hTheme, IntPtr hdc, int iPartId, + int iStateId, ref XplatUIWin32.RECT pRect, ref XplatUIWin32.RECT pClipRect); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 DrawThemeBackground (IntPtr hTheme, IntPtr hdc, int iPartId, + int iStateId, ref XplatUIWin32.RECT pRect, IntPtr pClipRect); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 DrawThemeEdge (IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, ref XplatUIWin32.RECT pDestRect, uint egde, uint flags, out XplatUIWin32.RECT pRect); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 DrawThemeEdge (IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, ref XplatUIWin32.RECT pDestRect, uint edge, uint flags, int pRect); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 DrawThemeIcon (IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, ref XplatUIWin32.RECT pRect, IntPtr himl, int iImageIndex); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 DrawThemeParentBackground (IntPtr hWnd, IntPtr hdc, ref XplatUIWin32.RECT pRect); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 DrawThemeParentBackground (IntPtr hWnd, IntPtr hdc, int pRect); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 DrawThemeText (IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, String text, int textLength, UInt32 textFlags, UInt32 textFlags2, ref XplatUIWin32.RECT pRect); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 EnableTheming (int fEnable); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public static extern IntPtr OpenThemeData (IntPtr hWnd, String classList); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemeBackgroundContentRect (IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, ref XplatUIWin32.RECT pBoundingRect, out XplatUIWin32.RECT pContentRect); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemeBackgroundExtent (IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, ref XplatUIWin32.RECT pRect, ref XplatUIWin32.RECT pClipRect); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemeBackgroundRegion (IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, ref XplatUIWin32.RECT pRect, out IntPtr pRegion); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemeBool (IntPtr hTheme, int iPartId, int iStateId, int iPropId, out int pfVal); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemeColor (IntPtr hTheme, int iPartId, int iStateId, int iPropId, out Int32 pColor); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemeEnumValue (IntPtr hTheme, int iPartId, int iStateId, int iPropId, out int piVal); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemeFilename (IntPtr hTheme, int iPartId, int iStateId, int iPropId, [MarshalAs (UnmanagedType.LPWStr)] System.Text.StringBuilder themeFileName, int themeFileNameLength); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemeFont (IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, int iPropId, [MarshalAs (UnmanagedType.LPStruct)] out LOGFONT lf); + + [DllImport ("gdi32", CharSet = CharSet.Auto)] + public static extern IntPtr CreateFontIndirect ([In, MarshalAs (UnmanagedType.LPStruct)] LOGFONT lplf); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemeInt (IntPtr hTheme, int iPartId, int iStateId, int iPropId, out int piVal); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemeMargins (IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, int iPropId, out XplatUIWin32.RECT prc, out MARGINS pMargins); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemePartSize (IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, ref XplatUIWin32.RECT pRect, int eSize, out SIZE size); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemePartSize (IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, IntPtr pRect, int eSize, out SIZE size); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemePosition (IntPtr hTheme, int iPartId, int iStateId, int iPropId, out POINT pPoint); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemeString (IntPtr hTheme, int iPartId, int iStateId, int iPropId, [MarshalAs (UnmanagedType.LPWStr)] StringBuilder themeString, int themeStringLength); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemeTextExtent (IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, String text, int textLength, int textFlags, ref XplatUIWin32.RECT boundingRect, out XplatUIWin32.RECT extentRect); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemeTextExtent (IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, String text, int textLength, int textFlags, int boundingRect, out XplatUIWin32.RECT extentRect); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemeTextMetrics (IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, out XplatUIWin32.TEXTMETRIC textMetric); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 HitTestThemeBackground (IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, UInt32 dwOptions, ref XplatUIWin32.RECT pRect, IntPtr hrgn, POINT ptTest, out HitTestCode code); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static int IsThemeBackgroundPartiallyTransparent (IntPtr hTheme, int iPartId, int iStateId); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static bool IsThemePartDefined (IntPtr hTheme, int iPartId, int iStateId); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static bool IsThemeActive (); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static bool IsAppThemed (); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 HitTestThemeBackground (IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, UInt32 dwOptions, ref XplatUIWin32.RECT pRect, IntPtr hrgn, POINT ptTest, out int code); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemeDocumentationProperty (String stringThemeName, String stringPropertyName, StringBuilder stringValue, int lengthValue); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetCurrentThemeName (StringBuilder stringThemeName, int lengthThemeName, StringBuilder stringColorName, int lengthColorName, StringBuilder stringSizeName, int lengthSizeName); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static UInt32 GetThemeSysColor (IntPtr hTheme, int iColorId); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static Int32 GetThemeSysInt (IntPtr hTheme, int iIntId, out int piVal); + + [DllImport ("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] + public extern static int GetThemeSysBool (IntPtr hTheme, int iBoolId); + #endregion + + #region LOGFONT Type + [StructLayout (LayoutKind.Sequential, CharSet = CharSet.Auto)] + public class LOGFONT + { + public int lfHeight = 0; + public int lfWidth = 0; + public int lfEscapement = 0; + public int lfOrientation = 0; + public int lfWeight = 0; + public byte lfItalic = 0; + public byte lfUnderline = 0; + public byte lfStrikeOut = 0; + public byte lfCharSet = 0; + public byte lfOutPrecision = 0; + public byte lfClipPrecision = 0; + public byte lfQuality = 0; + public byte lfPitchAndFamily = 0; + [MarshalAs (UnmanagedType.ByValTStr, SizeConst = 32)] + public string lfFaceName = string.Empty; + } + #endregion + + #region MARGINS Type + [StructLayout (LayoutKind.Sequential)] + public struct MARGINS + { + public int leftWidth; + public int rightWidth; + public int topHeight; + public int bottomHeight; + + public Padding ToPadding () + { + return new Padding (leftWidth, topHeight, rightWidth, bottomHeight); + } + } + #endregion + + #region SIZE Type + [StructLayout (LayoutKind.Sequential)] + public struct SIZE + { + public int cx; + public int cy; + + public Size ToSize () + { + return new Size (cx, cy); + } + } + #endregion + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/VerticalAlignment.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/VerticalAlignment.cs new file mode 100644 index 0000000..b1862f4 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/VerticalAlignment.cs @@ -0,0 +1,37 @@ +// +// VerticalAlignment.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum VerticalAlignment + { + Top = 0, + Center = 1, + Bottom = 2 + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStyleElement.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStyleElement.cs new file mode 100644 index 0000000..4e79689 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStyleElement.cs @@ -0,0 +1,2714 @@ +// +// VisualStyleElement.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public class VisualStyleElement + { + #region Private Variables + #region Class name/part/state constants + private const string BUTTON = "BUTTON"; + private const string CLOCK = "CLOCK"; + private const string COMBOBOX = "COMBOBOX"; + #region DATEPICKER + const string DATEPICKER = "DATEPICKER"; + enum DATEPICKERPARTS + { + DP_DATEBORDER = 2, + DP_SHOWCALENDARBUTTONRIGHT + } + enum DATEBORDERSTATES + { + DPDB_NORMAL = 1, + DPDB_HOT, + DPDB_FOCUSED, + DPDB_DISABLED + } + enum SHOWCALENDARBUTTONRIGHTSTATES + { + DPSCBR_NORMAL = 1, + DPSCBR_HOT, + DPSCBR_PRESSED, + DPSCBR_DISABLED + } + #endregion + private const string EDIT = "EDIT"; + private const string EXPLORERBAR = "EXPLORERBAR"; + private const string HEADER = "HEADER"; + private const string LISTVIEW = "LISTVIEW"; + private const string MENU = "MENU"; + private const string MENUBAND = "MENUBAND"; + private const string PAGE = "PAGE"; + private const string PROGRESS = "PROGRESS"; + private const string REBAR = "REBAR"; + private const string SCROLLBAR = "SCROLLBAR"; + private const string SPIN = "SPIN"; + private const string STARTPANEL = "STARTPANEL"; + private const string STATUS = "STATUS"; + private const string TAB = "TAB"; + private const string TASKBAND = "TASKBAND"; + private const string TASKBAR = "TASKBAR"; + private const string TOOLBAR = "TOOLBAR"; + private const string TOOLTIP = "TOOLTIP"; + private const string TRACKBAR = "TRACKBAR"; + private const string TRAYNOTIFY = "TRAYNOTIFY"; + private const string TREEVIEW = "TREEVIEW"; + private const string WINDOW = "WINDOW"; + #endregion + + private string class_name; + private int part; + private int state; + #endregion + + #region Constructors/Deconstructors + internal VisualStyleElement (string className, int part, int state) + { + this.class_name = className; + this.part = part; + this.state = state; + } + #endregion + + #region Public Instance Properties + public string ClassName { get { return this.class_name; } } + public int Part { get { return this.part; } } + public int State { get { return this.state; } } + #endregion + + #region Public Static Methods + public static VisualStyleElement CreateElement (string className, int part, int state) + { + return new VisualStyleElement (className, part, state); + } + #endregion + + #region Static Classes + #region Button + public static class Button + { + public static class CheckBox + { + public static VisualStyleElement CheckedDisabled { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_CHECKBOX, + (int)CHECKBOXSTATES.CBS_CHECKEDDISABLED); + } + } + public static VisualStyleElement CheckedHot { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_CHECKBOX, + (int)CHECKBOXSTATES.CBS_CHECKEDHOT); + } + } + public static VisualStyleElement CheckedNormal { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_CHECKBOX, + (int)CHECKBOXSTATES.CBS_CHECKEDNORMAL); + } + } + public static VisualStyleElement CheckedPressed { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_CHECKBOX, + (int)CHECKBOXSTATES.CBS_CHECKEDPRESSED); + } + } + public static VisualStyleElement MixedDisabled { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_CHECKBOX, + (int)CHECKBOXSTATES.CBS_MIXEDDISABLED); + } + } + public static VisualStyleElement MixedHot { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_CHECKBOX, + (int)CHECKBOXSTATES.CBS_MIXEDHOT); + } + } + public static VisualStyleElement MixedNormal { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_CHECKBOX, + (int)CHECKBOXSTATES.CBS_MIXEDNORMAL); + } + } + public static VisualStyleElement MixedPressed { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_CHECKBOX, + (int)CHECKBOXSTATES.CBS_MIXEDPRESSED); + } + } + public static VisualStyleElement UncheckedDisabled { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_CHECKBOX, + (int)CHECKBOXSTATES.CBS_UNCHECKEDDISABLED); + } + } + public static VisualStyleElement UncheckedHot { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_CHECKBOX, + (int)CHECKBOXSTATES.CBS_UNCHECKEDHOT); + } + } + public static VisualStyleElement UncheckedNormal { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_CHECKBOX, + (int)CHECKBOXSTATES.CBS_UNCHECKEDNORMAL); + } + } + public static VisualStyleElement UncheckedPressed { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_CHECKBOX, + (int)CHECKBOXSTATES.CBS_UNCHECKEDPRESSED); + } + } + } + public static class GroupBox + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_GROUPBOX, + (int)GROUPBOXSTATES.GBS_DISABLED); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_GROUPBOX, + (int)GROUPBOXSTATES.GBS_NORMAL); + } + } + } + public static class PushButton + { + public static VisualStyleElement Default { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_PUSHBUTTON, + (int)PUSHBUTTONSTATES.PBS_DEFAULTED); + } + } + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_PUSHBUTTON, + (int)PUSHBUTTONSTATES.PBS_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_PUSHBUTTON, + (int)PUSHBUTTONSTATES.PBS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_PUSHBUTTON, + (int)PUSHBUTTONSTATES.PBS_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_PUSHBUTTON, + (int)PUSHBUTTONSTATES.PBS_PRESSED); + } + } + } + public static class RadioButton + { + public static VisualStyleElement CheckedDisabled { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_RADIOBUTTON, + (int)RADIOBUTTONSTATES.RBS_CHECKEDDISABLED); + } + } + public static VisualStyleElement CheckedHot { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_RADIOBUTTON, + (int)RADIOBUTTONSTATES.RBS_CHECKEDHOT); + } + } + public static VisualStyleElement CheckedNormal { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_RADIOBUTTON, + (int)RADIOBUTTONSTATES.RBS_CHECKEDNORMAL); + } + } + public static VisualStyleElement CheckedPressed { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_RADIOBUTTON, + (int)RADIOBUTTONSTATES.RBS_CHECKEDPRESSED); + } + } + public static VisualStyleElement UncheckedDisabled { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_RADIOBUTTON, + (int)RADIOBUTTONSTATES.RBS_UNCHECKEDDISABLED); + } + } + public static VisualStyleElement UncheckedHot { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_RADIOBUTTON, + (int)RADIOBUTTONSTATES.RBS_UNCHECKEDHOT); + } + } + public static VisualStyleElement UncheckedNormal { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_RADIOBUTTON, + (int)RADIOBUTTONSTATES.RBS_UNCHECKEDNORMAL); + } + } + public static VisualStyleElement UncheckedPressed { + get { + return VisualStyleElement.CreateElement ( + BUTTON, + (int)BUTTONPARTS.BP_RADIOBUTTON, + (int)RADIOBUTTONSTATES.RBS_UNCHECKEDPRESSED); + } + } + } + public static class UserButton + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.BUTTON, 5, 0); } } + } + } + #endregion + #region ComboBox + public static class ComboBox + { + public static class DropDownButton + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + COMBOBOX, + (int)COMBOBOXPARTS.CP_DROPDOWNBUTTON, + (int)COMBOBOXSTYLESTATES.CBXS_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + COMBOBOX, + (int)COMBOBOXPARTS.CP_DROPDOWNBUTTON, + (int)COMBOBOXSTYLESTATES.CBXS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + COMBOBOX, + (int)COMBOBOXPARTS.CP_DROPDOWNBUTTON, + (int)COMBOBOXSTYLESTATES.CBXS_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + COMBOBOX, + (int)COMBOBOXPARTS.CP_DROPDOWNBUTTON, + (int)COMBOBOXSTYLESTATES.CBXS_PRESSED); + } + } + } + internal static class Border + { + public static VisualStyleElement Normal { + get { + return new VisualStyleElement ( + COMBOBOX, + (int)COMBOBOXPARTS.CP_BORDER, + (int)BORDERSTATES.CBB_NORMAL); + } + } + public static VisualStyleElement Hot { + get { + return new VisualStyleElement ( + COMBOBOX, + (int)COMBOBOXPARTS.CP_BORDER, + (int)BORDERSTATES.CBB_HOT); + } + } + public static VisualStyleElement Focused { + get { + return new VisualStyleElement ( + COMBOBOX, + (int)COMBOBOXPARTS.CP_BORDER, + (int)BORDERSTATES.CBB_FOCUSED); + } + } + public static VisualStyleElement Disabled { + get { + return new VisualStyleElement ( + COMBOBOX, + (int)COMBOBOXPARTS.CP_BORDER, + (int)BORDERSTATES.CBB_DISABLED); + } + } + } + } + #endregion + #region DatePicker + internal static class DatePicker + { + public static class DateBorder + { + public static VisualStyleElement Normal { + get { + return new VisualStyleElement ( + DATEPICKER, + (int)DATEPICKERPARTS.DP_DATEBORDER, + (int)DATEBORDERSTATES.DPDB_NORMAL); + } + } + public static VisualStyleElement Hot { + get { + return new VisualStyleElement ( + DATEPICKER, + (int)DATEPICKERPARTS.DP_DATEBORDER, + (int)DATEBORDERSTATES.DPDB_HOT); + } + } + public static VisualStyleElement Focused { + get { + return new VisualStyleElement ( + DATEPICKER, + (int)DATEPICKERPARTS.DP_DATEBORDER, + (int)DATEBORDERSTATES.DPDB_FOCUSED); + } + } + public static VisualStyleElement Disabled { + get { + return new VisualStyleElement ( + DATEPICKER, + (int)DATEPICKERPARTS.DP_DATEBORDER, + (int)DATEBORDERSTATES.DPDB_DISABLED); + } + } + } + public static class ShowCalendarButtonRight + { + public static VisualStyleElement Normal { + get { + return new VisualStyleElement ( + DATEPICKER, + (int)DATEPICKERPARTS.DP_SHOWCALENDARBUTTONRIGHT, + (int)SHOWCALENDARBUTTONRIGHTSTATES.DPSCBR_NORMAL); + } + } + public static VisualStyleElement Hot { + get { + return new VisualStyleElement ( + DATEPICKER, + (int)DATEPICKERPARTS.DP_SHOWCALENDARBUTTONRIGHT, + (int)SHOWCALENDARBUTTONRIGHTSTATES.DPSCBR_HOT); + } + } + public static VisualStyleElement Pressed { + get { + return new VisualStyleElement ( + DATEPICKER, + (int)DATEPICKERPARTS.DP_SHOWCALENDARBUTTONRIGHT, + (int)SHOWCALENDARBUTTONRIGHTSTATES.DPSCBR_PRESSED); + } + } + public static VisualStyleElement Disabled { + get { + return new VisualStyleElement ( + DATEPICKER, + (int)DATEPICKERPARTS.DP_SHOWCALENDARBUTTONRIGHT, + (int)SHOWCALENDARBUTTONRIGHTSTATES.DPSCBR_DISABLED); + } + } + } + } + #endregion + #region ExplorerBar + public static class ExplorerBar + { + public static class HeaderBackground + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 1, 0); } } + } + public static class HeaderClose + { + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 2, 1); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 2, 2); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 2, 3); } } + } + public static class HeaderPin + { + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 3, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 3, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 3, 3); } } + public static VisualStyleElement SelectedHot { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 3, 5); } } + public static VisualStyleElement SelectedNormal { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 3, 4); } } + public static VisualStyleElement SelectedPressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 3, 6); } } + } + public static class IEBarMenu + { + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 4, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 4, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 4, 3); } } + } + public static class NormalGroupBackground + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 5, 0); } } + } + public static class NormalGroupCollapse + { + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 6, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 6, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 6, 3); } } + } + public static class NormalGroupExpand + { + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 7, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 7, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 7, 3); } } + } + public static class NormalGroupHead + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 8, 0); } } + } + public static class SpecialGroupBackground + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 9, 0); } } + } + public static class SpecialGroupCollapse + { + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 10, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 10, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 10, 3); } } + } + public static class SpecialGroupExpand + { + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 11, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 11, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 11, 3); } } + } + public static class SpecialGroupHead + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.EXPLORERBAR, 12, 0); } } + } + } + #endregion + #region Header + public static class Header + { + public static class Item + { + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + HEADER, + (int)HEADERPARTS.HP_HEADERITEM, + (int)HEADERITEMSTATES.HIS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + HEADER, + (int)HEADERPARTS.HP_HEADERITEM, + (int)HEADERITEMSTATES.HIS_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + HEADER, + (int)HEADERPARTS.HP_HEADERITEM, + (int)HEADERITEMSTATES.HIS_PRESSED); + } + } + } + public static class ItemLeft + { + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.HEADER, 2, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.HEADER, 2, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.HEADER, 2, 3); } } + } + public static class ItemRight + { + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.HEADER, 3, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.HEADER, 3, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.HEADER, 3, 3); } } + } + public static class SortArrow + { + public static VisualStyleElement SortedDown { get { return VisualStyleElement.CreateElement (VisualStyleElement.HEADER, 4, 2); } } + public static VisualStyleElement SortedUp { get { return VisualStyleElement.CreateElement (VisualStyleElement.HEADER, 4, 1); } } + } + } + #endregion + #region ListView + public static class ListView + { + public static class Detail + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.LISTVIEW, 3, 0); } } + } + public static class EmptyText + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.LISTVIEW, 5, 0); } } + } + public static class Group + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.LISTVIEW, 2, 0); } } + } + public static class Item + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.LISTVIEW, 1, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.LISTVIEW, 1, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.LISTVIEW, 1, 1); } } + public static VisualStyleElement Selected { get { return VisualStyleElement.CreateElement (VisualStyleElement.LISTVIEW, 1, 3); } } + public static VisualStyleElement SelectedNotFocus { get { return VisualStyleElement.CreateElement (VisualStyleElement.LISTVIEW, 1, 5); } } + } + public static class SortedDetail + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.LISTVIEW, 4, 0); } } + } + } + #endregion + #region Menu + public static class Menu + { + public static class BarDropDown + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.MENU, 4, 0); } } + } + public static class BarItem + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.MENU, 3, 0); } } + } + public static class Chevron + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.MENU, 5, 0); } } + } + public static class DropDown + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.MENU, 2, 0); } } + } + public static class Item + { + public static VisualStyleElement Demoted { get { return VisualStyleElement.CreateElement (VisualStyleElement.MENU, 1, 3); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.MENU, 1, 1); } } + public static VisualStyleElement Selected { get { return VisualStyleElement.CreateElement (VisualStyleElement.MENU, 1, 2); } } + } + public static class Separator + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.MENU, 6, 0); } } + } + } + #endregion + #region MenuBand + public static class MenuBand + { + public static class NewApplicationButton + { + public static VisualStyleElement Checked { get { return VisualStyleElement.CreateElement (VisualStyleElement.MENUBAND, 1, 5); } } + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.MENUBAND, 1, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.MENUBAND, 1, 2); } } + public static VisualStyleElement HotChecked { get { return VisualStyleElement.CreateElement (VisualStyleElement.MENUBAND, 1, 6); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.MENUBAND, 1, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.MENUBAND, 1, 3); } } + } + public static class Separator + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.MENUBAND, 2, 0); } } + } + } + #endregion + #region Page + public static class Page + { + public static class Down + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.PAGE, 2, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.PAGE, 2, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.PAGE, 2, 3); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.PAGE, 2, 1); } } + } + public static class DownHorizontal + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.PAGE, 4, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.PAGE, 4, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.PAGE, 4, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.PAGE, 4, 3); } } + } + public static class Up + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.PAGE, 1, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.PAGE, 1, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.PAGE, 1, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.PAGE, 1, 3); } } + } + public static class UpHorizontal + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.PAGE, 3, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.PAGE, 3, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.PAGE, 3, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.PAGE, 3, 3); } } + } + } + #endregion + #region ProgressBar + public static class ProgressBar + { + public static class Bar + { + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + PROGRESS, + (int)PROGRESSPARTS.PP_BAR, + 0); + } + } + } + public static class BarVertical + { + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + PROGRESS, + (int)PROGRESSPARTS.PP_BARVERT, + 0); + } + } + } + public static class Chunk + { + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + PROGRESS, + (int)PROGRESSPARTS.PP_CHUNK, + 0); + } + } + } + public static class ChunkVertical + { + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + PROGRESS, + (int)PROGRESSPARTS.PP_CHUNKVERT, + 0); + } + } + } + } + #endregion + #region Rebar + public static class Rebar + { + public static class Band + { + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + REBAR, + (int)REBARPARTS.RP_BAND, + 0); + } + } + } + public static class Chevron + { + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.REBAR, 4, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.REBAR, 4, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.REBAR, 4, 3); } } + } + public static class ChevronVertical + { + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.REBAR, 5, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.REBAR, 5, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.REBAR, 5, 3); } } + } + public static class Gripper + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.REBAR, 1, 0); } } + } + public static class GripperVertical + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.REBAR, 2, 0); } } + } + } + #endregion + #region ScrollBar + public static class ScrollBar + { + public static class ArrowButton + { + public static VisualStyleElement DownDisabled { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_DOWNDISABLED); + } + } + public static VisualStyleElement DownHot { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_DOWNHOT); + } + } + public static VisualStyleElement DownNormal { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_DOWNNORMAL); + } + } + public static VisualStyleElement DownPressed { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_DOWNPRESSED); + } + } + public static VisualStyleElement LeftDisabled { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_LEFTDISABLED); + } + } + public static VisualStyleElement LeftHot { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_LEFTHOT); + } + } + public static VisualStyleElement LeftNormal { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_LEFTNORMAL); + } + } + public static VisualStyleElement LeftPressed { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_LEFTPRESSED); + } + } + public static VisualStyleElement RightDisabled { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_RIGHTDISABLED); + } + } + public static VisualStyleElement RightHot { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_RIGHTHOT); + } + } + public static VisualStyleElement RightNormal { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_RIGHTNORMAL); + } + } + public static VisualStyleElement RightPressed { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_RIGHTPRESSED); + } + } + public static VisualStyleElement UpDisabled { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_UPDISABLED); + } + } + public static VisualStyleElement UpHot { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_UPHOT); + } + } + public static VisualStyleElement UpNormal { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_UPNORMAL); + } + } + public static VisualStyleElement UpPressed { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_UPPRESSED); + } + } + internal static VisualStyleElement DownHover { + get { + return new VisualStyleElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_DOWNHOVER); + } + } + internal static VisualStyleElement LeftHover { + get { + return new VisualStyleElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_LEFTHOVER); + } + } + internal static VisualStyleElement RightHover { + get { + return new VisualStyleElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_RIGHTHOVER); + } + } + internal static VisualStyleElement UpHover { + get { + return new VisualStyleElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_ARROWBTN, + (int)ARROWBTNSTATES.ABS_UPHOVER); + } + } + } + public static class GripperHorizontal + { + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_GRIPPERHORZ, + 0); + } + } + } + public static class GripperVertical + { + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + VisualStyleElement.SCROLLBAR, + (int)SCROLLBARPARTS.SBP_GRIPPERVERT, + 0); + } + } + } + public static class LeftTrackHorizontal + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_UPPERTRACKHORZ, + (int)SCROLLBARSTYLESTATES.SCRBS_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_UPPERTRACKHORZ, + (int)SCROLLBARSTYLESTATES.SCRBS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_UPPERTRACKHORZ, + (int)SCROLLBARSTYLESTATES.SCRBS_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_UPPERTRACKHORZ, + (int)SCROLLBARSTYLESTATES.SCRBS_PRESSED); + } + } + } + public static class LowerTrackVertical + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_LOWERTRACKVERT, + (int)SCROLLBARSTYLESTATES.SCRBS_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_LOWERTRACKVERT, + (int)SCROLLBARSTYLESTATES.SCRBS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_LOWERTRACKVERT, + (int)SCROLLBARSTYLESTATES.SCRBS_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_LOWERTRACKVERT, + (int)SCROLLBARSTYLESTATES.SCRBS_PRESSED); + } + } + } + public static class RightTrackHorizontal + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_LOWERTRACKHORZ, + (int)SCROLLBARSTYLESTATES.SCRBS_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_LOWERTRACKHORZ, + (int)SCROLLBARSTYLESTATES.SCRBS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_LOWERTRACKHORZ, + (int)SCROLLBARSTYLESTATES.SCRBS_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_LOWERTRACKHORZ, + (int)SCROLLBARSTYLESTATES.SCRBS_PRESSED); + } + } + } + public static class SizeBox + { + public static VisualStyleElement LeftAlign { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_SIZEBOX, + (int)SIZEBOXSTATES.SZB_LEFTALIGN); + } + } + public static VisualStyleElement RightAlign { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_SIZEBOX, + (int)SIZEBOXSTATES.SZB_RIGHTALIGN); + } + } + } + public static class ThumbButtonHorizontal + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_THUMBBTNHORZ, + (int)SCROLLBARSTYLESTATES.SCRBS_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_THUMBBTNHORZ, + (int)SCROLLBARSTYLESTATES.SCRBS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_THUMBBTNHORZ, + 1); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_THUMBBTNHORZ, + (int)SCROLLBARSTYLESTATES.SCRBS_PRESSED); + } + } + } + public static class ThumbButtonVertical + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_THUMBBTNVERT, + (int)SCROLLBARSTYLESTATES.SCRBS_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_THUMBBTNVERT, + (int)SCROLLBARSTYLESTATES.SCRBS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_THUMBBTNVERT, + (int)SCROLLBARSTYLESTATES.SCRBS_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_THUMBBTNVERT, + (int)SCROLLBARSTYLESTATES.SCRBS_PRESSED); + } + } + } + public static class UpperTrackVertical + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_UPPERTRACKVERT, + (int)SCROLLBARSTYLESTATES.SCRBS_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_UPPERTRACKVERT, + (int)SCROLLBARSTYLESTATES.SCRBS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_UPPERTRACKVERT, + (int)SCROLLBARSTYLESTATES.SCRBS_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + SCROLLBAR, + (int)SCROLLBARPARTS.SBP_UPPERTRACKVERT, + (int)SCROLLBARSTYLESTATES.SCRBS_PRESSED); + } + } + } + } + #endregion + #region Spin + public static class Spin + { + public static class Down + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + SPIN, + (int)SPINPARTS.SPNP_DOWN, + (int)DOWNSTATES.DNS_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + SPIN, + (int)SPINPARTS.SPNP_DOWN, + (int)DOWNSTATES.DNS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + SPIN, + (int)SPINPARTS.SPNP_DOWN, + (int)DOWNSTATES.DNS_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + SPIN, + (int)SPINPARTS.SPNP_DOWN, + (int)DOWNSTATES.DNS_PRESSED); + } + } + } + public static class DownHorizontal + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + SPIN, + (int)SPINPARTS.SPNP_DOWNHORZ, + (int)DOWNHORZSTATES.DNHZS_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + SPIN, + (int)SPINPARTS.SPNP_DOWNHORZ, + (int)DOWNHORZSTATES.DNHZS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + SPIN, + (int)SPINPARTS.SPNP_DOWNHORZ, + (int)DOWNHORZSTATES.DNHZS_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + SPIN, + (int)SPINPARTS.SPNP_DOWNHORZ, + (int)DOWNHORZSTATES.DNHZS_PRESSED); + } + } + } + public static class Up + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + SPIN, + (int)SPINPARTS.SPNP_UP, + (int)UPSTATES.UPS_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + SPIN, + (int)SPINPARTS.SPNP_UP, + (int)UPSTATES.UPS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + SPIN, + (int)SPINPARTS.SPNP_UP, + (int)UPSTATES.UPS_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + SPIN, + (int)SPINPARTS.SPNP_UP, + (int)UPSTATES.UPS_PRESSED); + } + } + } + public static class UpHorizontal + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + SPIN, + (int)SPINPARTS.SPNP_UPHORZ, + (int)UPHORZSTATES.UPHZS_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + SPIN, + (int)SPINPARTS.SPNP_UPHORZ, + (int)UPHORZSTATES.UPHZS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + SPIN, + (int)SPINPARTS.SPNP_UPHORZ, + (int)UPHORZSTATES.UPHZS_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + SPIN, + (int)SPINPARTS.SPNP_UPHORZ, + (int)UPHORZSTATES.UPHZS_PRESSED); + } + } + } + } + #endregion + #region StartPanel + public static class StartPanel + { + public static class LogOff + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.STARTPANEL, 8, 0); } } + } + public static class LogOffButtons + { + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.STARTPANEL, 9, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.STARTPANEL, 9, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.STARTPANEL, 9, 3); } } + } + public static class MorePrograms + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.STARTPANEL, 2, 0); } } + } + public static class MoreProgramsArrow + { + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.STARTPANEL, 3, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.STARTPANEL, 3, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.STARTPANEL, 3, 3); } } + } + public static class PlaceList + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.STARTPANEL, 6, 0); } } + } + public static class PlaceListSeparator + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.STARTPANEL, 7, 0); } } + } + public static class Preview + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.STARTPANEL, 11, 0); } } + } + public static class ProgList + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.STARTPANEL, 4, 0); } } + } + public static class ProgListSeparator + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.STARTPANEL, 5, 0); } } + } + public static class UserPane + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.STARTPANEL, 1, 0); } } + } + public static class UserPicture + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.STARTPANEL, 10, 0); } } + } + } + #endregion + #region Status + public static class Status + { + public static class Bar + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.STATUS, 0, 0); } } + } + public static class Gripper + { + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + STATUS, + (int)STATUSPARTS.SP_GRIPPER, + 0); + } + } + } + public static class GripperPane + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.STATUS, 2, 0); } } + } + public static class Pane + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.STATUS, 1, 0); } } + } + } + #endregion + #region Tab + public static class Tab + { + public static class Body + { + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_BODY, + 0); + } + } + } + public static class Pane + { + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_PANE, + 0); + } + } + } + public static class TabItem + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TABITEM, + (int)TABITEMSTATES.TIS_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TABITEM, + (int)TABITEMSTATES.TIS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TABITEM, + (int)TABITEMSTATES.TIS_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TABITEM, + (int)TABITEMSTATES.TIS_SELECTED); + } + } + } + public static class TabItemBothEdges + { + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TABITEMBOTHEDGE, + 0); + } + } + } + public static class TabItemLeftEdge + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TABITEMLEFTEDGE, + (int)TABITEMLEFTEDGESTATES.TILES_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TABITEMLEFTEDGE, + (int)TABITEMLEFTEDGESTATES.TILES_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TABITEMLEFTEDGE, + (int)TABITEMLEFTEDGESTATES.TILES_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TABITEMLEFTEDGE, + (int)TABITEMLEFTEDGESTATES.TILES_SELECTED); + } + } + } + public static class TabItemRightEdge + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TABITEMRIGHTEDGE, + (int)TABITEMRIGHTEDGESTATES.TIRES_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TABITEMRIGHTEDGE, + (int)TABITEMRIGHTEDGESTATES.TIRES_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TABITEMRIGHTEDGE, + (int)TABITEMRIGHTEDGESTATES.TIRES_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TABITEMRIGHTEDGE, + (int)TABITEMRIGHTEDGESTATES.TIRES_SELECTED); + } + } + } + public static class TopTabItem + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TOPTABITEM, + (int)TOPTABITEMSTATES.TTIS_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TOPTABITEM, + (int)TOPTABITEMSTATES.TTIS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TOPTABITEM, + (int)TOPTABITEMSTATES.TTIS_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TOPTABITEM, + (int)TOPTABITEMSTATES.TTIS_SELECTED); + } + } + } + public static class TopTabItemBothEdges + { + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TOPTABITEMBOTHEDGE, + 0); + } + } + } + public static class TopTabItemLeftEdge + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TOPTABITEMLEFTEDGE, + (int)TOPTABITEMLEFTEDGESTATES.TTILES_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TOPTABITEMLEFTEDGE, + (int)TOPTABITEMLEFTEDGESTATES.TTILES_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TOPTABITEMLEFTEDGE, + (int)TOPTABITEMLEFTEDGESTATES.TTILES_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TOPTABITEMLEFTEDGE, + (int)TOPTABITEMLEFTEDGESTATES.TTILES_SELECTED); + } + } + } + public static class TopTabItemRightEdge + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TOPTABITEMRIGHTEDGE, + (int)TOPTABITEMRIGHTEDGESTATES.TTIRES_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TOPTABITEMRIGHTEDGE, + (int)TOPTABITEMRIGHTEDGESTATES.TTIRES_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TOPTABITEMRIGHTEDGE, + (int)TOPTABITEMRIGHTEDGESTATES.TTIRES_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + TAB, + (int)TABPARTS.TABP_TOPTABITEMRIGHTEDGE, + (int)TOPTABITEMRIGHTEDGESTATES.TTIRES_SELECTED); + } + } + } + } + #endregion + #region TaskBand + public static class TaskBand + { + public static class FlashButton + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TASKBAND, 2, 0); } } + } + public static class FlashButtonGroupMenu + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TASKBAND, 3, 0); } } + } + public static class GroupCount + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TASKBAND, 1, 0); } } + } + } + #endregion + #region TaskBar + public static class Taskbar + { + public static class BackgroundBottom + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TASKBAR, 1, 0); } } + } + public static class BackgroundLeft + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TASKBAR, 4, 0); } } + } + public static class BackgroundRight + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TASKBAR, 2, 0); } } + } + public static class BackgroundTop + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TASKBAR, 3, 0); } } + } + public static class SizingBarBottom + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TASKBAR, 5, 0); } } + } + public static class SizingBarLeft + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TASKBAR, 8, 0); } } + } + public static class SizingBarRight + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TASKBAR, 6, 0); } } + } + public static class SizingBarTop + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TASKBAR, 7, 0); } } + } + } + #endregion + #region TaskBarClock + public static class TaskbarClock + { + public static class Time + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.CLOCK, 1, 1); } } + } + } + #endregion + #region TextBox + public static class TextBox + { + public static class Caret + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.EDIT, 2, 0); } } + } + public static class TextEdit + { + public static VisualStyleElement Assist { + get { + return VisualStyleElement.CreateElement ( + EDIT, + (int)EDITPARTS.EP_EDITTEXT, + (int)EDITTEXTSTATES.ETS_ASSIST); + } + } + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + EDIT, + (int)EDITPARTS.EP_EDITTEXT, + (int)EDITTEXTSTATES.ETS_DISABLED); + } + } + public static VisualStyleElement Focused { + get { + return VisualStyleElement.CreateElement ( + EDIT, + (int)EDITPARTS.EP_EDITTEXT, + (int)EDITTEXTSTATES.ETS_FOCUSED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + EDIT, + (int)EDITPARTS.EP_EDITTEXT, + (int)EDITTEXTSTATES.ETS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + EDIT, + (int)EDITPARTS.EP_EDITTEXT, + (int)EDITTEXTSTATES.ETS_NORMAL); + } + } + public static VisualStyleElement ReadOnly { + get { + return VisualStyleElement.CreateElement ( + EDIT, + (int)EDITPARTS.EP_EDITTEXT, + (int)EDITTEXTSTATES.ETS_READONLY); + } + } + public static VisualStyleElement Selected { + get { + return VisualStyleElement.CreateElement ( + EDIT, + (int)EDITPARTS.EP_EDITTEXT, + (int)EDITTEXTSTATES.ETS_SELECTED); + } + } + } + } + #endregion + #region ToolBar + public static class ToolBar + { + public static class Button + { + public static VisualStyleElement Checked { + get { + return VisualStyleElement.CreateElement ( + TOOLBAR, + (int)TOOLBARPARTS.TP_BUTTON, + (int)TOOLBARSTYLESTATES.TS_CHECKED); + } + } + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + TOOLBAR, + (int)TOOLBARPARTS.TP_BUTTON, + (int)TOOLBARSTYLESTATES.TS_DISABLED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + TOOLBAR, + (int)TOOLBARPARTS.TP_BUTTON, + (int)TOOLBARSTYLESTATES.TS_HOT); + } + } + public static VisualStyleElement HotChecked { + get { + return VisualStyleElement.CreateElement ( + TOOLBAR, + (int)TOOLBARPARTS.TP_BUTTON, + (int)TOOLBARSTYLESTATES.TS_HOTCHECKED); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + TOOLBAR, + (int)TOOLBARPARTS.TP_BUTTON, + (int)TOOLBARSTYLESTATES.TS_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + TOOLBAR, + (int)TOOLBARPARTS.TP_BUTTON, + (int)TOOLBARSTYLESTATES.TS_PRESSED); + } + } + } + public static class DropDownButton + { + public static VisualStyleElement Checked { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 2, 5); } } + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 2, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 2, 2); } } + public static VisualStyleElement HotChecked { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 2, 6); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 2, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 2, 3); } } + } + public static class SeparatorHorizontal + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 5, 0); } } + } + public static class SeparatorVertical + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 6, 0); } } + } + public static class SplitButton + { + public static VisualStyleElement Checked { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 3, 5); } } + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 3, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 3, 2); } } + public static VisualStyleElement HotChecked { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 3, 6); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 3, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 3, 3); } } + } + public static class SplitButtonDropDown + { + public static VisualStyleElement Checked { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 4, 5); } } + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 4, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 4, 2); } } + public static VisualStyleElement HotChecked { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 4, 6); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 4, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLBAR, 4, 3); } } + } + } + #endregion + #region ToolTip + public static class ToolTip + { + public static class Balloon + { + public static VisualStyleElement Link { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLTIP, 3, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLTIP, 3, 1); } } + } + public static class BalloonTitle + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLTIP, 4, 0); } } + } + public static class Close + { + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLTIP, 5, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLTIP, 5, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLTIP, 5, 3); } } + } + public static class Standard + { + public static VisualStyleElement Link { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLTIP, 1, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLTIP, 1, 1); } } + } + public static class StandardTitle + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TOOLTIP, 2, 0); } } + } + } + #endregion + #region TrackBar + public static class TrackBar + { + public static class Thumb + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + TRACKBAR, + (int)TRACKBARPARTS.TKP_THUMB, + (int)THUMBSTATES.TUS_DISABLED); + } + } + public static VisualStyleElement Focused { + get { + return VisualStyleElement.CreateElement ( + TRACKBAR, + (int)TRACKBARPARTS.TKP_THUMB, + (int)THUMBSTATES.TUS_FOCUSED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + TRACKBAR, + (int)TRACKBARPARTS.TKP_THUMB, + (int)THUMBSTATES.TUS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + TRACKBAR, + (int)TRACKBARPARTS.TKP_THUMB, + (int)THUMBSTATES.TUS_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + TRACKBAR, + (int)TRACKBARPARTS.TKP_THUMB, + (int)THUMBSTATES.TUS_PRESSED); + } + } + } + public static class ThumbBottom + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 4, 5); } } + public static VisualStyleElement Focused { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 4, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 4, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 4, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 4, 3); } } + } + public static class ThumbLeft + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 7, 5); } } + public static VisualStyleElement Focused { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 7, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 7, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 7, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 7, 3); } } + } + public static class ThumbRight + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 8, 5); } } + public static VisualStyleElement Focused { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 8, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 8, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 8, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 8, 3); } } + } + public static class ThumbTop + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 5, 5); } } + public static VisualStyleElement Focused { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 5, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 5, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 5, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 5, 3); } } + } + public static class ThumbVertical + { + public static VisualStyleElement Disabled { + get { + return VisualStyleElement.CreateElement ( + TRACKBAR, + (int)TRACKBARPARTS.TKP_THUMBVERT, + (int)THUMBVERTSTATES.TUVS_DISABLED); + } + } + public static VisualStyleElement Focused { + get { + return VisualStyleElement.CreateElement ( + TRACKBAR, + (int)TRACKBARPARTS.TKP_THUMBVERT, + (int)THUMBVERTSTATES.TUVS_FOCUSED); + } + } + public static VisualStyleElement Hot { + get { + return VisualStyleElement.CreateElement ( + TRACKBAR, + (int)TRACKBARPARTS.TKP_THUMBVERT, + (int)THUMBVERTSTATES.TUVS_HOT); + } + } + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + TRACKBAR, + (int)TRACKBARPARTS.TKP_THUMBVERT, + (int)THUMBVERTSTATES.TUVS_NORMAL); + } + } + public static VisualStyleElement Pressed { + get { + return VisualStyleElement.CreateElement ( + TRACKBAR, + (int)TRACKBARPARTS.TKP_THUMBVERT, + (int)THUMBVERTSTATES.TUVS_PRESSED); + } + } + } + public static class Ticks + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 9, 1); } } + } + public static class TicksVertical + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRACKBAR, 10, 1); } } + } + public static class Track + { + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + TRACKBAR, + (int)TRACKBARPARTS.TKP_TRACK, + (int)TRACKSTATES.TRS_NORMAL); + } + } + } + public static class TrackVertical + { + public static VisualStyleElement Normal { + get { + return VisualStyleElement.CreateElement ( + TRACKBAR, + (int)TRACKBARPARTS.TKP_TRACKVERT, + (int)TRACKVERTSTATES.TRVS_NORMAL); + } + } + } + } + #endregion + #region TrayNotify + public static class TrayNotify + { + public static class AnimateBackground + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRAYNOTIFY, 2, 0); } } + } + public static class Background + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TRAYNOTIFY, 1, 0); } } + } + } + #endregion + #region TreeView + public static class TreeView + { + public static class Branch + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TREEVIEW, 3, 0); } } + } + public static class Glyph + { + public static VisualStyleElement Closed { + get { + return VisualStyleElement.CreateElement ( + TREEVIEW, + (int)TREEVIEWPARTS.TVP_GLYPH, + (int)GLYPHSTATES.GLPS_CLOSED); + } + } + public static VisualStyleElement Opened { + get { + return VisualStyleElement.CreateElement ( + TREEVIEW, + (int)TREEVIEWPARTS.TVP_GLYPH, + (int)GLYPHSTATES.GLPS_OPENED); + } + } + } + public static class Item + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.TREEVIEW, 1, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.TREEVIEW, 1, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.TREEVIEW, 1, 1); } } + public static VisualStyleElement Selected { get { return VisualStyleElement.CreateElement (VisualStyleElement.TREEVIEW, 1, 3); } } + public static VisualStyleElement SelectedNotFocus { get { return VisualStyleElement.CreateElement (VisualStyleElement.TREEVIEW, 1, 5); } } + } + } + #endregion + #region Window + public static class Window + { + public static class Caption + { + public static VisualStyleElement Active { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 1, 1); } } + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 1, 3); } } + public static VisualStyleElement Inactive { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 1, 2); } } + } + public static class CaptionSizingTemplate + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 30, 0); } } + } + public static class CloseButton + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 18, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 18, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 18, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 18, 3); } } + } + public static class Dialog + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 29, 0); } } + } + public static class FrameBottom + { + public static VisualStyleElement Active { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 9, 1); } } + public static VisualStyleElement Inactive { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 9, 2); } } + } + public static class FrameBottomSizingTemplate + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 36, 0); } } + } + public static class FrameLeft + { + public static VisualStyleElement Active { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 7, 1); } } + public static VisualStyleElement Inactive { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 7, 2); } } + } + public static class FrameLeftSizingTemplate + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 32, 0); } } + } + public static class FrameRight + { + public static VisualStyleElement Active { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 8, 1); } } + public static VisualStyleElement Inactive { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 8, 2); } } + } + public static class FrameRightSizingTemplate + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 34, 0); } } + } + public static class HelpButton + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 23, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 23, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 23, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 23, 3); } } + } + public static class HorizontalScroll + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 25, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 25, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 25, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 25, 3); } } + } + public static class HorizontalThumb + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 26, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 26, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 26, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 26, 3); } } + } + public static class MaxButton + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 17, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 17, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 17, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 17, 3); } } + } + public static class MaxCaption + { + public static VisualStyleElement Active { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 5, 1); } } + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 5, 3); } } + public static VisualStyleElement Inactive { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 5, 2); } } + } + public static class MdiCloseButton + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 20, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 20, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 20, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 20, 3); } } + } + public static class MdiHelpButton + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 24, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 24, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 24, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 24, 3); } } + } + public static class MdiMinButton + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 16, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 16, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 16, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 16, 3); } } + } + public static class MdiRestoreButton + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 22, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 22, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 22, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 22, 3); } } + } + public static class MdiSysButton + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 14, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 14, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 14, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 14, 3); } } + } + public static class MinButton + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 15, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 15, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 15, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 15, 3); } } + } + public static class MinCaption + { + public static VisualStyleElement Active { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 3, 1); } } + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 3, 3); } } + public static VisualStyleElement Inactive { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 3, 2); } } + } + public static class RestoreButton + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 21, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 21, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 21, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 21, 3); } } + } + public static class SmallCaption + { + public static VisualStyleElement Active { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 2, 1); } } + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 2, 3); } } + public static VisualStyleElement Inactive { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 2, 2); } } + } + public static class SmallCaptionSizingTemplate + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 31, 0); } } + } + public static class SmallCloseButton + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 19, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 19, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 19, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 19, 3); } } + } + public static class SmallFrameBottom + { + public static VisualStyleElement Active { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 12, 1); } } + public static VisualStyleElement Inactive { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 12, 2); } } + } + public static class SmallFrameBottomSizingTemplate + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 37, 0); } } + } + public static class SmallFrameLeft + { + public static VisualStyleElement Active { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 10, 1); } } + public static VisualStyleElement Inactive { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 10, 2); } } + } + public static class SmallFrameLeftSizingTemplate + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 33, 0); } } + } + public static class SmallFrameRight + { + public static VisualStyleElement Active { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 11, 1); } } + public static VisualStyleElement Inactive { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 11, 2); } } + } + public static class SmallFrameRightSizingTemplate + { + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 35, 0); } } + } + public static class SmallMaxCaption + { + public static VisualStyleElement Active { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 6, 1); } } + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 6, 3); } } + public static VisualStyleElement Inactive { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 6, 2); } } + } + public static class SmallMinCaption + { + public static VisualStyleElement Active { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 4, 1); } } + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 4, 3); } } + public static VisualStyleElement Inactive { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 4, 2); } } + } + public static class SysButton + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 13, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 13, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 13, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 13, 3); } } + } + public static class VerticalScroll + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 27, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 27, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 27, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 27, 3); } } + } + public static class VerticalThumb + { + public static VisualStyleElement Disabled { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 28, 4); } } + public static VisualStyleElement Hot { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 28, 2); } } + public static VisualStyleElement Normal { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 28, 1); } } + public static VisualStyleElement Pressed { get { return VisualStyleElement.CreateElement (VisualStyleElement.WINDOW, 28, 3); } } + } + } + #endregion + #endregion + } + #region Part and state constants + #region BUTTON + enum BUTTONPARTS + { + BP_PUSHBUTTON = 1, + BP_RADIOBUTTON, + BP_CHECKBOX, + BP_GROUPBOX + } + enum PUSHBUTTONSTATES + { + PBS_NORMAL = 1, + PBS_HOT, + PBS_PRESSED, + PBS_DISABLED, + PBS_DEFAULTED + } + enum RADIOBUTTONSTATES + { + RBS_UNCHECKEDNORMAL = 1, + RBS_UNCHECKEDHOT, + RBS_UNCHECKEDPRESSED, + RBS_UNCHECKEDDISABLED, + RBS_CHECKEDNORMAL, + RBS_CHECKEDHOT, + RBS_CHECKEDPRESSED, + RBS_CHECKEDDISABLED + } + enum CHECKBOXSTATES + { + CBS_UNCHECKEDNORMAL = 1, + CBS_UNCHECKEDHOT, + CBS_UNCHECKEDPRESSED, + CBS_UNCHECKEDDISABLED, + CBS_CHECKEDNORMAL, + CBS_CHECKEDHOT, + CBS_CHECKEDPRESSED, + CBS_CHECKEDDISABLED, + CBS_MIXEDNORMAL, + CBS_MIXEDHOT, + CBS_MIXEDPRESSED, + CBS_MIXEDDISABLED + } + enum GROUPBOXSTATES + { + GBS_NORMAL = 1, + GBS_DISABLED + } + #endregion + #region COMBOXBOX + enum COMBOBOXPARTS + { + CP_DROPDOWNBUTTON = 1, + CP_BORDER = 4 + } + enum COMBOBOXSTYLESTATES + { + CBXS_NORMAL = 1, + CBXS_HOT, + CBXS_PRESSED, + CBXS_DISABLED + } + enum BORDERSTATES + { + CBB_NORMAL = 1, + CBB_HOT, + CBB_FOCUSED, + CBB_DISABLED + } + #endregion + #region EDIT + enum EDITPARTS + { + EP_EDITTEXT = 1 + } + enum EDITTEXTSTATES { + ETS_NORMAL = 1, + ETS_HOT, + ETS_SELECTED, + ETS_DISABLED, + ETS_FOCUSED, + ETS_READONLY, + ETS_ASSIST + } + #endregion + #region HEADER + enum HEADERPARTS + { + HP_HEADERITEM = 1 + } + enum HEADERITEMSTATES + { + HIS_NORMAL = 1, + HIS_HOT, + HIS_PRESSED + } + #endregion + #region PROGRESS + enum PROGRESSPARTS + { + PP_BAR = 1, + PP_BARVERT, + PP_CHUNK, + PP_CHUNKVERT + } + #endregion + #region REBAR + enum REBARPARTS + { + RP_BAND = 3 + } + #endregion + #region SCROLLBAR + enum SCROLLBARPARTS + { + SBP_ARROWBTN = 1, + SBP_THUMBBTNHORZ, + SBP_THUMBBTNVERT, + SBP_LOWERTRACKHORZ, + SBP_UPPERTRACKHORZ, + SBP_LOWERTRACKVERT, + SBP_UPPERTRACKVERT, + SBP_GRIPPERHORZ, + SBP_GRIPPERVERT, + SBP_SIZEBOX + } + enum ARROWBTNSTATES + { + ABS_UPNORMAL = 1, + ABS_UPHOT, + ABS_UPPRESSED, + ABS_UPDISABLED, + ABS_DOWNNORMAL, + ABS_DOWNHOT, + ABS_DOWNPRESSED, + ABS_DOWNDISABLED, + ABS_LEFTNORMAL, + ABS_LEFTHOT, + ABS_LEFTPRESSED, + ABS_LEFTDISABLED, + ABS_RIGHTNORMAL, + ABS_RIGHTHOT, + ABS_RIGHTPRESSED, + ABS_RIGHTDISABLED, + ABS_UPHOVER, + ABS_DOWNHOVER, + ABS_LEFTHOVER, + ABS_RIGHTHOVER + } + enum SCROLLBARSTYLESTATES + { + SCRBS_NORMAL = 1, + SCRBS_HOT, + SCRBS_PRESSED, + SCRBS_DISABLED + } + enum SIZEBOXSTATES + { + SZB_RIGHTALIGN = 1, + SZB_LEFTALIGN + } + #endregion + #region SPIN + enum SPINPARTS + { + SPNP_UP = 1, + SPNP_DOWN, + SPNP_UPHORZ, + SPNP_DOWNHORZ + } + enum UPSTATES + { + UPS_NORMAL = 1, + UPS_HOT, + UPS_PRESSED, + UPS_DISABLED + } + enum DOWNSTATES + { + DNS_NORMAL = 1, + DNS_HOT, + DNS_PRESSED, + DNS_DISABLED + } + enum UPHORZSTATES + { + UPHZS_NORMAL = 1, + UPHZS_HOT, + UPHZS_PRESSED, + UPHZS_DISABLED + } + enum DOWNHORZSTATES + { + DNHZS_NORMAL = 1, + DNHZS_HOT, + DNHZS_PRESSED, + DNHZS_DISABLED + } + #endregion + #region STATUS + enum STATUSPARTS + { + SP_GRIPPER = 3 + } + #endregion + #region TAB + enum TABPARTS + { + TABP_TABITEM = 1, + TABP_TABITEMLEFTEDGE, + TABP_TABITEMRIGHTEDGE, + TABP_TABITEMBOTHEDGE, + TABP_TOPTABITEM, + TABP_TOPTABITEMLEFTEDGE, + TABP_TOPTABITEMRIGHTEDGE, + TABP_TOPTABITEMBOTHEDGE, + TABP_PANE, + TABP_BODY + } + enum TABITEMSTATES + { + TIS_NORMAL = 1, + TIS_HOT, + TIS_SELECTED, + TIS_DISABLED + } + enum TABITEMLEFTEDGESTATES + { + TILES_NORMAL = 1, + TILES_HOT, + TILES_SELECTED, + TILES_DISABLED + } + enum TABITEMRIGHTEDGESTATES + { + TIRES_NORMAL = 1, + TIRES_HOT, + TIRES_SELECTED, + TIRES_DISABLED + } + enum TOPTABITEMSTATES + { + TTIS_NORMAL = 1, + TTIS_HOT, + TTIS_SELECTED, + TTIS_DISABLED + } + enum TOPTABITEMLEFTEDGESTATES + { + TTILES_NORMAL = 1, + TTILES_HOT, + TTILES_SELECTED, + TTILES_DISABLED + } + enum TOPTABITEMRIGHTEDGESTATES + { + TTIRES_NORMAL = 1, + TTIRES_HOT, + TTIRES_SELECTED, + TTIRES_DISABLED + } + #endregion + #region TOOLBAR + enum TOOLBARPARTS + { + TP_BUTTON = 1 + } + enum TOOLBARSTYLESTATES + { + TS_NORMAL = 1, + TS_HOT, + TS_PRESSED, + TS_DISABLED, + TS_CHECKED, + TS_HOTCHECKED + } + #endregion + #region TRACKBAR + enum TRACKBARPARTS + { + TKP_TRACK = 1, + TKP_TRACKVERT, + TKP_THUMB, + TKP_THUMBVERT = 6 + } + enum TRACKSTATES + { + TRS_NORMAL = 1 + } + enum TRACKVERTSTATES + { + TRVS_NORMAL = 1 + } + enum THUMBSTATES + { + TUS_NORMAL = 1, + TUS_HOT, + TUS_PRESSED, + TUS_FOCUSED, + TUS_DISABLED + } + enum THUMBVERTSTATES + { + TUVS_NORMAL = 1, + TUVS_HOT, + TUVS_PRESSED, + TUVS_FOCUSED, + TUVS_DISABLED + } + #endregion + #region TREEVIEW + enum TREEVIEWPARTS + { + TVP_GLYPH = 2 + } + enum GLYPHSTATES + { + GLPS_CLOSED = 1, + GLPS_OPENED + } + #endregion + #endregion +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStyleInformation.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStyleInformation.cs new file mode 100644 index 0000000..ae9bddb --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStyleInformation.cs @@ -0,0 +1,180 @@ +// +// VisualStyleInformation.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System; + +namespace ShiftUI.VisualStyles +{ + public static class VisualStyleInformation + { + #region Public Static Properties + public static string Author { + get { + if (!VisualStyleRenderer.IsSupported) + return string.Empty; + + return VisualStyles.VisualStyleInformationAuthor; + } + } + + public static string ColorScheme { + get { + if (!VisualStyleRenderer.IsSupported) + return string.Empty; + + return VisualStyles.VisualStyleInformationColorScheme; + } + } + + public static string Company { + get { + if (!VisualStyleRenderer.IsSupported) + return string.Empty; + + return VisualStyles.VisualStyleInformationCompany; + } + } + + [MonoTODO(@"Cannot get this to return the same as MS's...")] + public static Color WidgetHighlightHot { + get { + if (!VisualStyleRenderer.IsSupported) + return SystemColors.ButtonHighlight; + + return VisualStyles.VisualStyleInformationWidgetHighlightHot; + } + } + + public static string Copyright { + get { + if (!VisualStyleRenderer.IsSupported) + return string.Empty; + + return VisualStyles.VisualStyleInformationCopyright; + } + } + + public static string Description { + get { + if (!VisualStyleRenderer.IsSupported) + return string.Empty; + + return VisualStyles.VisualStyleInformationDescription; + } + } + + public static string DisplayName { + get { + if (!VisualStyleRenderer.IsSupported) + return string.Empty; + + return VisualStyles.VisualStyleInformationDisplayName; + } + } + + public static bool IsEnabledByUser { + get { + if (!VisualStyleInformation.IsSupportedByOS) + return false; + + return (VisualStyles.UxThemeIsAppThemed () && VisualStyles.UxThemeIsThemeActive ()); + } + } + + public static bool IsSupportedByOS { + get { + return VisualStyles.VisualStyleInformationIsSupportedByOS; + } + } + + public static int MinimumColorDepth { + get { + if (!VisualStyleRenderer.IsSupported) + return 0; + + return VisualStyles.VisualStyleInformationMinimumColorDepth; + } + } + + public static string Size { + get { + if (!VisualStyleRenderer.IsSupported) + return string.Empty; + + return VisualStyles.VisualStyleInformationSize; + } + } + + public static bool SupportsFlatMenus { + get { + if (!VisualStyleRenderer.IsSupported) + return false; + + return VisualStyles.VisualStyleInformationSupportsFlatMenus; + } + } + + [MonoTODO(@"Cannot get this to return the same as MS's...")] + public static Color TextWidgetBorder { + get { + if (!VisualStyleRenderer.IsSupported) + return SystemColors.ControlDarkDark; + + return VisualStyles.VisualStyleInformationTextWidgetBorder; + } + } + + public static string Url { + get { + if (!VisualStyleRenderer.IsSupported) + return string.Empty; + + return VisualStyles.VisualStyleInformationUrl; + } + } + + public static string Version { + get { + if (!VisualStyleRenderer.IsSupported) + return string.Empty; + + return VisualStyles.VisualStyleInformationVersion; + } + } + #endregion + + #region Private Static Properties + static IVisualStyles VisualStyles { + get { + return VisualStylesEngine.Instance; + } + } + #endregion + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStyleRenderer.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStyleRenderer.cs new file mode 100644 index 0000000..c49e213 --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStyleRenderer.cs @@ -0,0 +1,447 @@ +// +// VisualStyleRenderer.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System; + +namespace ShiftUI.VisualStyles +{ + public sealed class VisualStyleRenderer + { + private string class_name; + private int part; + private int state; + private IntPtr theme; + private int last_hresult = 0; + private ThemeHandleManager theme_handle_manager = new ThemeHandleManager (); + + #region Public Constructors + public VisualStyleRenderer (string className, int part, int state) + { + theme_handle_manager.VisualStyleRenderer = this; + this.SetParameters (className, part, state); + } + + public VisualStyleRenderer (VisualStyleElement element) + : this (element.ClassName, element.Part, element.State) { + } + #endregion + + #region Public Properties + public String Class { get { return this.class_name; } } + public IntPtr Handle { get { return this.theme; } } + public int LastHResult { get { return this.last_hresult; } } + public int Part { get { return this.part; } } + public int State { get { return this.state; } } + + public static bool IsSupported { + get { + if (!VisualStyleInformation.IsEnabledByUser) + return false; + + if (Application.VisualStyleState == VisualStyleState.ClientAndNonClientAreasEnabled || + Application.VisualStyleState == VisualStyleState.ClientAreaEnabled) + return true; + + return false; + } + } + #endregion + + #region Public Static Methods + public static bool IsElementDefined (VisualStyleElement element) + { + if (!IsSupported) + throw new InvalidOperationException ("Visual Styles are not enabled."); + + if (IsElementKnownToBeSupported (element.ClassName, element.Part, element.State)) + return true; + + IntPtr theme = VisualStyles.UxThemeOpenThemeData (IntPtr.Zero, element.ClassName); + if (theme == IntPtr.Zero) + return false; + bool retval = VisualStyles.UxThemeIsThemePartDefined (theme, element.Part); + VisualStyles.UxThemeCloseThemeData (theme); + + return retval; + } + #endregion + + #region Public Instance Methods + public void DrawBackground (IDeviceContext dc, Rectangle bounds) + { + if (dc == null) + throw new ArgumentNullException ("dc"); + + last_hresult = VisualStyles.UxThemeDrawThemeBackground (theme, dc, this.part, this.state, bounds); + } + + public void DrawBackground (IDeviceContext dc, Rectangle bounds, Rectangle clipRectangle) + { + if (dc == null) + throw new ArgumentNullException ("dc"); + + last_hresult = VisualStyles.UxThemeDrawThemeBackground (theme, dc, this.part, this.state, bounds, clipRectangle); + } + + public Rectangle DrawEdge (IDeviceContext dc, Rectangle bounds, Edges edges, EdgeStyle style, EdgeEffects effects) + { + if (dc == null) + throw new ArgumentNullException ("dc"); + + Rectangle result; + last_hresult = VisualStyles.UxThemeDrawThemeEdge (theme, dc, this.part, this.state, bounds, edges, style, effects, out result); + return result; + } + + public void DrawImage (Graphics g, Rectangle bounds, ImageList imageList, int imageIndex) + { + if (g == null) + throw new ArgumentNullException ("g"); + if (imageIndex < 0 || imageIndex > imageList.Images.Count - 1) + throw new ArgumentOutOfRangeException ("imageIndex"); + if (imageList.Images[imageIndex] == null) + throw new ArgumentNullException ("imageIndex"); + + g.DrawImage (imageList.Images[imageIndex], bounds); + } + + public void DrawImage (Graphics g, Rectangle bounds, Image image) + { + if (g == null) + throw new ArgumentNullException ("g"); + if (image == null) + throw new ArgumentNullException ("image"); + + g.DrawImage (image, bounds); + } + + public void DrawParentBackground (IDeviceContext dc, Rectangle bounds, Widget childWidget) + { + if (dc == null) + throw new ArgumentNullException ("dc"); + + last_hresult = VisualStyles.UxThemeDrawThemeParentBackground (dc, bounds, childWidget); + } + + public void DrawText (IDeviceContext dc, Rectangle bounds, string textToDraw, bool drawDisabled, TextFormatFlags flags) + { + if (dc == null) + throw new ArgumentNullException ("dc"); + + last_hresult = VisualStyles.UxThemeDrawThemeText (theme, dc, this.part, this.state, textToDraw, flags, bounds); + } + + public void DrawText (IDeviceContext dc, Rectangle bounds, string textToDraw, bool drawDisabled) + { + this.DrawText (dc, bounds, textToDraw, drawDisabled, TextFormatFlags.Default); + } + + public void DrawText (IDeviceContext dc, Rectangle bounds, string textToDraw) + { + this.DrawText (dc, bounds, textToDraw, false, TextFormatFlags.Default); + } + + public Rectangle GetBackgroundContentRectangle (IDeviceContext dc, Rectangle bounds) + { + if (dc == null) + throw new ArgumentNullException ("dc"); + + Rectangle result; + last_hresult = VisualStyles.UxThemeGetThemeBackgroundContentRect (theme, dc, this.part, this.state, bounds, out result); + return result; + } + + public Rectangle GetBackgroundExtent (IDeviceContext dc, Rectangle contentBounds) + { + if (dc == null) + throw new ArgumentNullException ("dc"); + + Rectangle result; + last_hresult = VisualStyles.UxThemeGetThemeBackgroundExtent (theme, dc, this.part, this.state, contentBounds, out result); + return result; + } + + [System.Security.SuppressUnmanagedCodeSecurity] + public Region GetBackgroundRegion (IDeviceContext dc, Rectangle bounds) + { + if (dc == null) + throw new ArgumentNullException ("dc"); + + Region result; + last_hresult = VisualStyles.UxThemeGetThemeBackgroundRegion (theme, dc, this.part, this.state, bounds, out result); + return result; + } + + public bool GetBoolean (BooleanProperty prop) + { + if (!Enum.IsDefined (typeof (BooleanProperty), prop)) + throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (BooleanProperty)); + + bool result; + last_hresult = VisualStyles.UxThemeGetThemeBool (theme, this.part, this.state, prop, out result); + return result; + } + + public Color GetColor (ColorProperty prop) + { + if (!Enum.IsDefined (typeof (ColorProperty), prop)) + throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (ColorProperty)); + + Color result; + last_hresult = VisualStyles.UxThemeGetThemeColor (theme, this.part, this.state, prop, out result); + return result; + } + + public int GetEnumValue (EnumProperty prop) + { + if (!Enum.IsDefined (typeof (EnumProperty), prop)) + throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (EnumProperty)); + + int result; + last_hresult = VisualStyles.UxThemeGetThemeEnumValue (theme, this.part, this.state, prop, out result); + return result; + } + + public string GetFilename (FilenameProperty prop) + { + if (!Enum.IsDefined (typeof (FilenameProperty), prop)) + throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (FilenameProperty)); + + string result; + last_hresult = VisualStyles.UxThemeGetThemeFilename (theme, this.part, this.state, prop, out result); + return result; + + } + + [MonoTODO(@"I can't get MS's to return anything but null, so I can't really get this one right")] + public Font GetFont (IDeviceContext dc, FontProperty prop) + { + throw new NotImplementedException(); + //if (dc == null) + // throw new ArgumentNullException ("dc"); + //if (!Enum.IsDefined (typeof (FontProperty), prop)) + // throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (FontProperty)); + + //UXTheme.LOGFONT lf = new UXTheme.LOGFONT(); + + //UXTheme.GetThemeFont (theme, dc.GetHdc (), this.part, this.state, (int)prop, out lf); + //IntPtr fontPtr = UXTheme.CreateFontIndirect(lf); + //dc.ReleaseHdc(); + + //return Font.FromLogFont(lf); + //return null; + } + + public int GetInteger (IntegerProperty prop) + { + if (!Enum.IsDefined (typeof (IntegerProperty), prop)) + throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (IntegerProperty)); + + int result; + last_hresult = VisualStyles.UxThemeGetThemeInt (theme, this.part, this.state, prop, out result); + return result; + } + + [MonoTODO(@"MS's causes a PInvokeStackUnbalance on me, so this is not verified against MS.")] + public Padding GetMargins (IDeviceContext dc, MarginProperty prop) + { + if (dc == null) + throw new ArgumentNullException ("dc"); + if (!Enum.IsDefined (typeof (MarginProperty), prop)) + throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (MarginProperty)); + + Padding result; + last_hresult = VisualStyles.UxThemeGetThemeMargins (theme, dc, this.part, this.state, prop, out result); + return result; + } + + public Size GetPartSize (IDeviceContext dc, Rectangle bounds, ThemeSizeType type) + { + if (dc == null) + throw new ArgumentNullException ("dc"); + if (!Enum.IsDefined (typeof (ThemeSizeType), type)) + throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)type, typeof (ThemeSizeType)); + + Size result; + last_hresult = VisualStyles.UxThemeGetThemePartSize (theme, dc, this.part, this.state, bounds, type, out result); + return result; + } + + public Size GetPartSize (IDeviceContext dc, ThemeSizeType type) + { + if (dc == null) + throw new ArgumentNullException ("dc"); + if (!Enum.IsDefined (typeof (ThemeSizeType), type)) + throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)type, typeof (ThemeSizeType)); + + Size result; + last_hresult = VisualStyles.UxThemeGetThemePartSize (theme, dc, this.part, this.state, type, out result); + return result; + } + + public Point GetPoint (PointProperty prop) + { + if (!Enum.IsDefined (typeof (PointProperty), prop)) + throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (PointProperty)); + + Point result; + last_hresult = VisualStyles.UxThemeGetThemePosition (theme, this.part, this.state, prop, out result); + return result; + } + + [MonoTODO(@"Can't find any values that return anything on MS to test against")] + public string GetString (StringProperty prop) + { + if (!Enum.IsDefined (typeof (StringProperty), prop)) + throw new System.ComponentModel.InvalidEnumArgumentException ("prop", (int)prop, typeof (StringProperty)); + + string result; + last_hresult = VisualStyles.UxThemeGetThemeString (theme, this.part, this.state, prop, out result); + return result; + } + + public Rectangle GetTextExtent (IDeviceContext dc, Rectangle bounds, string textToDraw, TextFormatFlags flags) + { + if (dc == null) + throw new ArgumentNullException ("dc"); + + Rectangle result; + last_hresult = VisualStyles.UxThemeGetThemeTextExtent (theme, dc, this.part, this.state, textToDraw, flags, bounds, out result); + return result; + } + + public Rectangle GetTextExtent (IDeviceContext dc, string textToDraw, TextFormatFlags flags) + { + if (dc == null) + throw new ArgumentNullException ("dc"); + + Rectangle result; + last_hresult = VisualStyles.UxThemeGetThemeTextExtent (theme, dc, this.part, this.state, textToDraw, flags, out result); + return result; + } + + public TextMetrics GetTextMetrics (IDeviceContext dc) + { + if (dc == null) + throw new ArgumentNullException ("dc", "dc cannot be null."); + + TextMetrics result; + last_hresult = VisualStyles.UxThemeGetThemeTextMetrics (theme, dc, this.part, this.state, out result); + return result; + } + + public HitTestCode HitTestBackground (IDeviceContext dc, Rectangle backgroundRectangle, IntPtr hRgn, Point pt, HitTestOptions options) + { + if (dc == null) + throw new ArgumentNullException ("dc"); + + HitTestCode result; + last_hresult = VisualStyles.UxThemeHitTestThemeBackground(theme, dc, this.part, this.state, options, backgroundRectangle, hRgn, pt, out result); + return result; + } + + public HitTestCode HitTestBackground (Graphics g, Rectangle backgroundRectangle, Region region, Point pt, HitTestOptions options) + { + if (g == null) + throw new ArgumentNullException ("g"); + + IntPtr hRgn = region.GetHrgn(g); + + return this.HitTestBackground(g, backgroundRectangle, hRgn, pt, options); + } + + public HitTestCode HitTestBackground (IDeviceContext dc, Rectangle backgroundRectangle, Point pt, HitTestOptions options) + { + return this.HitTestBackground (dc, backgroundRectangle, IntPtr.Zero, pt, options); + } + + public bool IsBackgroundPartiallyTransparent () + { + return VisualStyles.UxThemeIsThemeBackgroundPartiallyTransparent (theme, this.part, this.state); + } + + public void SetParameters (string className, int part, int state) + { + if (theme != IntPtr.Zero) + last_hresult = VisualStyles.UxThemeCloseThemeData (theme); + + if (!IsSupported) + throw new InvalidOperationException ("Visual Styles are not enabled."); + + this.class_name = className; + this.part = part; + this.state = state; + theme = VisualStyles.UxThemeOpenThemeData (IntPtr.Zero, this.class_name); + + if (IsElementKnownToBeSupported (className, part, state)) + return; + if (theme == IntPtr.Zero || !VisualStyles.UxThemeIsThemePartDefined (theme, this.part)) + throw new ArgumentException ("This element is not supported by the current visual style."); + } + + public void SetParameters (VisualStyleElement element) + { + this.SetParameters (element.ClassName, element.Part, element.State); + } + #endregion + + #region Private Properties + internal static IVisualStyles VisualStyles { + get { return VisualStylesEngine.Instance; } + } + #endregion + + #region Private Instance Methods + internal void DrawBackgroundExcludingArea (IDeviceContext dc, Rectangle bounds, Rectangle excludedArea) + { + VisualStyles.VisualStyleRendererDrawBackgroundExcludingArea (theme, dc, part, state, bounds, excludedArea); + } + #endregion + + #region Private Static Methods + private static bool IsElementKnownToBeSupported (string className, int part, int state) + { + return className == "STATUS" && part == 0 && state == 0; + } + #endregion + + #region Private Classes + private class ThemeHandleManager + { + public VisualStyleRenderer VisualStyleRenderer; + ~ThemeHandleManager () + { + if (VisualStyleRenderer.theme == IntPtr.Zero) + return; + VisualStyles.UxThemeCloseThemeData (VisualStyleRenderer.theme); + } + } + #endregion + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStyleState.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStyleState.cs new file mode 100644 index 0000000..4fead8f --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStyleState.cs @@ -0,0 +1,38 @@ +// +// VisualStyleState.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI.VisualStyles +{ + public enum VisualStyleState + { + NoneEnabled = 0, + NonClientAreaEnabled = 1, + ClientAreaEnabled = 2, + ClientAndNonClientAreasEnabled = 3 + } +} \ No newline at end of file diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStylesEngine.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStylesEngine.cs new file mode 100644 index 0000000..7552b9d --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStylesEngine.cs @@ -0,0 +1,52 @@ +// +// VisualStylesEngine.cs: Selects and provides an IVisualStyles. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2008 George Giolfan +// +// Authors: +// George Giolfan (georgegiolfan@yahoo.com) +// +using System; + +namespace ShiftUI.VisualStyles +{ + class VisualStylesEngine + { + static IVisualStyles instance = Initialize (); + public static IVisualStyles Instance { + get { return instance; } + } + static IVisualStyles Initialize () + { + string environment_variable = Environment.GetEnvironmentVariable("MONO_VISUAL_STYLES"); + if (environment_variable != null) + environment_variable = environment_variable.ToLower (); + if ( +#if !VISUAL_STYLES_USE_GTKPLUS_ON_WINDOWS + environment_variable == "gtkplus" && +#endif + VisualStylesGtkPlus.Initialize ()) + return new VisualStylesGtkPlus (); + return new VisualStylesNative (); + } + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStylesGtkPlus.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStylesGtkPlus.cs new file mode 100644 index 0000000..e1c11de --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStylesGtkPlus.cs @@ -0,0 +1,1177 @@ +// +// VisualStylesGtkPlus.cs: IVisualStyles that uses GtkPlus. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2008 George Giolfan +// +// Authors: +// George Giolfan (georgegiolfan@yahoo.com) +// + +using System.Drawing; +using System.Collections.Generic; +using System; + + +namespace ShiftUI.VisualStyles +{ + class VisualStylesGtkPlus : IVisualStyles + { + public static bool Initialize () + { + return GtkPlus.Initialize (); + } + static GtkPlus GtkPlus { + get { + return GtkPlus.Instance; + } + } + + enum S { + S_OK, + S_FALSE + } + enum ThemeHandle { + BUTTON = 1, + COMBOBOX, + EDIT, + HEADER, + PROGRESS, + REBAR, + SCROLLBAR, + SPIN, + STATUS, + TAB, + TOOLBAR, + TRACKBAR, + TREEVIEW + } + + #region UxTheme + public int UxThemeCloseThemeData (IntPtr hTheme) + { +#if DEBUG + return (int)((Enum.IsDefined (typeof (ThemeHandle), (int)hTheme)) ? S.S_OK : S.S_FALSE); +#else + return (int)S.S_OK; +#endif + } + public int UxThemeDrawThemeParentBackground (IDeviceContext dc, Rectangle bounds, Widget childWidget) + { + return (int)S.S_FALSE; + } + public int UxThemeDrawThemeBackground (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, Rectangle clipRectangle) + { + return (int)(DrawBackground ((ThemeHandle)(int)hTheme, dc, iPartId, iStateId, bounds, clipRectangle, Rectangle.Empty) ? S.S_OK : S.S_FALSE); + } + public int UxThemeDrawThemeBackground (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds) + { + return UxThemeDrawThemeBackground (hTheme, dc, iPartId, iStateId, bounds, bounds); + } + bool DrawBackground (ThemeHandle themeHandle, IDeviceContext dc, int part, int state, Rectangle bounds, Rectangle clipRectangle, Rectangle excludedArea) { + GtkPlusState gtk_plus_state; + GtkPlusToggleButtonValue gtk_plus_toggle_button_value; + switch (themeHandle) { + #region BUTTON + case ThemeHandle.BUTTON: + switch ((BUTTONPARTS)part) { + #region BP_PUSHBUTTON + case BUTTONPARTS.BP_PUSHBUTTON: + switch ((PUSHBUTTONSTATES)state) { + case PUSHBUTTONSTATES.PBS_NORMAL: + gtk_plus_state = GtkPlusState.Normal; + break; + case PUSHBUTTONSTATES.PBS_HOT: + gtk_plus_state = GtkPlusState.Hot; + break; + case PUSHBUTTONSTATES.PBS_PRESSED: + gtk_plus_state = GtkPlusState.Pressed; + break; + case PUSHBUTTONSTATES.PBS_DISABLED: + gtk_plus_state = GtkPlusState.Disabled; + break; + case PUSHBUTTONSTATES.PBS_DEFAULTED: + gtk_plus_state = GtkPlusState.Normal; + break; + default: + return false; + } + GtkPlus.ButtonPaint (dc, bounds, clipRectangle, (PUSHBUTTONSTATES)state == PUSHBUTTONSTATES.PBS_DEFAULTED, gtk_plus_state); + return true; + #endregion + #region BP_RADIOBUTTON + case BUTTONPARTS.BP_RADIOBUTTON: + switch ((RADIOBUTTONSTATES)state) { + case RADIOBUTTONSTATES.RBS_UNCHECKEDNORMAL: + gtk_plus_state = GtkPlusState.Normal; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Unchecked; + break; + case RADIOBUTTONSTATES.RBS_UNCHECKEDPRESSED: + gtk_plus_state = GtkPlusState.Pressed; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Unchecked; + break; + case RADIOBUTTONSTATES.RBS_UNCHECKEDHOT: + gtk_plus_state = GtkPlusState.Hot; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Unchecked; + break; + case RADIOBUTTONSTATES.RBS_UNCHECKEDDISABLED: + gtk_plus_state = GtkPlusState.Disabled; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Unchecked; + break; + case RADIOBUTTONSTATES.RBS_CHECKEDNORMAL: + gtk_plus_state = GtkPlusState.Normal; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Checked; + break; + case RADIOBUTTONSTATES.RBS_CHECKEDPRESSED: + gtk_plus_state = GtkPlusState.Pressed; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Checked; + break; + case RADIOBUTTONSTATES.RBS_CHECKEDHOT: + gtk_plus_state = GtkPlusState.Hot; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Checked; + break; + case RADIOBUTTONSTATES.RBS_CHECKEDDISABLED: + gtk_plus_state = GtkPlusState.Disabled; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Checked; + break; + default: + return false; + } + GtkPlus.RadioButtonPaint (dc, bounds, clipRectangle, gtk_plus_state, gtk_plus_toggle_button_value); + return true; + #endregion + #region BP_CHECKBOX + case BUTTONPARTS.BP_CHECKBOX: + switch ((CHECKBOXSTATES)state) { + case CHECKBOXSTATES.CBS_UNCHECKEDNORMAL: + gtk_plus_state = GtkPlusState.Normal; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Unchecked; + break; + case CHECKBOXSTATES.CBS_UNCHECKEDPRESSED: + gtk_plus_state = GtkPlusState.Pressed; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Unchecked; + break; + case CHECKBOXSTATES.CBS_UNCHECKEDHOT: + gtk_plus_state = GtkPlusState.Hot; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Unchecked; + break; + case CHECKBOXSTATES.CBS_UNCHECKEDDISABLED: + gtk_plus_state = GtkPlusState.Disabled; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Unchecked; + break; + case CHECKBOXSTATES.CBS_CHECKEDNORMAL: + gtk_plus_state = GtkPlusState.Normal; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Checked; + break; + case CHECKBOXSTATES.CBS_CHECKEDPRESSED: + gtk_plus_state = GtkPlusState.Pressed; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Checked; + break; + case CHECKBOXSTATES.CBS_CHECKEDHOT: + gtk_plus_state = GtkPlusState.Hot; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Checked; + break; + case CHECKBOXSTATES.CBS_CHECKEDDISABLED: + gtk_plus_state = GtkPlusState.Disabled; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Checked; + break; + case CHECKBOXSTATES.CBS_MIXEDNORMAL: + gtk_plus_state = GtkPlusState.Normal; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Mixed; + break; + case CHECKBOXSTATES.CBS_MIXEDPRESSED: + gtk_plus_state = GtkPlusState.Pressed; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Mixed; + break; + case CHECKBOXSTATES.CBS_MIXEDHOT: + gtk_plus_state = GtkPlusState.Hot; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Mixed; + break; + case CHECKBOXSTATES.CBS_MIXEDDISABLED: + gtk_plus_state = GtkPlusState.Disabled; + gtk_plus_toggle_button_value = GtkPlusToggleButtonValue.Mixed; + break; + default: + return false; + } + GtkPlus.CheckBoxPaint (dc, bounds, clipRectangle, gtk_plus_state, gtk_plus_toggle_button_value); + return true; + #endregion + #region BP_GROUPBOX + case BUTTONPARTS.BP_GROUPBOX: + switch ((GROUPBOXSTATES)state) { + case GROUPBOXSTATES.GBS_NORMAL: + gtk_plus_state = GtkPlusState.Normal; + break; + case GROUPBOXSTATES.GBS_DISABLED: + gtk_plus_state = GtkPlusState.Disabled; + break; + default: + return false; + } + GtkPlus.GroupBoxPaint (dc, bounds, excludedArea, gtk_plus_state); + return true; + #endregion + default: return false; + } + #endregion + #region COMBOBOX + case ThemeHandle.COMBOBOX: + switch ((COMBOBOXPARTS)part) { + #region CP_DROPDOWNBUTTON + case COMBOBOXPARTS.CP_DROPDOWNBUTTON: + switch ((COMBOBOXSTYLESTATES)state) { + case COMBOBOXSTYLESTATES.CBXS_NORMAL: gtk_plus_state = GtkPlusState.Normal; break; + case COMBOBOXSTYLESTATES.CBXS_HOT: gtk_plus_state = GtkPlusState.Hot; break; + case COMBOBOXSTYLESTATES.CBXS_PRESSED: gtk_plus_state = GtkPlusState.Pressed; break; + case COMBOBOXSTYLESTATES.CBXS_DISABLED: gtk_plus_state = GtkPlusState.Disabled; break; + default: return false; + } + GtkPlus.ComboBoxPaintDropDownButton (dc, bounds, clipRectangle, gtk_plus_state); + return true; + #endregion + #region CP_BORDER + case COMBOBOXPARTS.CP_BORDER: + switch ((BORDERSTATES)state) { + case BORDERSTATES.CBB_NORMAL: + case BORDERSTATES.CBB_HOT: + case BORDERSTATES.CBB_FOCUSED: + case BORDERSTATES.CBB_DISABLED: + GtkPlus.ComboBoxPaintBorder (dc, bounds, clipRectangle); + return true; + default: return false; + } + #endregion + default: return false; + } + #endregion + #region EDIT + case ThemeHandle.EDIT: + switch ((EDITPARTS)part) { + #region EP_EDITTEXT + case EDITPARTS.EP_EDITTEXT: + switch ((EDITTEXTSTATES)state) { + case EDITTEXTSTATES.ETS_NORMAL: + case EDITTEXTSTATES.ETS_ASSIST: + case EDITTEXTSTATES.ETS_READONLY: + case EDITTEXTSTATES.ETS_HOT: + case EDITTEXTSTATES.ETS_SELECTED: + case EDITTEXTSTATES.ETS_FOCUSED: + gtk_plus_state = GtkPlusState.Normal; + break; + case EDITTEXTSTATES.ETS_DISABLED: + gtk_plus_state = GtkPlusState.Disabled; + break; + default: return false; + } + GtkPlus.TextBoxPaint (dc, bounds, excludedArea, gtk_plus_state); + return true; + #endregion + default: return false; + } + #endregion + #region HEADER + case ThemeHandle.HEADER: + switch ((HEADERPARTS)part) { + #region HP_HEADERITEM + case HEADERPARTS.HP_HEADERITEM: + switch ((HEADERITEMSTATES)state) { + case HEADERITEMSTATES.HIS_NORMAL: + gtk_plus_state = GtkPlusState.Normal; + break; + case HEADERITEMSTATES.HIS_HOT: + gtk_plus_state = GtkPlusState.Hot; + break; + case HEADERITEMSTATES.HIS_PRESSED: + gtk_plus_state = GtkPlusState.Pressed; + break; + default: return false; + } + GtkPlus.HeaderPaint (dc, bounds, clipRectangle, gtk_plus_state); + return true; + #endregion + default: return false; + } + #endregion + #region PROGRESS + case ThemeHandle.PROGRESS: + switch ((PROGRESSPARTS)part) { + case PROGRESSPARTS.PP_BAR: + case PROGRESSPARTS.PP_BARVERT: + GtkPlus.ProgressBarPaintBar (dc, bounds, clipRectangle); + return true; + case PROGRESSPARTS.PP_CHUNK: + case PROGRESSPARTS.PP_CHUNKVERT: + GtkPlus.ProgressBarPaintChunk (dc, bounds, clipRectangle); + return true; + default: return false; + } + #endregion + #region REBAR + case ThemeHandle.REBAR: + switch ((REBARPARTS)part) { + case REBARPARTS.RP_BAND: + GtkPlus.ToolBarPaint (dc, bounds, clipRectangle); + return true; + default: return false; + } + #endregion + #region SCROLLBAR + case ThemeHandle.SCROLLBAR: + switch ((SCROLLBARPARTS)part) { + #region SBP_ARROWBTN + case SCROLLBARPARTS.SBP_ARROWBTN: + bool horizontal; + bool up_or_left; + switch ((ARROWBTNSTATES)state) { + case ARROWBTNSTATES.ABS_UPNORMAL: + gtk_plus_state = GtkPlusState.Normal; + horizontal = false; + up_or_left = true; + break; + case ARROWBTNSTATES.ABS_UPHOT: + gtk_plus_state = GtkPlusState.Hot; + horizontal = false; + up_or_left = true; + break; + case ARROWBTNSTATES.ABS_UPPRESSED: + gtk_plus_state = GtkPlusState.Pressed; + horizontal = false; + up_or_left = true; + break; + case ARROWBTNSTATES.ABS_UPDISABLED: + gtk_plus_state = GtkPlusState.Disabled; + horizontal = false; + up_or_left = true; + break; + case ARROWBTNSTATES.ABS_DOWNNORMAL: + gtk_plus_state = GtkPlusState.Normal; + horizontal = false; + up_or_left = false; + break; + case ARROWBTNSTATES.ABS_DOWNHOT: + gtk_plus_state = GtkPlusState.Hot; + horizontal = false; + up_or_left = false; + break; + case ARROWBTNSTATES.ABS_DOWNPRESSED: + gtk_plus_state = GtkPlusState.Pressed; + horizontal = false; + up_or_left = false; + break; + case ARROWBTNSTATES.ABS_DOWNDISABLED: + gtk_plus_state = GtkPlusState.Disabled; + horizontal = false; + up_or_left = false; + break; + case ARROWBTNSTATES.ABS_LEFTNORMAL: + gtk_plus_state = GtkPlusState.Normal; + horizontal = true; + up_or_left = true; + break; + case ARROWBTNSTATES.ABS_LEFTHOT: + gtk_plus_state = GtkPlusState.Hot; + horizontal = true; + up_or_left = true; + break; + case ARROWBTNSTATES.ABS_LEFTPRESSED: + gtk_plus_state = GtkPlusState.Pressed; + horizontal = true; + up_or_left = true; + break; + case ARROWBTNSTATES.ABS_LEFTDISABLED: + gtk_plus_state = GtkPlusState.Disabled; + horizontal = true; + up_or_left = true; + break; + case ARROWBTNSTATES.ABS_RIGHTNORMAL: + gtk_plus_state = GtkPlusState.Normal; + horizontal = true; + up_or_left = false; + break; + case ARROWBTNSTATES.ABS_RIGHTHOT: + gtk_plus_state = GtkPlusState.Hot; + horizontal = true; + up_or_left = false; + break; + case ARROWBTNSTATES.ABS_RIGHTPRESSED: + gtk_plus_state = GtkPlusState.Pressed; + horizontal = true; + up_or_left = false; + break; + case ARROWBTNSTATES.ABS_RIGHTDISABLED: + gtk_plus_state = GtkPlusState.Disabled; + horizontal = true; + up_or_left = false; + break; + default: return false; + } + GtkPlus.ScrollBarPaintArrowButton (dc, bounds, clipRectangle, gtk_plus_state, horizontal, up_or_left); + return true; + #endregion + #region SBP_THUMBBTNHORZ, SBP_THUMBBTNVERT + case SCROLLBARPARTS.SBP_THUMBBTNHORZ: + case SCROLLBARPARTS.SBP_THUMBBTNVERT: + if (!GetGtkPlusState ((SCROLLBARSTYLESTATES)state, out gtk_plus_state)) + return false; + GtkPlus.ScrollBarPaintThumbButton ( + dc, + bounds, + clipRectangle, + gtk_plus_state, + (SCROLLBARPARTS)part == SCROLLBARPARTS.SBP_THUMBBTNHORZ); + return true; + #endregion + #region SBP_LOWERTRACKHORZ, SBP_UPPERTRACKHORZ, SBP_LOWERTRACKVERT, SBP_UPPERTRACKVERT + case SCROLLBARPARTS.SBP_LOWERTRACKHORZ: + case SCROLLBARPARTS.SBP_UPPERTRACKHORZ: + case SCROLLBARPARTS.SBP_LOWERTRACKVERT: + case SCROLLBARPARTS.SBP_UPPERTRACKVERT: + if (!GetGtkPlusState ((SCROLLBARSTYLESTATES)state, out gtk_plus_state)) + return false; + GtkPlus.ScrollBarPaintTrack ( + dc, + bounds, + clipRectangle, + gtk_plus_state, + (SCROLLBARPARTS)part == SCROLLBARPARTS.SBP_LOWERTRACKHORZ || + (SCROLLBARPARTS)part == SCROLLBARPARTS.SBP_UPPERTRACKHORZ, + (SCROLLBARPARTS)part == SCROLLBARPARTS.SBP_UPPERTRACKHORZ || + (SCROLLBARPARTS)part == SCROLLBARPARTS.SBP_UPPERTRACKVERT); + return true; + #endregion + default: return false; + } + #endregion + #region SPIN + case ThemeHandle.SPIN: + bool up; + switch ((SPINPARTS)part) { + #region SPNP_UP + case SPINPARTS.SPNP_UP: + up = true; + switch ((UPSTATES)state) { + case UPSTATES.UPS_NORMAL: gtk_plus_state = GtkPlusState.Normal; break; + case UPSTATES.UPS_HOT: gtk_plus_state = GtkPlusState.Hot; break; + case UPSTATES.UPS_PRESSED: gtk_plus_state = GtkPlusState.Pressed; break; + case UPSTATES.UPS_DISABLED: gtk_plus_state = GtkPlusState.Disabled; break; + default: return false; + } + break; + #endregion + #region SPNP_DOWN + case SPINPARTS.SPNP_DOWN: + up = false; + switch ((DOWNSTATES)state) { + case DOWNSTATES.DNS_NORMAL: gtk_plus_state = GtkPlusState.Normal; break; + case DOWNSTATES.DNS_HOT: gtk_plus_state = GtkPlusState.Hot; break; + case DOWNSTATES.DNS_PRESSED: gtk_plus_state = GtkPlusState.Pressed; break; + case DOWNSTATES.DNS_DISABLED: gtk_plus_state = GtkPlusState.Disabled; break; + default: return false; + } + break; + #endregion + default: return false; + } + GtkPlus.UpDownPaint (dc, bounds, clipRectangle, up, gtk_plus_state); + return true; + #endregion + #region STATUS + case ThemeHandle.STATUS: + switch ((STATUSPARTS)part) { + case STATUSPARTS.SP_GRIPPER: + GtkPlus.StatusBarPaintGripper (dc, bounds, clipRectangle); + return true; + default: return false; + } + #endregion + #region TABWidget + case ThemeHandle.TAB: + bool selected; + switch ((TABPARTS)part) { + #region TABP_TABITEM + case TABPARTS.TABP_TABITEM: + switch ((TABITEMSTATES)state) { + case TABITEMSTATES.TIS_SELECTED: + selected = true; + break; + case TABITEMSTATES.TIS_NORMAL: + case TABITEMSTATES.TIS_HOT: + case TABITEMSTATES.TIS_DISABLED: + selected = false; + break; + default: return false; + } + break; + #endregion + #region TABP_TABITEMLEFTEDGE + case TABPARTS.TABP_TABITEMLEFTEDGE: + switch ((TABITEMLEFTEDGESTATES)state) { + case TABITEMLEFTEDGESTATES.TILES_SELECTED: + selected = true; + break; + case TABITEMLEFTEDGESTATES.TILES_NORMAL: + case TABITEMLEFTEDGESTATES.TILES_HOT: + case TABITEMLEFTEDGESTATES.TILES_DISABLED: + selected = false; + break; + default: return false; + } + break; + #endregion + #region TABP_TABITEMRIGHTEDGE + case TABPARTS.TABP_TABITEMRIGHTEDGE: + switch ((TABITEMRIGHTEDGESTATES)state) { + case TABITEMRIGHTEDGESTATES.TIRES_SELECTED: + selected = true; + break; + case TABITEMRIGHTEDGESTATES.TIRES_NORMAL: + case TABITEMRIGHTEDGESTATES.TIRES_HOT: + case TABITEMRIGHTEDGESTATES.TIRES_DISABLED: + selected = false; + break; + default: return false; + } + break; + #endregion + #region TABP_TABITEMBOTHEDGE + case TABPARTS.TABP_TABITEMBOTHEDGE: + selected = false; + break; + #endregion + #region TABP_TOPTABITEM + case TABPARTS.TABP_TOPTABITEM: + switch ((TOPTABITEMSTATES)state) { + case TOPTABITEMSTATES.TTIS_SELECTED: + selected = true; + break; + case TOPTABITEMSTATES.TTIS_NORMAL: + case TOPTABITEMSTATES.TTIS_HOT: + case TOPTABITEMSTATES.TTIS_DISABLED: + selected = false; + break; + default: return false; + } + break; + #endregion + #region TABP_TOPTABITEMLEFTEDGE + case TABPARTS.TABP_TOPTABITEMLEFTEDGE: + switch ((TOPTABITEMLEFTEDGESTATES)state) { + case TOPTABITEMLEFTEDGESTATES.TTILES_SELECTED: + selected = true; + break; + case TOPTABITEMLEFTEDGESTATES.TTILES_NORMAL: + case TOPTABITEMLEFTEDGESTATES.TTILES_HOT: + case TOPTABITEMLEFTEDGESTATES.TTILES_DISABLED: + selected = false; + break; + default: return false; + } + break; + #endregion + #region TABP_TOPTABITEMRIGHTEDGE + case TABPARTS.TABP_TOPTABITEMRIGHTEDGE: + switch ((TOPTABITEMRIGHTEDGESTATES)state) { + case TOPTABITEMRIGHTEDGESTATES.TTIRES_SELECTED: + selected = true; + break; + case TOPTABITEMRIGHTEDGESTATES.TTIRES_NORMAL: + case TOPTABITEMRIGHTEDGESTATES.TTIRES_HOT: + case TOPTABITEMRIGHTEDGESTATES.TTIRES_DISABLED: + selected = false; + break; + default: return false; + } + break; + #endregion + #region TABP_TOPTABITEMBOTHEDGE + case TABPARTS.TABP_TOPTABITEMBOTHEDGE: + selected = false; + break; + #endregion + #region TABP_PANE + case TABPARTS.TABP_PANE: + GtkPlus.TabWidgetPaintPane (dc, bounds, clipRectangle); + return true; + #endregion + default: return false; + } + GtkPlus.TabWidgetPaintTabItem (dc, bounds, clipRectangle, selected ? GtkPlusState.Pressed : GtkPlusState.Normal); + return true; + #endregion + #region TOOLBAR + case ThemeHandle.TOOLBAR: + switch ((TOOLBARPARTS)part) { + case TOOLBARPARTS.TP_BUTTON: + switch ((TOOLBARSTYLESTATES)state) { + case TOOLBARSTYLESTATES.TS_NORMAL: + gtk_plus_state = GtkPlusState.Normal; + break; + case TOOLBARSTYLESTATES.TS_HOT: + gtk_plus_state = GtkPlusState.Hot; + break; + case TOOLBARSTYLESTATES.TS_PRESSED: + gtk_plus_state = GtkPlusState.Pressed; + break; + case TOOLBARSTYLESTATES.TS_DISABLED: + gtk_plus_state = GtkPlusState.Disabled; + break; + case TOOLBARSTYLESTATES.TS_CHECKED: + case TOOLBARSTYLESTATES.TS_HOTCHECKED: + GtkPlus.ToolBarPaintCheckedButton (dc, bounds, clipRectangle); + return true; + default: return false; + } + GtkPlus.ToolBarPaintButton (dc, bounds, clipRectangle, gtk_plus_state); + return true; + default: return false; + } + #endregion + #region TRACKBAR + case ThemeHandle.TRACKBAR: + switch ((TRACKBARPARTS)part) { + #region TKP_TRACK + case TRACKBARPARTS.TKP_TRACK: + switch ((TRACKSTATES)state) { + case TRACKSTATES.TRS_NORMAL: + GtkPlus.TrackBarPaintTrack (dc, bounds, clipRectangle, true); + return true; + default: return false; + } + #endregion + #region TKP_TRACKVERT + case TRACKBARPARTS.TKP_TRACKVERT: + switch ((TRACKVERTSTATES)state) { + case TRACKVERTSTATES.TRVS_NORMAL: + GtkPlus.TrackBarPaintTrack (dc, bounds, clipRectangle, false); + return true; + default: return false; + } + #endregion + #region TKP_THUMB + case TRACKBARPARTS.TKP_THUMB: + switch ((THUMBSTATES)state) { + case THUMBSTATES.TUS_NORMAL: + gtk_plus_state = GtkPlusState.Normal; + break; + case THUMBSTATES.TUS_HOT: + gtk_plus_state = GtkPlusState.Hot; + break; + case THUMBSTATES.TUS_PRESSED: + gtk_plus_state = GtkPlusState.Pressed; + break; + case THUMBSTATES.TUS_FOCUSED: + gtk_plus_state = GtkPlusState.Selected; + break; + case THUMBSTATES.TUS_DISABLED: + gtk_plus_state = GtkPlusState.Disabled; + break; + default: return false; + } + GtkPlus.TrackBarPaintThumb (dc, bounds, clipRectangle, gtk_plus_state, true); + return true; + #endregion + #region TKP_THUMBVERT + case TRACKBARPARTS.TKP_THUMBVERT: + switch ((THUMBVERTSTATES)state) { + case THUMBVERTSTATES.TUVS_NORMAL: + gtk_plus_state = GtkPlusState.Normal; + break; + case THUMBVERTSTATES.TUVS_HOT: + gtk_plus_state = GtkPlusState.Hot; + break; + case THUMBVERTSTATES.TUVS_PRESSED: + gtk_plus_state = GtkPlusState.Pressed; + break; + case THUMBVERTSTATES.TUVS_FOCUSED: + gtk_plus_state = GtkPlusState.Selected; + break; + case THUMBVERTSTATES.TUVS_DISABLED: + gtk_plus_state = GtkPlusState.Disabled; + break; + default: return false; + } + GtkPlus.TrackBarPaintThumb (dc, bounds, clipRectangle, gtk_plus_state, false); + return true; + #endregion + default: return false; + } + #endregion + #region TREEVIEW + case ThemeHandle.TREEVIEW: + switch ((TREEVIEWPARTS)part) { + case TREEVIEWPARTS.TVP_GLYPH: + bool closed; + switch ((GLYPHSTATES)state) { + case GLYPHSTATES.GLPS_CLOSED : closed = true; break; + case GLYPHSTATES.GLPS_OPENED: closed = false; break; + default: return false; + } + GtkPlus.TreeViewPaintGlyph (dc, bounds, clipRectangle, closed); + return true; + default: return false; + } + #endregion + default: return false; + } + } + static bool GetGtkPlusState (SCROLLBARSTYLESTATES state, out GtkPlusState result) + { + switch (state) { + case SCROLLBARSTYLESTATES.SCRBS_NORMAL: + result = GtkPlusState.Normal; + break; + case SCROLLBARSTYLESTATES.SCRBS_HOT: + result = GtkPlusState.Hot; + break; + case SCROLLBARSTYLESTATES.SCRBS_PRESSED: + result = GtkPlusState.Pressed; + break; + case SCROLLBARSTYLESTATES.SCRBS_DISABLED: + result = GtkPlusState.Disabled; + break; + default: + result = (GtkPlusState)0; + return false; + } + return true; + } + public int UxThemeDrawThemeEdge (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, Edges edges, EdgeStyle style, EdgeEffects effects, out Rectangle result) + { + result = Rectangle.Empty; + return (int)S.S_FALSE; + } + public int UxThemeDrawThemeText (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, string text, TextFormatFlags textFlags, Rectangle bounds) + { + return (int)S.S_FALSE; + } + public int UxThemeGetThemeBackgroundContentRect (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, out Rectangle result) + { + return (int)(GetBackgroundContentRectangle ((ThemeHandle)(int)hTheme, iPartId, iStateId, bounds, out result) ? S.S_OK : S.S_FALSE); + } + bool GetBackgroundContentRectangle (ThemeHandle handle, int part, int state, Rectangle bounds, out Rectangle result) + { + switch (handle) { + case ThemeHandle.PROGRESS: + switch ((PROGRESSPARTS)part) { + case PROGRESSPARTS.PP_BAR: + case PROGRESSPARTS.PP_BARVERT: + result = GtkPlus.ProgressBarGetBackgroundContentRectagle (bounds); + return true; + } + break; + } + result = Rectangle.Empty; + return false; + } + public int UxThemeGetThemeBackgroundExtent (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle contentBounds, out Rectangle result) + { + result = Rectangle.Empty; + return (int)S.S_FALSE; + } + public int UxThemeGetThemeBackgroundRegion (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, out Region result) + { + result = null; + return (int)S.S_FALSE; + } + public int UxThemeGetThemeBool (IntPtr hTheme, int iPartId, int iStateId, BooleanProperty prop, out bool result) + { + result = false; + return (int)S.S_FALSE; + } + public int UxThemeGetThemeColor (IntPtr hTheme, int iPartId, int iStateId, ColorProperty prop, out Color result) + { + result = Color.Black; + return (int)S.S_FALSE; + } + public int UxThemeGetThemeEnumValue (IntPtr hTheme, int iPartId, int iStateId, EnumProperty prop, out int result) + { + result = 0; + return (int)S.S_FALSE; + } + public int UxThemeGetThemeFilename (IntPtr hTheme, int iPartId, int iStateId, FilenameProperty prop, out string result) + { + result = null; + return (int)S.S_FALSE; + } + public int UxThemeGetThemeInt (IntPtr hTheme, int iPartId, int iStateId, IntegerProperty prop, out int result) + { + return (int)(GetInteger ((ThemeHandle)(int)hTheme, iPartId, iStateId, prop, out result) ? S.S_OK : S.S_FALSE); + } + bool GetInteger (ThemeHandle handle, int part, int state, IntegerProperty property, out int result) + { + switch (handle) { + case ThemeHandle.PROGRESS: + switch ((PROGRESSPARTS)part) { + case PROGRESSPARTS.PP_CHUNK: + case PROGRESSPARTS.PP_CHUNKVERT: + switch (property) { + case IntegerProperty.ProgressChunkSize: + result = ThemeWin32Classic.ProgressBarGetChunkSize (); + return true; + case IntegerProperty.ProgressSpaceSize: + result = ThemeWin32Classic.ProgressBarChunkSpacing; + return true; + } + break; + } + break; + } + result = 0; + return false; + } + public int UxThemeGetThemeMargins (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, MarginProperty prop, out Padding result) + { + result = Padding.Empty; + return (int)S.S_FALSE; + } + public int UxThemeGetThemePartSize (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, ThemeSizeType type, out Size result) + { + return (int)(GetPartSize ((ThemeHandle)(int)hTheme, dc, iPartId, iStateId, bounds, true, type, out result) ? S.S_OK : S.S_FALSE); + } + public int UxThemeGetThemePartSize (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, ThemeSizeType type, out Size result) + { + return (int)(GetPartSize ((ThemeHandle)(int)hTheme, dc, iPartId, iStateId, Rectangle.Empty, false, type, out result) ? S.S_OK : S.S_FALSE); + } + bool GetPartSize (ThemeHandle themeHandle, IDeviceContext dc, int part, int state, Rectangle bounds, bool rectangleSpecified, ThemeSizeType type, out Size result) + { + switch (themeHandle) { + #region BUTTON + case ThemeHandle.BUTTON: + switch ((BUTTONPARTS)part) { + case BUTTONPARTS.BP_RADIOBUTTON: + result = GtkPlus.RadioButtonGetSize (); + return true; + case BUTTONPARTS.BP_CHECKBOX: + result = GtkPlus.CheckBoxGetSize (); + return true; + } + break; + #endregion + #region HEADER + case ThemeHandle.HEADER: + switch ((HEADERPARTS)part) { + case HEADERPARTS.HP_HEADERITEM: + result = new Size (0, ThemeWin32Classic.ListViewGetHeaderHeight ()); + return true; + } + break; + #endregion + #region TRACKBAR + case ThemeHandle.TRACKBAR: + switch ((TRACKBARPARTS)part) { + case TRACKBARPARTS.TKP_TRACK: + result = new Size (0, ThemeWin32Classic.TrackBarHorizontalTrackHeight); + return true; + case TRACKBARPARTS.TKP_TRACKVERT: + result = new Size (ThemeWin32Classic.TrackBarVerticalTrackWidth, 0); + return true; + case TRACKBARPARTS.TKP_THUMB: + case TRACKBARPARTS.TKP_THUMBVERT: + result = ThemeWin32Classic.TrackBarGetThumbSize (); + if ((TRACKBARPARTS)part == TRACKBARPARTS.TKP_THUMBVERT) { + int temporary = result.Width; + result.Width = result.Height; + result.Height = temporary; + } + return true; + } + break; + #endregion + } + result = Size.Empty; + return false; + } + public int UxThemeGetThemePosition (IntPtr hTheme, int iPartId, int iStateId, PointProperty prop, out Point result) + { + result = Point.Empty; + return (int)S.S_FALSE; + } + public int UxThemeGetThemeString (IntPtr hTheme, int iPartId, int iStateId, StringProperty prop, out string result) + { + result = null; + return (int)S.S_FALSE; + } + public int UxThemeGetThemeTextExtent (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, string textToDraw, TextFormatFlags flags, Rectangle bounds, out Rectangle result) + { + result = Rectangle.Empty; + return (int)S.S_FALSE; + } + public int UxThemeGetThemeTextExtent (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, string textToDraw, TextFormatFlags flags, out Rectangle result) + { + result = Rectangle.Empty; + return (int)S.S_FALSE; + } + public int UxThemeGetThemeTextMetrics (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, out TextMetrics result) + { + result = new TextMetrics (); + return (int)S.S_FALSE; + } + public int UxThemeHitTestThemeBackground (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, HitTestOptions options, Rectangle backgroundRectangle, IntPtr hrgn, Point pt, out HitTestCode result) + { + result = HitTestCode.Bottom; + return (int)S.S_FALSE; + } + public bool UxThemeIsAppThemed () + { + return true; + } + public bool UxThemeIsThemeActive () + { + return true; + } + public bool UxThemeIsThemeBackgroundPartiallyTransparent (IntPtr hTheme, int iPartId, int iStateId) + { + return true; + } + public bool UxThemeIsThemePartDefined (IntPtr hTheme, int iPartId) + { + switch ((ThemeHandle)(int)hTheme) { + #region BUTTON + case ThemeHandle.BUTTON: + switch ((BUTTONPARTS)iPartId) { + case BUTTONPARTS.BP_PUSHBUTTON: + case BUTTONPARTS.BP_CHECKBOX: + case BUTTONPARTS.BP_RADIOBUTTON: + case BUTTONPARTS.BP_GROUPBOX: + return true; + default: return false; + } + #endregion + #region COMBOBOX + case ThemeHandle.COMBOBOX: + switch ((COMBOBOXPARTS)iPartId) { + case COMBOBOXPARTS.CP_DROPDOWNBUTTON: + case COMBOBOXPARTS.CP_BORDER: + return true; + default: return false; + } + #endregion + #region EDIT + case ThemeHandle.EDIT: + switch ((EDITPARTS)iPartId) { + case EDITPARTS.EP_EDITTEXT: + return true; + default: return false; + } + #endregion + #region HEADER + case ThemeHandle.HEADER: + switch ((HEADERPARTS)iPartId) { + case HEADERPARTS.HP_HEADERITEM: + return true; + default: return false; + } + #endregion + #region PROGRESS + case ThemeHandle.PROGRESS: + switch ((PROGRESSPARTS)iPartId) { + case PROGRESSPARTS.PP_BAR: + case PROGRESSPARTS.PP_BARVERT: + case PROGRESSPARTS.PP_CHUNK: + case PROGRESSPARTS.PP_CHUNKVERT: + return true; + default: return false; + } + #endregion + #region REBAR + case ThemeHandle.REBAR: + switch ((REBARPARTS)iPartId) { + case REBARPARTS.RP_BAND: + return true; + default: return false; + } + #endregion + #region SCROLLBAR + case ThemeHandle.SCROLLBAR: + switch ((SCROLLBARPARTS)iPartId) { + case SCROLLBARPARTS.SBP_ARROWBTN: + case SCROLLBARPARTS.SBP_THUMBBTNHORZ: + case SCROLLBARPARTS.SBP_THUMBBTNVERT: + case SCROLLBARPARTS.SBP_LOWERTRACKHORZ: + case SCROLLBARPARTS.SBP_UPPERTRACKHORZ: + case SCROLLBARPARTS.SBP_LOWERTRACKVERT: + case SCROLLBARPARTS.SBP_UPPERTRACKVERT: + return true; + default: return false; + } + #endregion + #region SPIN + case ThemeHandle.SPIN: + switch ((SPINPARTS)iPartId) { + case SPINPARTS.SPNP_UP: + case SPINPARTS.SPNP_DOWN: + return true; + default: return false; + } + + #endregion + #region STATUS + case ThemeHandle.STATUS: + switch ((STATUSPARTS)iPartId) { + case STATUSPARTS.SP_GRIPPER: + return true; + default: return false; + } + #endregion + #region TABWidget + case ThemeHandle.TAB: + switch ((TABPARTS)iPartId) { + case TABPARTS.TABP_TABITEM: + case TABPARTS.TABP_TABITEMLEFTEDGE: + case TABPARTS.TABP_TABITEMRIGHTEDGE: + case TABPARTS.TABP_TABITEMBOTHEDGE: + case TABPARTS.TABP_TOPTABITEM: + case TABPARTS.TABP_TOPTABITEMLEFTEDGE: + case TABPARTS.TABP_TOPTABITEMRIGHTEDGE: + case TABPARTS.TABP_TOPTABITEMBOTHEDGE: + case TABPARTS.TABP_PANE: + return true; + default: return false; + } + #endregion + #region TOOLBAR + case ThemeHandle.TOOLBAR: + switch ((TOOLBARPARTS)iPartId) { + case TOOLBARPARTS.TP_BUTTON: + return true; + default: return false; + } + #endregion + #region TRACKBAR + case ThemeHandle.TRACKBAR: + switch ((TRACKBARPARTS)iPartId) { + case TRACKBARPARTS.TKP_TRACK: + case TRACKBARPARTS.TKP_TRACKVERT: + case TRACKBARPARTS.TKP_THUMB: + case TRACKBARPARTS.TKP_THUMBVERT: + return true; + default: return false; + } + #endregion + #region TREEVIEW + case ThemeHandle.TREEVIEW: + switch ((TREEVIEWPARTS)iPartId) { + case TREEVIEWPARTS.TVP_GLYPH: + return true; + default: return false; + } + #endregion + default: return false; + } + } + public IntPtr UxThemeOpenThemeData (IntPtr hWnd, string classList) + { + ThemeHandle theme_handle; + try { + theme_handle = (ThemeHandle)Enum.Parse (typeof (ThemeHandle), classList); + } catch (ArgumentException) { + return IntPtr.Zero; + } + return (IntPtr)(int)theme_handle; + } + #endregion + #region VisualStyleInformation + public string VisualStyleInformationAuthor { + get { + return null; + } + } + public string VisualStyleInformationColorScheme { + get { + return null; + } + } + public string VisualStyleInformationCompany { + get { + return null; + } + } + public Color VisualStyleInformationWidgetHighlightHot { + get { + return Color.Black; + } + } + public string VisualStyleInformationCopyright { + get { + return null; + } + } + public string VisualStyleInformationDescription { + get { + return null; + } + } + public string VisualStyleInformationDisplayName { + get { + return null; + } + } + public string VisualStyleInformationFileName { + get { + return null; + } + } + public bool VisualStyleInformationIsSupportedByOS + { + get { + return true; + } + } + public int VisualStyleInformationMinimumColorDepth { + get { + return 0; + } + } + public string VisualStyleInformationSize { + get { + return null; + } + } + public bool VisualStyleInformationSupportsFlatMenus { + get { + return false; + } + } + public Color VisualStyleInformationTextWidgetBorder { + get { + return Color.Black; + } + } + public string VisualStyleInformationUrl { + get { + return null; + } + } + public string VisualStyleInformationVersion { + get { + return null; + } + } + #endregion + #region VisualStyleRenderer + public void VisualStyleRendererDrawBackgroundExcludingArea (IntPtr theme, IDeviceContext dc, int part, int state, Rectangle bounds, Rectangle excludedArea) + { + DrawBackground ((ThemeHandle)(int)theme, dc, part, state, bounds, bounds, excludedArea); + } + #endregion + } +} diff --git a/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStylesNative.cs b/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStylesNative.cs new file mode 100644 index 0000000..6d304fd --- /dev/null +++ b/source/ShiftUI/System.Windows.Forms.VisualStyles/VisualStylesNative.cs @@ -0,0 +1,455 @@ +// +// VisualStylesNative.cs: IVisualStyles that uses the Visual Styles feature of +// Windows XP and later. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System.Diagnostics; +using System; +using System.Text; + + +namespace ShiftUI.VisualStyles +{ + class VisualStylesNative : IVisualStyles + { + #region UxTheme + public int UxThemeCloseThemeData (IntPtr hTheme) + { + return UXTheme.CloseThemeData (hTheme); + } + public int UxThemeDrawThemeBackground (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds) + { + XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); + + int result = UXTheme.DrawThemeBackground(hTheme, dc.GetHdc (), iPartId, iStateId, ref BoundsRect, IntPtr.Zero); + dc.ReleaseHdc (); + return result; + } + public int UxThemeDrawThemeBackground (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, Rectangle clipRectangle) + { + XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); + XplatUIWin32.RECT ClipRect = XplatUIWin32.RECT.FromRectangle (clipRectangle); + + int result = UXTheme.DrawThemeBackground (hTheme, dc.GetHdc (), iPartId, iStateId, ref BoundsRect, ref ClipRect); + dc.ReleaseHdc (); + return result; + } + public int UxThemeDrawThemeEdge (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, Edges edges, EdgeStyle style, EdgeEffects effects, out Rectangle result) + { + XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); + XplatUIWin32.RECT retval; + + int hresult = UXTheme.DrawThemeEdge (hTheme, dc.GetHdc (), iPartId, iStateId, ref BoundsRect, (uint)style, (uint)edges + (uint)effects, out retval); + dc.ReleaseHdc (); + result = retval.ToRectangle(); + return hresult; + } + public int UxThemeDrawThemeParentBackground (IDeviceContext dc, Rectangle bounds, Widget childWidget) + { + int result; + + XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); + + using (Graphics g = Graphics.FromHwnd (childWidget.Handle)) { + IntPtr hdc = g.GetHdc (); + result = UXTheme.DrawThemeParentBackground (childWidget.Handle, hdc, ref BoundsRect); + g.ReleaseHdc (hdc); + } + + return result; + } + public int UxThemeDrawThemeText (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, string text, TextFormatFlags textFlags, Rectangle bounds) + { + XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); + + int result = UXTheme.DrawThemeText (hTheme, dc.GetHdc (), iPartId, iStateId, text, text.Length, (uint)textFlags, 0, ref BoundsRect); + dc.ReleaseHdc (); + return result; + } + public int UxThemeGetThemeBackgroundContentRect (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, out Rectangle result) + { + XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); + XplatUIWin32.RECT retval; + + int hresult = UXTheme.GetThemeBackgroundContentRect (hTheme, dc.GetHdc (), iPartId, iStateId, ref BoundsRect, out retval); + dc.ReleaseHdc (); + + result = retval.ToRectangle (); + return hresult; + } + public int UxThemeGetThemeBackgroundExtent (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle contentBounds, out Rectangle result) + { + XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (contentBounds); + XplatUIWin32.RECT retval = new XplatUIWin32.RECT (); + + int hresult = UXTheme.GetThemeBackgroundExtent (hTheme, dc.GetHdc (), iPartId, iStateId, ref BoundsRect, ref retval); + dc.ReleaseHdc (); + + result = retval.ToRectangle (); + return hresult; + } + public int UxThemeGetThemeBackgroundRegion (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, out Region result) + { + XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); + IntPtr retval; + + int hresult = UXTheme.GetThemeBackgroundRegion (hTheme, dc.GetHdc (), iPartId, iStateId, ref BoundsRect, out retval); + dc.ReleaseHdc (); + + result = Region.FromHrgn (retval); + return hresult; + } + public int UxThemeGetThemeBool (IntPtr hTheme, int iPartId, int iStateId, BooleanProperty prop, out bool result) + { + int retval; + int hresult = UXTheme.GetThemeBool (hTheme, iPartId, iStateId, (int)prop, out retval); + + result = retval == 0 ? false : true; + return hresult; + } + public int UxThemeGetThemeColor (IntPtr hTheme, int iPartId, int iStateId, ColorProperty prop, out Color result) + { + int retval; + int hresult = UXTheme.GetThemeColor (hTheme, iPartId, iStateId, (int)prop, out retval); + + result = System.Drawing.Color.FromArgb ((int)(0x000000FFU & retval), + (int)(0x0000FF00U & retval) >> 8, (int)(0x00FF0000U & retval) >> 16); + return hresult; + } + public int UxThemeGetThemeEnumValue (IntPtr hTheme, int iPartId, int iStateId, EnumProperty prop, out int result) + { + int retval; + int hresult = UXTheme.GetThemeEnumValue (hTheme, iPartId, iStateId, (int)prop, out retval); + + result = retval; + return hresult; + } + public int UxThemeGetThemeFilename (IntPtr hTheme, int iPartId, int iStateId, FilenameProperty prop, out string result) + { + StringBuilder sb = new StringBuilder (255); + int hresult = UXTheme.GetThemeFilename (hTheme, iPartId, iStateId, (int)prop, sb, sb.Capacity); + + result = sb.ToString (); + return hresult; + } + public int UxThemeGetThemeInt (IntPtr hTheme, int iPartId, int iStateId, IntegerProperty prop, out int result) + { + int retval; + int hresult = UXTheme.GetThemeInt (hTheme, iPartId, iStateId, (int)prop, out retval); + + result = retval; + return hresult; + } + public int UxThemeGetThemeMargins (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, MarginProperty prop, out Padding result) + { + UXTheme.MARGINS retval = new UXTheme.MARGINS (); + XplatUIWin32.RECT BoundsRect; + + int hresult = UXTheme.GetThemeMargins (hTheme, dc.GetHdc (), iPartId, iStateId, (int)prop, out BoundsRect, out retval); + dc.ReleaseHdc (); + + result = retval.ToPadding(); + return hresult; + } + public int UxThemeGetThemePartSize (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, Rectangle bounds, ThemeSizeType type, out Size result) + { + XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); + UXTheme.SIZE retval; + + int hresult = UXTheme.GetThemePartSize (hTheme, dc.GetHdc (), iPartId, iStateId, ref BoundsRect, (int)type, out retval); + dc.ReleaseHdc (); + + result = retval.ToSize(); + return hresult; + } + public int UxThemeGetThemePartSize (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, ThemeSizeType type, out Size result) + { + UXTheme.SIZE retval; + + int hresult = UXTheme.GetThemePartSize (hTheme, dc.GetHdc (), iPartId, iStateId, IntPtr.Zero, (int)type, out retval); + dc.ReleaseHdc (); + + result = retval.ToSize (); + return hresult; + } + public int UxThemeGetThemePosition (IntPtr hTheme, int iPartId, int iStateId, PointProperty prop, out Point result) + { + POINT retval; + int hresult = UXTheme.GetThemePosition (hTheme, iPartId, iStateId, (int)prop, out retval); + + result = retval.ToPoint(); + return hresult; + } + public int UxThemeGetThemeString (IntPtr hTheme, int iPartId, int iStateId, StringProperty prop, out string result) + { + StringBuilder sb = new StringBuilder (255); + int hresult = UXTheme.GetThemeString (hTheme, iPartId, iStateId, (int)prop, sb, sb.Capacity); + + result = sb.ToString (); + return hresult; + } + public int UxThemeGetThemeTextExtent (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, string textToDraw, TextFormatFlags flags, Rectangle bounds, out Rectangle result) + { + XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (bounds); + XplatUIWin32.RECT retval; + + int hresult = UXTheme.GetThemeTextExtent (hTheme, dc.GetHdc (), iPartId, iStateId, textToDraw, textToDraw.Length, (int)flags, ref BoundsRect, out retval); + dc.ReleaseHdc (); + + result = retval.ToRectangle (); + return hresult; + } + public int UxThemeGetThemeTextExtent (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, string textToDraw, TextFormatFlags flags, out Rectangle result) + { + XplatUIWin32.RECT retval; + + int hresult = UXTheme.GetThemeTextExtent (hTheme, dc.GetHdc (), iPartId, iStateId, textToDraw, textToDraw.Length, (int)flags, 0, out retval); + dc.ReleaseHdc (); + + result = retval.ToRectangle (); + return hresult; + } + public int UxThemeGetThemeTextMetrics (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, out TextMetrics result) + { + XplatUIWin32.TEXTMETRIC metrics; + + int hresult = UXTheme.GetThemeTextMetrics (hTheme, dc.GetHdc (), iPartId, iStateId, out metrics); + dc.ReleaseHdc (); + + TextMetrics retval = new TextMetrics (); + retval.Ascent = metrics.tmAscent; + retval.AverageCharWidth = metrics.tmAveCharWidth; + retval.BreakChar =(char)metrics.tmBreakChar; + retval.CharSet = (TextMetricsCharacterSet)metrics.tmCharSet; + retval.DefaultChar = (char)metrics.tmDefaultChar; + retval.Descent = metrics.tmDescent; + retval.DigitizedAspectX = metrics.tmDigitizedAspectX; + retval.DigitizedAspectY = metrics.tmDigitizedAspectY; + retval.ExternalLeading = metrics.tmExternalLeading; + retval.FirstChar = (char)metrics.tmFirstChar; + retval.Height = metrics.tmHeight; + retval.InternalLeading = metrics.tmInternalLeading; + retval.Italic = metrics.tmItalic == 0 ? false : true; + retval.LastChar = (char)metrics.tmLastChar; + retval.MaxCharWidth = metrics.tmMaxCharWidth; + retval.Overhang = metrics.tmOverhang; + retval.PitchAndFamily = (TextMetricsPitchAndFamilyValues)metrics.tmPitchAndFamily; + retval.StruckOut = metrics.tmStruckOut == 0 ? false : true; + retval.Underlined = metrics.tmUnderlined == 0 ? false : true; + retval.Weight = metrics.tmWeight; + + result = retval; + return hresult; + } + public int UxThemeHitTestThemeBackground (IntPtr hTheme, IDeviceContext dc, int iPartId, int iStateId, HitTestOptions options, Rectangle backgroundRectangle, IntPtr hrgn, Point pt, out HitTestCode result) + { + XplatUIWin32.RECT BoundsRect = XplatUIWin32.RECT.FromRectangle (backgroundRectangle); + int retval; + + int hresult = UXTheme.HitTestThemeBackground (hTheme, dc.GetHdc (), iPartId, iStateId, (uint)options, ref BoundsRect, hrgn, new POINT(pt.X, pt.Y), out retval); + dc.ReleaseHdc (); + + result = (HitTestCode)retval; + return hresult; + } + public bool UxThemeIsAppThemed () + { + return UXTheme.IsAppThemed (); + } + public bool UxThemeIsThemeActive () + { + return UXTheme.IsThemeActive (); + } + public bool UxThemeIsThemePartDefined (IntPtr hTheme, int iPartId) + { + return UXTheme.IsThemePartDefined (hTheme, iPartId, 0); + } + public bool UxThemeIsThemeBackgroundPartiallyTransparent (IntPtr hTheme, int iPartId, int iStateId) + { + int retval = UXTheme.IsThemeBackgroundPartiallyTransparent (hTheme, iPartId, iStateId); + + return retval == 0 ? false : true; + } + public IntPtr UxThemeOpenThemeData (IntPtr hWnd, string classList) + { + return UXTheme.OpenThemeData (hWnd, classList); + } + #endregion + #region VisualStyleInformation + public string VisualStyleInformationAuthor { + get { + return GetData ("AUTHOR"); + } + } + public string VisualStyleInformationColorScheme { + get { + StringBuilder ThemeName = new StringBuilder (260); + StringBuilder ColorName = new StringBuilder (260); + StringBuilder SizeName = new StringBuilder (260); + UXTheme.GetCurrentThemeName (ThemeName, ThemeName.Capacity, ColorName, ColorName.Capacity, SizeName, SizeName.Capacity); + + return ColorName.ToString (); + } + } + public string VisualStyleInformationCompany { + get { + return GetData ("COMPANY"); + } + } + public Color VisualStyleInformationWidgetHighlightHot { + get { + IntPtr theme = UXTheme.OpenThemeData (IntPtr.Zero, "BUTTON"); + + uint retval = UXTheme.GetThemeSysColor (theme, 1621); + UXTheme.CloseThemeData (theme); + + return System.Drawing.Color.FromArgb ((int)(0x000000FFU & retval), + (int)(0x0000FF00U & retval) >> 8, (int)(0x00FF0000U & retval) >> 16); + } + } + public string VisualStyleInformationCopyright { + get { + return GetData ("COPYRIGHT"); + } + } + public string VisualStyleInformationDescription { + get { + return GetData ("DESCRIPTION"); + } + } + public string VisualStyleInformationDisplayName { + get { + return GetData ("DISPLAYNAME"); + } + } + public string VisualStyleInformationFileName { + get { + StringBuilder ThemeName = new StringBuilder (260); + StringBuilder ColorName = new StringBuilder (260); + StringBuilder SizeName = new StringBuilder (260); + UXTheme.GetCurrentThemeName (ThemeName, ThemeName.Capacity, ColorName, ColorName.Capacity, SizeName, SizeName.Capacity); + + return ThemeName.ToString (); + } + } + static string GetData (string propertyName) + { + StringBuilder ThemeName = new StringBuilder (260); + StringBuilder ColorName = new StringBuilder (260); + StringBuilder SizeName = new StringBuilder (260); + + UXTheme.GetCurrentThemeName (ThemeName, ThemeName.Capacity, ColorName, ColorName.Capacity, SizeName, SizeName.Capacity); + + StringBuilder PropertyValue = new StringBuilder (260); + + UXTheme.GetThemeDocumentationProperty (ThemeName.ToString(), propertyName, PropertyValue, PropertyValue.Capacity); + + return PropertyValue.ToString (); + } + public bool VisualStyleInformationIsSupportedByOS { + get { + return IsSupported (); + } + } + public int VisualStyleInformationMinimumColorDepth { + get { + IntPtr theme = UXTheme.OpenThemeData (IntPtr.Zero, "BUTTON"); + int retval; + + UXTheme.GetThemeSysInt (theme, 1301, out retval); + UXTheme.CloseThemeData (theme); + + return retval; + } + } + public static bool IsSupported () + { + // Supported OS's should be NT based and at least XP (XP, 2003, Vista) + if ((Environment.OSVersion.Platform == PlatformID.Win32NT) && (Environment.OSVersion.Version >= new Version (5, 1))) + return true; + + return false; + } + public string VisualStyleInformationSize { + get { + StringBuilder ThemeName = new StringBuilder (260); + StringBuilder ColorName = new StringBuilder (260); + StringBuilder SizeName = new StringBuilder (260); + UXTheme.GetCurrentThemeName (ThemeName, ThemeName.Capacity, ColorName, ColorName.Capacity, SizeName, SizeName.Capacity); + + return SizeName.ToString (); + } + } + public bool VisualStyleInformationSupportsFlatMenus { + get { + IntPtr theme = UXTheme.OpenThemeData (IntPtr.Zero, "BUTTON"); + bool retval; + + retval = UXTheme.GetThemeSysBool (theme, 1001) == 0 ? false : true; + UXTheme.CloseThemeData (theme); + + return retval; + } + } + public Color VisualStyleInformationTextWidgetBorder { + get { + IntPtr theme = UXTheme.OpenThemeData (IntPtr.Zero, "EDIT"); + + uint retval = UXTheme.GetThemeSysColor (theme, 1611); + UXTheme.CloseThemeData (theme); + + return System.Drawing.Color.FromArgb ((int)(0x000000FFU & retval), + (int)(0x0000FF00U & retval) >> 8, (int)(0x00FF0000U & retval) >> 16); + } + } + public string VisualStyleInformationUrl { + get { + return GetData ("URL"); + } + } + public string VisualStyleInformationVersion { + get { + return GetData ("VERSION"); + } + } + #endregion + #region VisualStyleRenderer + public void VisualStyleRendererDrawBackgroundExcludingArea (IntPtr theme, IDeviceContext dc, int part, int state, Rectangle bounds, Rectangle excludedArea) + { + XplatUIWin32.RECT bounds_rect = XplatUIWin32.RECT.FromRectangle (bounds); + IntPtr hdc = dc.GetHdc (); + XplatUIWin32.Win32ExcludeClipRect (hdc, excludedArea.Left, excludedArea.Top, excludedArea.Right, excludedArea.Bottom); + UXTheme.DrawThemeBackground (theme, hdc, part, state, ref bounds_rect, IntPtr.Zero); + IntPtr hrgn = XplatUIWin32.Win32CreateRectRgn (excludedArea.Left, excludedArea.Top, excludedArea.Right, excludedArea.Bottom); + XplatUIWin32.Win32ExtSelectClipRgn (hdc, hrgn, (int)ClipCombineMode.RGN_OR); + XplatUIWin32.Win32DeleteObject (hrgn); + dc.ReleaseHdc (); + } + #endregion + } +} diff --git a/source/ShiftUI/Theming/Default/.gitattributes b/source/ShiftUI/Theming/Default/.gitattributes new file mode 100644 index 0000000..fdf3545 --- /dev/null +++ b/source/ShiftUI/Theming/Default/.gitattributes @@ -0,0 +1,5 @@ +/ButtonPainter.cs -crlf +/CheckBoxPainter.cs -crlf +/RadioButtonPainter.cs -crlf +/TabWidgetPainter.cs -crlf +/ToolStripPainter.cs -crlf diff --git a/source/ShiftUI/Theming/Default/ButtonPainter.cs b/source/ShiftUI/Theming/Default/ButtonPainter.cs new file mode 100644 index 0000000..366b17d --- /dev/null +++ b/source/ShiftUI/Theming/Default/ButtonPainter.cs @@ -0,0 +1,189 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Andreia Gaita (avidigal@novell.com) + +using System; +using System.Drawing; + +namespace ShiftUI.Theming.Default +{ + /// + /// Summary description for Button. + /// + internal class ButtonPainter + { + public ButtonPainter () + { + + } + + protected SystemResPool ResPool { get { return ThemeEngine.Current.ResPool; } } + + #region Buttons + #region Standard Button + public virtual void Draw (Graphics g, Rectangle bounds, ButtonThemeState state, Color backColor, Color foreColor) { + bool is_themecolor = backColor.ToArgb () == ThemeEngine.Current.ColorControl.ToArgb () || backColor == Color.Empty ? true : false; + CPColor cpcolor = is_themecolor ? CPColor.Empty : ResPool.GetCPColor (backColor); + Pen pen; + + switch (state) { + case ButtonThemeState.Normal: + case ButtonThemeState.Entered: + case ButtonThemeState.Disabled: + pen = is_themecolor ? SystemPens.ControlLightLight : ResPool.GetPen (cpcolor.LightLight); + g.DrawLine (pen, bounds.X, bounds.Y, bounds.X, bounds.Bottom - 2); + g.DrawLine (pen, bounds.X + 1, bounds.Y, bounds.Right - 2, bounds.Y); + + pen = is_themecolor ? SystemPens.Control : ResPool.GetPen (backColor); + g.DrawLine (pen, bounds.X + 1, bounds.Y + 1, bounds.X + 1, bounds.Bottom - 3); + g.DrawLine (pen, bounds.X + 2, bounds.Y + 1, bounds.Right - 3, bounds.Y + 1); + + pen = is_themecolor ? SystemPens.ControlDark : ResPool.GetPen (cpcolor.Dark); + g.DrawLine (pen, bounds.X + 1, bounds.Bottom - 2, bounds.Right - 2, bounds.Bottom - 2); + g.DrawLine (pen, bounds.Right - 2, bounds.Y + 1, bounds.Right - 2, bounds.Bottom - 3); + + pen = is_themecolor ? SystemPens.ControlDarkDark : ResPool.GetPen (cpcolor.DarkDark); + g.DrawLine (pen, bounds.X, bounds.Bottom - 1, bounds.Right - 1, bounds.Bottom - 1); + g.DrawLine (pen, bounds.Right - 1, bounds.Y, bounds.Right - 1, bounds.Bottom - 2); + break; + case ButtonThemeState.Pressed: + g.DrawRectangle (ResPool.GetPen (foreColor), bounds.X, bounds.Y, bounds.Width - 1, bounds.Height - 1); + + bounds.Inflate (-1, -1); + pen = is_themecolor ? SystemPens.ControlDark : ResPool.GetPen (cpcolor.Dark); + g.DrawRectangle (pen, bounds.X, bounds.Y, bounds.Width - 1, bounds.Height - 1); + break; + case ButtonThemeState.Default: + g.DrawRectangle (ResPool.GetPen (foreColor), bounds.X, bounds.Y, bounds.Width - 1, bounds.Height - 1); + + bounds.Inflate (-1, -1); + pen = is_themecolor ? SystemPens.ControlLightLight : ResPool.GetPen (cpcolor.LightLight); + g.DrawLine (pen, bounds.X, bounds.Y, bounds.X, bounds.Bottom - 2); + g.DrawLine (pen, bounds.X + 1, bounds.Y, bounds.Right - 2, bounds.Y); + + pen = is_themecolor ? SystemPens.Control : ResPool.GetPen (backColor); + g.DrawLine (pen, bounds.X + 1, bounds.Y + 1, bounds.X + 1, bounds.Bottom - 3); + g.DrawLine (pen, bounds.X + 2, bounds.Y + 1, bounds.Right - 3, bounds.Y + 1); + + pen = is_themecolor ? SystemPens.ControlDark : ResPool.GetPen (cpcolor.Dark); + g.DrawLine (pen, bounds.X + 1, bounds.Bottom - 2, bounds.Right - 2, bounds.Bottom - 2); + g.DrawLine (pen, bounds.Right - 2, bounds.Y + 1, bounds.Right - 2, bounds.Bottom - 3); + + pen = is_themecolor ? SystemPens.ControlDarkDark : ResPool.GetPen (cpcolor.DarkDark); + g.DrawLine (pen, bounds.X, bounds.Bottom - 1, bounds.Right - 1, bounds.Bottom - 1); + g.DrawLine (pen, bounds.Right - 1, bounds.Y, bounds.Right - 1, bounds.Bottom - 2); + break; + } + } + #endregion + + #region FlatStyle Button + public virtual void DrawFlat (Graphics g, Rectangle bounds, ButtonThemeState state, Color backColor, Color foreColor, FlatButtonAppearance appearance) { + bool is_themecolor = backColor.ToArgb () == ThemeEngine.Current.ColorControl.ToArgb () || backColor == Color.Empty ? true : false; + CPColor cpcolor = is_themecolor ? CPColor.Empty : ResPool.GetCPColor (backColor); + Pen pen; + + switch (state) { + case ButtonThemeState.Normal: + case ButtonThemeState.Disabled: + // This will just use the BackColor + break; + case ButtonThemeState.Entered: + case ButtonThemeState.Default | ButtonThemeState.Entered: + if (appearance.MouseOverBackColor != Color.Empty) + g.FillRectangle (ResPool.GetSolidBrush (appearance.MouseOverBackColor), bounds); + else + g.FillRectangle (ResPool.GetSolidBrush (ChangeIntensity (backColor, .9F)), bounds); + break; + case ButtonThemeState.Pressed: + if (appearance.MouseDownBackColor != Color.Empty) + g.FillRectangle (ResPool.GetSolidBrush (appearance.MouseDownBackColor), bounds); + else + g.FillRectangle (ResPool.GetSolidBrush (ChangeIntensity (backColor, .95F)), bounds); + break; + case ButtonThemeState.Default: + if (appearance.CheckedBackColor != Color.Empty) + g.FillRectangle (ResPool.GetSolidBrush (appearance.CheckedBackColor), bounds); + break; + } + + if (appearance.BorderColor == Color.Empty) + pen = is_themecolor ? SystemPens.ControlDarkDark : ResPool.GetSizedPen (cpcolor.DarkDark, appearance.BorderSize); + else + pen = ResPool.GetSizedPen (appearance.BorderColor, appearance.BorderSize); + + bounds.Width -= 1; + bounds.Height -= 1; + + if (appearance.BorderSize > 0) + g.DrawRectangle (pen, bounds); + } + #endregion + + #region Popup Button + public virtual void DrawPopup (Graphics g, Rectangle bounds, ButtonThemeState state, Color backColor, Color foreColor) { + bool is_themecolor = backColor.ToArgb () == ThemeEngine.Current.ColorControl.ToArgb () || backColor == Color.Empty ? true : false; + CPColor cpcolor = is_themecolor ? CPColor.Empty : ResPool.GetCPColor (backColor); + Pen pen; + + switch (state) { + case ButtonThemeState.Normal: + case ButtonThemeState.Disabled: + case ButtonThemeState.Pressed: + case ButtonThemeState.Default: + pen = is_themecolor ? SystemPens.ControlDarkDark : ResPool.GetPen (cpcolor.DarkDark); + + bounds.Width -= 1; + bounds.Height -= 1; + g.DrawRectangle (pen, bounds); + + if (state == ButtonThemeState.Default || state == ButtonThemeState.Pressed) { + bounds.Inflate (-1, -1); + g.DrawRectangle (pen, bounds); + } + break; + case ButtonThemeState.Entered: + pen = is_themecolor ? SystemPens.ControlLightLight : ResPool.GetPen (cpcolor.LightLight); + g.DrawLine (pen, bounds.X, bounds.Y, bounds.X, bounds.Bottom - 2); + g.DrawLine (pen, bounds.X + 1, bounds.Y, bounds.Right - 2, bounds.Y); + + pen = is_themecolor ? SystemPens.ControlDark : ResPool.GetPen (cpcolor.Dark); + g.DrawLine (pen, bounds.X, bounds.Bottom - 1, bounds.Right - 1, bounds.Bottom - 1); + g.DrawLine (pen, bounds.Right - 1, bounds.Y, bounds.Right - 1, bounds.Bottom - 2); + break; + } + } + #endregion + #endregion + + private static Color ChangeIntensity (Color baseColor, float percent) + { + int H, I, S; + + WidgetPaint.Color2HBS (baseColor, out H, out I, out S); + int NewIntensity = Math.Min (255, (int)(I * percent)); + + return WidgetPaint.HBS2Color (H, NewIntensity, S); + } + } +} diff --git a/source/ShiftUI/Theming/Default/CheckBoxPainter.cs b/source/ShiftUI/Theming/Default/CheckBoxPainter.cs new file mode 100644 index 0000000..a759fbf --- /dev/null +++ b/source/ShiftUI/Theming/Default/CheckBoxPainter.cs @@ -0,0 +1,357 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; + +namespace ShiftUI.Theming.Default +{ + /// + /// Summary description for Button. + /// + internal class CheckBoxPainter + { + public CheckBoxPainter () + { + } + + protected SystemResPool ResPool { get { return ThemeEngine.Current.ResPool; } } + + public void PaintCheckBox (Graphics g, Rectangle bounds, Color backColor, Color foreColor, ElementState state, FlatStyle style, CheckState checkState) + { + switch (style) { + case FlatStyle.Standard: + case FlatStyle.System: + switch (state) { + case ElementState.Normal: + DrawNormalCheckBox (g, bounds, backColor, foreColor, checkState); + break; + case ElementState.Hot: + DrawHotCheckBox (g, bounds, backColor, foreColor, checkState); + break; + case ElementState.Pressed: + DrawPressedCheckBox (g, bounds, backColor, foreColor, checkState); + break; + case ElementState.Disabled: + DrawDisabledCheckBox (g, bounds, backColor, foreColor, checkState); + break; + } + break; + case FlatStyle.Flat: + switch (state) { + case ElementState.Normal: + DrawFlatNormalCheckBox (g, bounds, backColor, foreColor, checkState); + break; + case ElementState.Hot: + DrawFlatHotCheckBox (g, bounds, backColor, foreColor, checkState); + break; + case ElementState.Pressed: + DrawFlatPressedCheckBox (g, bounds, backColor, foreColor, checkState); + break; + case ElementState.Disabled: + DrawFlatDisabledCheckBox (g, bounds, backColor, foreColor, checkState); + break; + } + break; + case FlatStyle.Popup: + switch (state) { + case ElementState.Normal: + DrawPopupNormalCheckBox (g, bounds, backColor, foreColor, checkState); + break; + case ElementState.Hot: + DrawPopupHotCheckBox (g, bounds, backColor, foreColor, checkState); + break; + case ElementState.Pressed: + DrawPopupPressedCheckBox (g, bounds, backColor, foreColor, checkState); + break; + case ElementState.Disabled: + DrawPopupDisabledCheckBox (g, bounds, backColor, foreColor, checkState); + break; + } + break; + } + } + + #region Standard + public virtual void DrawNormalCheckBox (Graphics g, Rectangle bounds, Color backColor, Color foreColor, CheckState state) + { + int check_box_visible_size = (bounds.Height > bounds.Width) ? bounds.Width : bounds.Height; + int x_pos = Math.Max (0, bounds.X + (bounds.Width / 2) - check_box_visible_size / 2); + int y_pos = Math.Max (0, bounds.Y + (bounds.Height / 2) - check_box_visible_size / 2); + + Rectangle rect = new Rectangle (x_pos, y_pos, check_box_visible_size, check_box_visible_size); + + g.FillRectangle (SystemBrushes.ControlLightLight, rect.X + 2, rect.Y + 2, rect.Width - 3, rect.Height - 3); + + Pen pen = SystemPens.ControlDark; + g.DrawLine (pen, rect.X, rect.Y, rect.X, rect.Bottom - 2); + g.DrawLine (pen, rect.X + 1, rect.Y, rect.Right - 2, rect.Y); + + pen = SystemPens.ControlDarkDark; + g.DrawLine (pen, rect.X + 1, rect.Y + 1, rect.X + 1, rect.Bottom - 3); + g.DrawLine (pen, rect.X + 2, rect.Y + 1, rect.Right - 3, rect.Y + 1); + + pen = SystemPens.ControlLightLight; + g.DrawLine (pen, rect.Right - 1, rect.Y, rect.Right - 1, rect.Bottom - 1); + g.DrawLine (pen, rect.X, rect.Bottom - 1, rect.Right - 1, rect.Bottom - 1); + + // oh boy, matching ms is like fighting against windmills + using (Pen h_pen = new Pen (ResPool.GetHatchBrush (HatchStyle.Percent50, + Color.FromArgb (Clamp (ColorControl.R + 3, 0, 255), + ColorControl.G, ColorControl.B), ColorControl))) { + g.DrawLine (h_pen, rect.X + 1, rect.Bottom - 2, rect.Right - 2, rect.Bottom - 2); + g.DrawLine (h_pen, rect.Right - 2, rect.Y + 1, rect.Right - 2, rect.Bottom - 2); + } + + if (state == CheckState.Checked) + DrawCheck (g, bounds, Color.Black); + else if (state == CheckState.Indeterminate) + DrawCheck (g, bounds, SystemColors.ControlDark); + } + + public virtual void DrawHotCheckBox (Graphics g, Rectangle bounds, Color backColor, Color foreColor, CheckState state) + { + DrawNormalCheckBox (g, bounds, backColor, foreColor, state); + } + + public virtual void DrawPressedCheckBox (Graphics g, Rectangle bounds, Color backColor, Color foreColor, CheckState state) + { + int check_box_visible_size = (bounds.Height > bounds.Width) ? bounds.Width : bounds.Height; + int x_pos = Math.Max (0, bounds.X + (bounds.Width / 2) - check_box_visible_size / 2); + int y_pos = Math.Max (0, bounds.Y + (bounds.Height / 2) - check_box_visible_size / 2); + + Rectangle rect = new Rectangle (x_pos, y_pos, check_box_visible_size, check_box_visible_size); + + g.FillRectangle (ResPool.GetHatchBrush (HatchStyle.Percent50, + Color.FromArgb (Clamp (ColorControl.R + 3, 0, 255), + ColorControl.G, ColorControl.B), + ColorControl), rect.X + 2, rect.Y + 2, rect.Width - 3, rect.Height - 3); + + Pen pen = SystemPens.ControlDark; + g.DrawLine (pen, rect.X, rect.Y, rect.X, rect.Bottom - 2); + g.DrawLine (pen, rect.X + 1, rect.Y, rect.Right - 2, rect.Y); + + pen = SystemPens.ControlDarkDark; + g.DrawLine (pen, rect.X + 1, rect.Y + 1, rect.X + 1, rect.Bottom - 3); + g.DrawLine (pen, rect.X + 2, rect.Y + 1, rect.Right - 3, rect.Y + 1); + + pen = SystemPens.ControlLightLight; + g.DrawLine (pen, rect.Right - 1, rect.Y, rect.Right - 1, rect.Bottom - 1); + g.DrawLine (pen, rect.X, rect.Bottom - 1, rect.Right - 1, rect.Bottom - 1); + + // oh boy, matching ms is like fighting against windmills + using (Pen h_pen = new Pen (ResPool.GetHatchBrush (HatchStyle.Percent50, + Color.FromArgb (Clamp (ColorControl.R + 3, 0, 255), + ColorControl.G, ColorControl.B), ColorControl))) { + g.DrawLine (h_pen, rect.X + 1, rect.Bottom - 2, rect.Right - 2, rect.Bottom - 2); + g.DrawLine (h_pen, rect.Right - 2, rect.Y + 1, rect.Right - 2, rect.Bottom - 2); + } + + if (state == CheckState.Checked) + DrawCheck (g, bounds, Color.Black); + else if (state == CheckState.Indeterminate) + DrawCheck (g, bounds, SystemColors.ControlDarkDark); + } + + public virtual void DrawDisabledCheckBox (Graphics g, Rectangle bounds, Color backColor, Color foreColor, CheckState state) + { + DrawPressedCheckBox (g, bounds, backColor, foreColor, CheckState.Unchecked); + + if (state == CheckState.Checked || state == CheckState.Indeterminate) + DrawCheck (g, bounds, SystemColors.ControlDark); + } + #endregion + + #region FlatStyle + public virtual void DrawFlatNormalCheckBox (Graphics g, Rectangle bounds, Color backColor, Color foreColor, CheckState state) + { + Rectangle checkbox_rectangle; + Rectangle fill_rectangle; + + // set up our rectangles first + // clip two pixels from bottom right for non popup rendered checkboxes + checkbox_rectangle = new Rectangle (bounds.X, bounds.Y, Math.Max (bounds.Width - 2, 0), Math.Max (bounds.Height - 2, 0)); + fill_rectangle = new Rectangle (checkbox_rectangle.X + 1, checkbox_rectangle.Y + 1, Math.Max (checkbox_rectangle.Width - 2, 0), Math.Max (checkbox_rectangle.Height - 2, 0)); + + g.FillRectangle (ResPool.GetSolidBrush (WidgetPaint.LightLight (backColor)), fill_rectangle); + WidgetPaint.DrawBorder (g, checkbox_rectangle, foreColor, ButtonBorderStyle.Solid); + + bounds.Offset (-1, 0); + + if (state == CheckState.Checked) + DrawCheck (g, bounds, Color.Black); + else if (state == CheckState.Indeterminate) + DrawCheck (g, bounds, SystemColors.ControlDarkDark); + } + + public virtual void DrawFlatHotCheckBox (Graphics g, Rectangle bounds, Color backColor, Color foreColor, CheckState state) + { + Rectangle checkbox_rectangle; + Rectangle fill_rectangle; + + // set up our rectangles first + // clip two pixels from bottom right for non popup rendered checkboxes + checkbox_rectangle = new Rectangle (bounds.X, bounds.Y, Math.Max (bounds.Width - 2, 0), Math.Max (bounds.Height - 2, 0)); + fill_rectangle = new Rectangle (checkbox_rectangle.X + 1, checkbox_rectangle.Y + 1, Math.Max (checkbox_rectangle.Width - 2, 0), Math.Max (checkbox_rectangle.Height - 2, 0)); + + g.FillRectangle (ResPool.GetSolidBrush (backColor), fill_rectangle); + WidgetPaint.DrawBorder (g, checkbox_rectangle, foreColor, ButtonBorderStyle.Solid); + + bounds.Offset (-1, 0); + + if (state == CheckState.Checked) + DrawCheck (g, bounds, Color.Black); + else if (state == CheckState.Indeterminate) + DrawCheck (g, bounds, SystemColors.ControlDarkDark); + } + + public virtual void DrawFlatPressedCheckBox (Graphics g, Rectangle bounds, Color backColor, Color foreColor, CheckState state) + { + DrawFlatNormalCheckBox (g, bounds, backColor, foreColor, state); + } + + public virtual void DrawFlatDisabledCheckBox (Graphics g, Rectangle bounds, Color backColor, Color foreColor, CheckState state) + { + Rectangle checkbox_rectangle; + + checkbox_rectangle = new Rectangle (bounds.X, bounds.Y, Math.Max (bounds.Width - 2, 0), Math.Max (bounds.Height - 2, 0)); + + WidgetPaint.DrawBorder (g, checkbox_rectangle, foreColor, ButtonBorderStyle.Solid); + + bounds.Offset (-1, 0); + + if (state == CheckState.Checked || state == CheckState.Indeterminate) + DrawCheck (g, bounds, SystemColors.ControlDarkDark); + } + #endregion + + #region Popup + public virtual void DrawPopupNormalCheckBox (Graphics g, Rectangle bounds, Color backColor, Color foreColor, CheckState state) + { + DrawFlatNormalCheckBox (g, bounds, backColor, foreColor, state); + } + + public virtual void DrawPopupHotCheckBox (Graphics g, Rectangle bounds, Color backColor, Color foreColor, CheckState state) + { + Rectangle checkbox_rectangle; + Rectangle fill_rectangle; + + // clip one pixel from bottom right for non popup rendered checkboxes + checkbox_rectangle = new Rectangle (bounds.X, bounds.Y, Math.Max (bounds.Width - 1, 0), Math.Max (bounds.Height - 1, 0)); + fill_rectangle = new Rectangle (checkbox_rectangle.X + 1, checkbox_rectangle.Y + 1, Math.Max (checkbox_rectangle.Width - 3, 0), Math.Max (checkbox_rectangle.Height - 3, 0)); + + g.FillRectangle (ResPool.GetSolidBrush (WidgetPaint.LightLight (backColor)), fill_rectangle); + + // draw sunken effect + ThemeEngine.Current.CPDrawBorder3D (g, checkbox_rectangle, Border3DStyle.SunkenInner, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom, backColor); + + bounds.Offset (-1, 0); + + if (state == CheckState.Checked) + DrawCheck (g, bounds, Color.Black); + else if (state == CheckState.Indeterminate) + DrawCheck (g, bounds, SystemColors.ControlDarkDark); + } + + public virtual void DrawPopupPressedCheckBox (Graphics g, Rectangle bounds, Color backColor, Color foreColor, CheckState state) + { + Rectangle checkbox_rectangle; + Rectangle fill_rectangle; + + // clip one pixel from bottom right for non popup rendered checkboxes + checkbox_rectangle = new Rectangle (bounds.X, bounds.Y, Math.Max (bounds.Width - 1, 0), Math.Max (bounds.Height - 1, 0)); + fill_rectangle = new Rectangle (checkbox_rectangle.X + 1, checkbox_rectangle.Y + 1, Math.Max (checkbox_rectangle.Width - 3, 0), Math.Max (checkbox_rectangle.Height - 3, 0)); + + g.FillRectangle (ResPool.GetSolidBrush (backColor), fill_rectangle); + + // draw sunken effect + ThemeEngine.Current.CPDrawBorder3D (g, checkbox_rectangle, Border3DStyle.SunkenInner, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom, backColor); + + bounds.Offset (-1, 0); + + if (state == CheckState.Checked) + DrawCheck (g, bounds, Color.Black); + else if (state == CheckState.Indeterminate) + DrawCheck (g, bounds, SystemColors.ControlDarkDark); + } + + public virtual void DrawPopupDisabledCheckBox (Graphics g, Rectangle bounds, Color backColor, Color foreColor, CheckState state) + { + DrawFlatDisabledCheckBox (g, bounds, backColor, foreColor, state); + } + #endregion + + #region Check + public virtual void DrawCheck (Graphics g, Rectangle bounds, Color checkColor) + { + int check_size = (bounds.Height > bounds.Width) ? bounds.Width / 2 : bounds.Height / 2; + + Pen check_pen = ResPool.GetPen (checkColor); + + if (check_size < 7) { + int lineWidth = Math.Max (3, check_size / 3); + int Scale = Math.Max (1, check_size / 9); + + Rectangle rect = new Rectangle (bounds.X + (bounds.Width / 2) - (check_size / 2) - 1, bounds.Y + (bounds.Height / 2) - (check_size / 2) - 1, + check_size, check_size); + + for (int i = 0; i < lineWidth; i++) { + g.DrawLine (check_pen, rect.Left + lineWidth / 2, rect.Top + lineWidth + i, rect.Left + lineWidth / 2 + 2 * Scale, rect.Top + lineWidth + 2 * Scale + i); + g.DrawLine (check_pen, rect.Left + lineWidth / 2 + 2 * Scale, rect.Top + lineWidth + 2 * Scale + i, rect.Left + lineWidth / 2 + 6 * Scale, rect.Top + lineWidth - 2 * Scale + i); + } + } else { + int lineWidth = Math.Max (3, check_size / 3) + 1; + + int x_half = bounds.Width / 2; + int y_half = bounds.Height / 2; + + Rectangle rect = new Rectangle (bounds.X + x_half - (check_size / 2) - 1, bounds.Y + y_half - (check_size / 2), + check_size, check_size); + + int gradient_left = check_size / 3; + int gradient_right = check_size - gradient_left - 1; + + for (int i = 0; i < lineWidth; i++) { + g.DrawLine (check_pen, rect.X, rect.Bottom - 1 - gradient_left - i, rect.X + gradient_left, rect.Bottom - 1 - i); + g.DrawLine (check_pen, rect.X + gradient_left, rect.Bottom - 1 - i, rect.Right - 1, rect.Bottom - i - 1 - gradient_right); + } + } + } + #endregion + + #region Private Methods + private int Clamp (int value, int lower, int upper) + { + if (value < lower) return lower; + else if (value > upper) return upper; + else return value; + } + + private Color ColorControl { + get { return SystemColors.Control; } + } + #endregion + } +} diff --git a/source/ShiftUI/Theming/Default/LabelPainter.cs b/source/ShiftUI/Theming/Default/LabelPainter.cs new file mode 100644 index 0000000..15ca995 --- /dev/null +++ b/source/ShiftUI/Theming/Default/LabelPainter.cs @@ -0,0 +1,57 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Everaldo Canuto (ecanuto@novell.com) + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; + +namespace ShiftUI.Theming.Default +{ + internal class LabelPainter + { + public LabelPainter () + { + } + + public virtual void Draw (Graphics dc, Rectangle client_rectangle, Label label) + { + Rectangle rect = label.PaddingClientRectangle; + + label.DrawImage (dc, label.Image, rect, label.ImageAlign); + + if (label.Enabled) { + dc.DrawString (label.Text, label.Font, + ThemeEngine.Current.ResPool.GetSolidBrush (label.ForeColor), + rect, label.string_format); + } else { + WidgetPaint.DrawStringDisabled ( + dc, label.Text, label.Font, label.BackColor, rect, label.string_format); + } + } + + public virtual Size DefaultSize { + get { return new Size (100, 23); } + } + } +} \ No newline at end of file diff --git a/source/ShiftUI/Theming/Default/LinkLabelPainter.cs b/source/ShiftUI/Theming/Default/LinkLabelPainter.cs new file mode 100644 index 0000000..6ac39a0 --- /dev/null +++ b/source/ShiftUI/Theming/Default/LinkLabelPainter.cs @@ -0,0 +1,120 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Everaldo Canuto (ecanuto@novell.com) + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; + +namespace ShiftUI.Theming.Default +{ + internal class LinkLabelPainter + { + public LinkLabelPainter () + { + } + + private Color GetPieceColor (LinkLabel label, LinkLabel.Piece piece, int i) + { + if (!label.Enabled) + return label.DisabledLinkColor; + + if (piece.link == null) + return label.ForeColor; + + if (!piece.link.Enabled) + return label.DisabledLinkColor; + + if (piece.link.Active) + return label.ActiveLinkColor; + + if ((label.LinkVisited && i == 0) || piece.link.Visited) + return label.VisitedLinkColor; + + return label.LinkColor; + } + + public virtual void Draw (Graphics dc, Rectangle clip_rectangle, LinkLabel label) + { + Rectangle client_rect = label.PaddingClientRectangle; + + label.DrawImage (dc, label.Image, client_rect, label.ImageAlign); + + if (label.pieces == null) + return; + + // Paint all text as disabled. + if (!label.Enabled) { + dc.SetClip (clip_rectangle); + ThemeEngine.Current.CPDrawStringDisabled ( + dc, label.Text, label.Font, label.BackColor, client_rect, label.string_format); + return; + } + + Font font, link_font = ThemeEngine.Current.GetLinkFont (label); + + Region text_region = new Region (new Rectangle()); + + // Draw links. + for (int i = 0; i < label.pieces.Length; i ++) { + LinkLabel.Piece piece = label.pieces[i]; + + if (piece.link == null) { + text_region.Union (piece.region); + continue; + } + + Color color = GetPieceColor (label, piece, i); + + if ( (label.LinkBehavior == LinkBehavior.AlwaysUnderline) || + (label.LinkBehavior == LinkBehavior.SystemDefault) || + ((label.LinkBehavior == LinkBehavior.HoverUnderline) && piece.link.Hovered) ) + font = link_font; + else + font = label.Font; + + dc.Clip = piece.region; + dc.Clip.Intersect (clip_rectangle); + dc.DrawString (label.Text, font, + ThemeEngine.Current.ResPool.GetSolidBrush (color), + client_rect, label.string_format); + + // Draw focus rectangle + if ((piece.link != null) && piece.link.Focused) { + foreach (RectangleF rect in piece.region.GetRegionScans (dc.Transform)) + WidgetPaint.DrawFocusRectangle (dc, Rectangle.Round (rect), label.ForeColor, label.BackColor); + } + } + + // Draw normal text (without links). + if (!text_region.IsEmpty (dc)) { + dc.Clip = text_region; + dc.Clip.Intersect (clip_rectangle); + if (!dc.Clip.IsEmpty (dc)) + dc.DrawString(label.Text, label.Font, + ThemeEngine.Current.ResPool.GetSolidBrush(label.ForeColor), + client_rect, label.string_format); + } + } + } +} \ No newline at end of file diff --git a/source/ShiftUI/Theming/Default/RadioButtonPainter.cs b/source/ShiftUI/Theming/Default/RadioButtonPainter.cs new file mode 100644 index 0000000..83885ed --- /dev/null +++ b/source/ShiftUI/Theming/Default/RadioButtonPainter.cs @@ -0,0 +1,239 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; + +namespace ShiftUI.Theming.Default +{ + /// + /// Summary description for Button. + /// + internal class RadioButtonPainter + { + public RadioButtonPainter () + { + } + + protected SystemResPool ResPool { get { return ThemeEngine.Current.ResPool; } } + + public void PaintRadioButton (Graphics g, Rectangle bounds, Color backColor, Color foreColor, ElementState state, FlatStyle style, bool isChecked) + { + switch (style) { + case FlatStyle.Standard: + case FlatStyle.System: + switch (state) { + case ElementState.Normal: + DrawNormalRadioButton (g, bounds, backColor, foreColor, isChecked); + break; + case ElementState.Hot: + DrawHotRadioButton (g, bounds, backColor, foreColor, isChecked); + break; + case ElementState.Pressed: + DrawPressedRadioButton (g, bounds, backColor, foreColor, isChecked); + break; + case ElementState.Disabled: + DrawDisabledRadioButton (g, bounds, backColor, foreColor, isChecked); + break; + } + break; + case FlatStyle.Flat: + switch (state) { + case ElementState.Normal: + DrawFlatNormalRadioButton (g, bounds, backColor, foreColor, isChecked); + break; + case ElementState.Hot: + DrawFlatHotRadioButton (g, bounds, backColor, foreColor, isChecked); + break; + case ElementState.Pressed: + DrawFlatPressedRadioButton (g, bounds, backColor, foreColor, isChecked); + break; + case ElementState.Disabled: + DrawFlatDisabledRadioButton (g, bounds, backColor, foreColor, isChecked); + break; + } + break; + case FlatStyle.Popup: + switch (state) { + case ElementState.Normal: + DrawPopupNormalRadioButton (g, bounds, backColor, foreColor, isChecked); + break; + case ElementState.Hot: + DrawPopupHotRadioButton (g, bounds, backColor, foreColor, isChecked); + break; + case ElementState.Pressed: + DrawPopupPressedRadioButton (g, bounds, backColor, foreColor, isChecked); + break; + case ElementState.Disabled: + DrawPopupDisabledRadioButton (g, bounds, backColor, foreColor, isChecked); + break; + } + break; + } + } + + #region Standard + public virtual void DrawNormalRadioButton (Graphics g, Rectangle bounds, Color backColor, Color foreColor, bool isChecked) + { + ButtonState bs = ButtonState.Normal; + + if (isChecked) + bs |= ButtonState.Checked; + + WidgetPaint.DrawRadioButton (g, bounds, bs); + } + + public virtual void DrawHotRadioButton (Graphics g, Rectangle bounds, Color backColor, Color foreColor, bool isChecked) + { + DrawNormalRadioButton (g, bounds, backColor, foreColor, isChecked); + } + + public virtual void DrawPressedRadioButton (Graphics g, Rectangle bounds, Color backColor, Color foreColor, bool isChecked) + { + ButtonState bs = ButtonState.Pushed; + + if (isChecked) + bs |= ButtonState.Checked; + + WidgetPaint.DrawRadioButton (g, bounds, bs); + } + + public virtual void DrawDisabledRadioButton (Graphics g, Rectangle bounds, Color backColor, Color foreColor, bool isChecked) + { + ButtonState bs = ButtonState.Inactive; + + if (isChecked) + bs |= ButtonState.Checked; + + WidgetPaint.DrawRadioButton (g, bounds, bs); + } + #endregion + + #region FlatStyle + public virtual void DrawFlatNormalRadioButton (Graphics g, Rectangle bounds, Color backColor, Color foreColor, bool isChecked) + { + g.DrawArc (SystemPens.ControlDarkDark, bounds, 0, 359); + g.FillPie (SystemBrushes.ControlLightLight, bounds.X + 1, bounds.Y + 1, bounds.Width - 2, bounds.Height - 2, 0, 359); + + if (isChecked) + DrawFlatRadioGlyphDot (g, bounds, SystemColors.ControlDarkDark); + } + + public virtual void DrawFlatHotRadioButton (Graphics g, Rectangle bounds, Color backColor, Color foreColor, bool isChecked) + { + g.DrawArc (SystemPens.ControlDarkDark, bounds, 0, 359); + g.FillPie (SystemBrushes.ControlLight, bounds.X + 1, bounds.Y + 1, bounds.Width - 2, bounds.Height - 2, 0, 359); + + if (isChecked) + DrawFlatRadioGlyphDot (g, bounds, SystemColors.ControlDarkDark); + } + + public virtual void DrawFlatPressedRadioButton (Graphics g, Rectangle bounds, Color backColor, Color foreColor, bool isChecked) + { + g.DrawArc (SystemPens.ControlDarkDark, bounds, 0, 359); + g.FillPie (SystemBrushes.ControlLightLight, bounds.X + 1, bounds.Y + 1, bounds.Width - 2, bounds.Height - 2, 0, 359); + + if (isChecked) + DrawFlatRadioGlyphDot (g, bounds, SystemColors.ControlDarkDark); + } + + public virtual void DrawFlatDisabledRadioButton (Graphics g, Rectangle bounds, Color backColor, Color foreColor, bool isChecked) + { + g.FillPie (SystemBrushes.Control, bounds.X + 1, bounds.Y + 1, bounds.Width - 2, bounds.Height - 2, 0, 359); + g.DrawArc (SystemPens.ControlDark, bounds, 0, 359); + + if (isChecked) + DrawFlatRadioGlyphDot (g, bounds, SystemColors.ControlDark); + } + #endregion + + #region Popup + public virtual void DrawPopupNormalRadioButton (Graphics g, Rectangle bounds, Color backColor, Color foreColor, bool isChecked) + { + g.FillPie (SystemBrushes.ControlLightLight, bounds, 0, 359); + g.DrawArc (SystemPens.ControlDark, bounds, 0, 359); + + if (isChecked) + DrawFlatRadioGlyphDot (g, bounds, SystemColors.ControlDarkDark); + } + + public virtual void DrawPopupHotRadioButton (Graphics g, Rectangle bounds, Color backColor, Color foreColor, bool isChecked) + { + g.FillPie (SystemBrushes.ControlLightLight, bounds, 0, 359); + g.DrawArc (SystemPens.ControlLight, bounds.X + 1, bounds.Y + 1, bounds.Width - 2, bounds.Height - 2, 0, 359); + + g.DrawArc (SystemPens.ControlDark, bounds, 135, 180); + g.DrawArc (SystemPens.ControlLightLight, bounds, 315, 180); + + if (isChecked) + DrawFlatRadioGlyphDot (g, bounds, SystemColors.ControlDarkDark); + } + + public virtual void DrawPopupPressedRadioButton (Graphics g, Rectangle bounds, Color backColor, Color foreColor, bool isChecked) + { + g.FillPie (SystemBrushes.ControlLightLight, bounds, 0, 359); + g.DrawArc (SystemPens.ControlLight, bounds.X + 1, bounds.Y + 1, bounds.Width - 2, bounds.Height - 2, 0, 359); + + g.DrawArc (SystemPens.ControlDark, bounds, 135, 180); + g.DrawArc (SystemPens.ControlLightLight, bounds, 315, 180); + + if (isChecked) + DrawFlatRadioGlyphDot (g, bounds, SystemColors.ControlDarkDark); + } + + public virtual void DrawPopupDisabledRadioButton (Graphics g, Rectangle bounds, Color backColor, Color foreColor, bool isChecked) + { + g.FillPie (SystemBrushes.Control, bounds.X + 1, bounds.Y + 1, bounds.Width - 2, bounds.Height - 2, 0, 359); + g.DrawArc (SystemPens.ControlDark, bounds, 0, 359); + + if (isChecked) + DrawFlatRadioGlyphDot (g, bounds, SystemColors.ControlDarkDark); + } + #endregion + + #region Glyph + protected void DrawFlatRadioGlyphDot (Graphics g, Rectangle bounds, Color dotColor) + { + int lineWidth = Math.Max (1, Math.Min (bounds.Width, bounds.Height) / 3); + + Pen dot_pen = ResPool.GetPen (dotColor); + Brush dot_brush = ResPool.GetSolidBrush (dotColor); + + if (bounds.Height > 13) { + g.FillPie (dot_brush, bounds.X + lineWidth, bounds.Y + lineWidth, bounds.Width - lineWidth * 2, bounds.Height - lineWidth * 2, 0, 359); + } else { + int x_half_pos = (bounds.Width / 2) + bounds.X; + int y_half_pos = (bounds.Height / 2) + bounds.Y; + + g.DrawLine (dot_pen, x_half_pos - 1, y_half_pos, x_half_pos + 2, y_half_pos); + g.DrawLine (dot_pen, x_half_pos - 1, y_half_pos + 1, x_half_pos + 2, y_half_pos + 1); + + g.DrawLine (dot_pen, x_half_pos, y_half_pos - 1, x_half_pos, y_half_pos + 2); + g.DrawLine (dot_pen, x_half_pos + 1, y_half_pos - 1, x_half_pos + 1, y_half_pos + 2); + } + } + #endregion + } +} diff --git a/source/ShiftUI/Theming/Default/TabControlPainter.cs b/source/ShiftUI/Theming/Default/TabControlPainter.cs new file mode 100644 index 0000000..2ecdacd --- /dev/null +++ b/source/ShiftUI/Theming/Default/TabControlPainter.cs @@ -0,0 +1,507 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Andreia Gaita (avidigal@novell.com) + +using System; +using System.Drawing; +using System.Drawing.Text; +using ShiftUI; +using ShiftUI.VisualStyles; + +namespace ShiftUI.Theming.Default +{ + /// + /// Summary description for TabWidget. + /// + internal class TabWidgetPainter { + protected SystemResPool ResPool { get { return ThemeEngine.Current.ResPool; } } + + #region private + + private Size defaultItemSize; + private Point defaultPadding; + private int minimumTabWidth; + private Rectangle selectedTabDelta; + + private Point tabPanelOffset; + + private int selectedSpacing; + + private Size rowSpacingNormal; + private Size rowSpacingButtons; + private Size rowSpacingFlatButtons; + private int scrollerWidth; + private Point focusRectSpacing; + private Rectangle tabPageSpacing; + private int colSpacing; + private int flatButtonSpacing; + + private Point imagePadding; + + private StringFormat defaultFormatting; + + private Rectangle borderThickness; + + #endregion + + #region Properties + + public virtual Size DefaultItemSize { + get { return defaultItemSize; } + set { defaultItemSize = value; } + } + + public virtual Point DefaultPadding { + get { return defaultPadding; } + set { defaultPadding = value; } + } + + public virtual int MinimumTabWidth { + get { return minimumTabWidth; } + set { minimumTabWidth = value; } + } + + public virtual Rectangle SelectedTabDelta { + get { return selectedTabDelta; } + set { selectedTabDelta = value; } + } + + public virtual Point TabPanelOffset { + get { return tabPanelOffset; } + set { tabPanelOffset = value; } + } + + public virtual int SelectedSpacing { + get { return selectedSpacing; } + set { selectedSpacing = value; } + } + + public virtual Size RowSpacingNormal { + get { return rowSpacingNormal; } + set { rowSpacingNormal = value; } + } + + public virtual Size RowSpacingButtons { + get { return rowSpacingButtons; } + set { rowSpacingButtons = value; } + } + + public virtual Size RowSpacingFlatButtons { + get { return rowSpacingFlatButtons; } + set { rowSpacingFlatButtons = value; } + } + + public virtual Point FocusRectSpacing { + get { return focusRectSpacing; } + set { focusRectSpacing = value; } + } + + public virtual int ColSpacing { + get { return colSpacing; } + set { colSpacing = value; } + } + + public virtual int FlatButtonSpacing { + get { return flatButtonSpacing; } + set { flatButtonSpacing = value; } + } + + public virtual Rectangle TabPageSpacing { + get { return tabPageSpacing; } + set { tabPageSpacing = value; } + } + + public virtual Point ImagePadding { + get { return imagePadding; } + set { imagePadding = value; } + } + + public virtual StringFormat DefaultFormatting { + get { return defaultFormatting; } + set { defaultFormatting = value; } + } + + public virtual Rectangle BorderThickness { + get { return borderThickness; } + set { borderThickness = value; } + } + + public virtual int ScrollerWidth { + get { return scrollerWidth; } + set { scrollerWidth = value; } + } + + public virtual Size RowSpacing (ShiftUI.TabWidget tab) { + switch (tab.Appearance) { + case TabAppearance.Normal: + return rowSpacingNormal; + case TabAppearance.Buttons: + return rowSpacingButtons; + case TabAppearance.FlatButtons: + return rowSpacingFlatButtons; + default: + throw new Exception ("Invalid Appearance value: " + tab.Appearance); + } + } + #endregion + + public TabWidgetPainter () + { + defaultItemSize = new Size (42, 16); + defaultPadding = new Point (6, 3); + selectedTabDelta = new Rectangle (2, 2, 4, 3); + selectedSpacing = 0; + + rowSpacingNormal = new Size (0, 0); + rowSpacingButtons = new Size (3, 3); + rowSpacingFlatButtons = new Size (9, 3); + + colSpacing = 0; + + minimumTabWidth = 42; + scrollerWidth = 17; + focusRectSpacing = new Point (2, 2); + tabPanelOffset = new Point (4, 0); + flatButtonSpacing = 8; + tabPageSpacing = new Rectangle (4, 2, 3, 4); + + imagePadding = new Point (2, 3); + + defaultFormatting = new StringFormat(); + // Horizontal Alignment is handled in the Draw method + defaultFormatting.Alignment = StringAlignment.Near; + defaultFormatting.LineAlignment = StringAlignment.Center; + defaultFormatting.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.NoClip; + defaultFormatting.HotkeyPrefix = HotkeyPrefix.Show; + + borderThickness = new Rectangle (1, 1, 2, 2); + } + + public virtual Rectangle GetLeftScrollRect (ShiftUI.TabWidget tab) + { + switch (tab.Alignment) { + case TabAlignment.Top: + return new Rectangle (tab.ClientRectangle.Right - (scrollerWidth * 2), tab.ClientRectangle.Top + 1, scrollerWidth, scrollerWidth); + default: + Rectangle panel_rect = GetTabPanelRect (tab); + return new Rectangle (tab.ClientRectangle.Right - (scrollerWidth * 2), panel_rect.Bottom + 2, scrollerWidth, scrollerWidth); + } + } + + public virtual Rectangle GetRightScrollRect (ShiftUI.TabWidget tab) + { + switch (tab.Alignment) { + case TabAlignment.Top: + return new Rectangle (tab.ClientRectangle.Right - (scrollerWidth), tab.ClientRectangle.Top + 1, scrollerWidth, scrollerWidth); + default: + Rectangle panel_rect = GetTabPanelRect (tab); + return new Rectangle (tab.ClientRectangle.Right - (scrollerWidth), panel_rect.Bottom + 2, scrollerWidth, scrollerWidth); + } + } + + public Rectangle GetDisplayRectangle (ShiftUI.TabWidget tab) + { + Rectangle ext = GetTabPanelRect (tab); + // Account for border size + return new Rectangle (ext.Left + tabPageSpacing.X, ext.Top + tabPageSpacing.Y, + ext.Width - tabPageSpacing.X - tabPageSpacing.Width, ext.Height - tabPageSpacing.Y - tabPageSpacing.Height); + } + + public Rectangle GetTabPanelRect (ShiftUI.TabWidget tab) + { + // Offset the tab page (panel) from the top corner + Rectangle res = tab.ClientRectangle; + + if (tab.TabCount == 0) + return res; + + int spacing = RowSpacing (tab).Height; + int tabOffset = (tab.ItemSize.Height + spacing - selectedTabDelta.Height) * tab.RowCount + selectedTabDelta.Y; + switch (tab.Alignment) { + case TabAlignment.Top: + res.Y += tabOffset; + res.Height -= tabOffset; + break; + case TabAlignment.Bottom: + res.Height -= tabOffset; + break; + case TabAlignment.Left: + res.X += tabOffset; + res.Width -= tabOffset; + break; + case TabAlignment.Right: + res.Width -= tabOffset; + break; + } + + return res; + } + + public virtual void Draw (Graphics dc, Rectangle area, TabWidget tab) + { + DrawBackground (dc, area, tab); + + int start = 0; + int end = tab.TabPages.Count; + int delta = 1; + + if (tab.Alignment == TabAlignment.Top) { + start = end; + end = 0; + delta = -1; + } + + if (tab.SizeMode == TabSizeMode.Fixed) + defaultFormatting.Alignment = StringAlignment.Center; + else + defaultFormatting.Alignment = StringAlignment.Near; + + int counter = start; + for (; counter != end; counter += delta) { + for (int i = tab.SliderPos; i < tab.TabPages.Count; i++) { + if (i == tab.SelectedIndex) + continue; + if (counter != tab.TabPages[i].Row) + continue; + Rectangle rect = tab.GetTabRect (i); + if (!rect.IntersectsWith (area)) + continue; + DrawTab (dc, tab.TabPages[i], tab, rect, false); + } + } + + if (tab.SelectedIndex != -1 && tab.SelectedIndex >= tab.SliderPos) { + Rectangle rect = tab.GetTabRect (tab.SelectedIndex); + if (rect.IntersectsWith (area)) + DrawTab (dc, tab.TabPages[tab.SelectedIndex], tab, rect, true); + } + + if (tab.ShowSlider) { + Rectangle right = GetRightScrollRect (tab); + Rectangle left = GetLeftScrollRect (tab); + DrawScrollButton (dc, right, area, ScrollButton.Right, tab.RightSliderState); + DrawScrollButton (dc, left, area, ScrollButton.Left, tab.LeftSliderState); + } + } + + protected virtual void DrawScrollButton (Graphics dc, Rectangle bounds, Rectangle clippingArea, ScrollButton button, PushButtonState state) + { + WidgetPaint.DrawScrollButton (dc, bounds, button, GetButtonState (state)); + } + + static ButtonState GetButtonState (PushButtonState state) + { + switch (state) { + case PushButtonState.Pressed: + return ButtonState.Pushed; + default: + return ButtonState.Normal; + } + } + + protected virtual void DrawBackground (Graphics dc, Rectangle area, TabWidget tab) + { + Brush brush = SystemBrushes.Control; + dc.FillRectangle (brush, area); + Rectangle panel_rect = GetTabPanelRect (tab); + + if (tab.Appearance == TabAppearance.Normal) { + WidgetPaint.DrawBorder3D (dc, panel_rect, Border3DStyle.RaisedInner, Border3DSide.Left | Border3DSide.Top); + WidgetPaint.DrawBorder3D (dc, panel_rect, Border3DStyle.Raised, Border3DSide.Right | Border3DSide.Bottom); + } + } + + protected virtual int DrawTab (Graphics dc, ShiftUI.TabPage page, ShiftUI.TabWidget tab, Rectangle bounds, bool is_selected) + { + Rectangle interior; + int res = bounds.Width; + + dc.FillRectangle (ResPool.GetSolidBrush (tab.BackColor), bounds); + + if (tab.Appearance == TabAppearance.Buttons || tab.Appearance == TabAppearance.FlatButtons) { + // Separators + if (tab.Appearance == TabAppearance.FlatButtons) { + int width = bounds.Width; + bounds.Width += (flatButtonSpacing - 2); + res = bounds.Width; + if (tab.Alignment == TabAlignment.Top || tab.Alignment == TabAlignment.Bottom) + ThemeEngine.Current.CPDrawBorder3D (dc, bounds, Border3DStyle.Etched, Border3DSide.Right); + else + ThemeEngine.Current.CPDrawBorder3D (dc, bounds, Border3DStyle.Etched, Border3DSide.Top); + bounds.Width = width; + } + + if (is_selected) { + ThemeEngine.Current.CPDrawBorder3D (dc, bounds, Border3DStyle.Sunken, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom); + } else if (tab.Appearance != TabAppearance.FlatButtons) { + ThemeEngine.Current.CPDrawBorder3D (dc, bounds, Border3DStyle.Raised, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom); + } + + + } else { + CPColor cpcolor = ResPool.GetCPColor (tab.BackColor); + + Pen light = ResPool.GetPen (cpcolor.LightLight); + + switch (tab.Alignment) { + + case TabAlignment.Top: + + dc.DrawLine (light, bounds.Left, bounds.Bottom - 1, bounds.Left, bounds.Top + 3); + dc.DrawLine (light, bounds.Left, bounds.Top + 3, bounds.Left + 2, bounds.Top); + dc.DrawLine (light, bounds.Left + 2, bounds.Top, bounds.Right - 3, bounds.Top); + + dc.DrawLine (SystemPens.ControlDark, bounds.Right - 2, bounds.Top + 1, bounds.Right - 2, bounds.Bottom - 1); + dc.DrawLine (SystemPens.ControlDarkDark, bounds.Right - 2, bounds.Top + 1, bounds.Right - 1, bounds.Top + 2); + dc.DrawLine (SystemPens.ControlDarkDark, bounds.Right - 1, bounds.Top + 2, bounds.Right - 1, bounds.Bottom - 1); + break; + + case TabAlignment.Bottom: + + dc.DrawLine (light, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom - 2); + dc.DrawLine (light, bounds.Left, bounds.Bottom - 2, bounds.Left + 3, bounds.Bottom); + + dc.DrawLine (SystemPens.ControlDarkDark, bounds.Left + 3, bounds.Bottom, bounds.Right - 3, bounds.Bottom); + dc.DrawLine (SystemPens.ControlDark, bounds.Left + 3, bounds.Bottom - 1, bounds.Right - 3, bounds.Bottom - 1); + + dc.DrawLine (SystemPens.ControlDark, bounds.Right - 2, bounds.Bottom - 1, bounds.Right - 2, bounds.Top + 1); + dc.DrawLine (SystemPens.ControlDarkDark, bounds.Right - 2, bounds.Bottom - 1, bounds.Right - 1, bounds.Bottom - 2); + dc.DrawLine (SystemPens.ControlDarkDark, bounds.Right - 1, bounds.Bottom - 2, bounds.Right - 1, bounds.Top + 1); + + break; + + case TabAlignment.Left: + + dc.DrawLine (light, bounds.Left - 2, bounds.Top, bounds.Right, bounds.Top); + dc.DrawLine (light, bounds.Left, bounds.Top + 2, bounds.Left - 2, bounds.Top); + dc.DrawLine (light, bounds.Left, bounds.Top + 2, bounds.Left, bounds.Bottom - 2); + + dc.DrawLine (SystemPens.ControlDark, bounds.Left, bounds.Bottom - 2, bounds.Left + 2, bounds.Bottom - 1); + + dc.DrawLine (SystemPens.ControlDark, bounds.Left + 2, bounds.Bottom - 1, bounds.Right, bounds.Bottom - 1); + dc.DrawLine (SystemPens.ControlDarkDark, bounds.Left + 2, bounds.Bottom, bounds.Right, bounds.Bottom); + + break; + + default: // TabAlignment.Right + + dc.DrawLine (light, bounds.Left, bounds.Top, bounds.Right - 3, bounds.Top); + dc.DrawLine (light, bounds.Right - 3, bounds.Top, bounds.Right, bounds.Top + 3); + + dc.DrawLine (SystemPens.ControlDark, bounds.Right - 1, bounds.Top + 1, bounds.Right - 1, bounds.Bottom - 1); + dc.DrawLine (SystemPens.ControlDark, bounds.Left, bounds.Bottom - 1, bounds.Right - 2, bounds.Bottom - 1); + + dc.DrawLine (SystemPens.ControlDarkDark, bounds.Right, bounds.Top + 3, bounds.Right, bounds.Bottom - 3); + dc.DrawLine (SystemPens.ControlDarkDark, bounds.Left, bounds.Bottom, bounds.Right - 3, bounds.Bottom); + + break; + } + } + + Point padding = tab.Padding; + interior = new Rectangle (bounds.Left + padding.X - 1, // substract a little offset + bounds.Top + padding.Y, + bounds.Width - (padding.X * 2), + bounds.Height - (padding.Y * 2)); + + if (tab.DrawMode == TabDrawMode.Normal && page.Text != null) { + if (tab.Alignment == TabAlignment.Left) { + dc.TranslateTransform (bounds.Left, bounds.Bottom); + dc.RotateTransform (-90); + dc.DrawString (page.Text, tab.Font, + SystemBrushes.ControlText, + tab.Padding.X - 2, // drawstring adds some extra unwanted leading spaces, so trimming + tab.Padding.Y, + defaultFormatting); + dc.ResetTransform (); + } else if (tab.Alignment == TabAlignment.Right) { + dc.TranslateTransform (bounds.Right, bounds.Top); + dc.RotateTransform (90); + dc.DrawString (page.Text, tab.Font, + SystemBrushes.ControlText, + tab.Padding.X - 2, // drawstring adds some extra unwanted leading spaces, so trimming + tab.Padding.Y, + defaultFormatting); + dc.ResetTransform (); + } else { + Rectangle str_rect = interior; + + if (is_selected) { + // Reduce the interior size to match the inner size of non-selected tabs + str_rect.X += selectedTabDelta.X; + str_rect.Y += selectedTabDelta.Y; + str_rect.Width -= selectedTabDelta.Width; + str_rect.Height -= selectedTabDelta.Height; + + str_rect.Y -= selectedTabDelta.Y; // Move up the text / image of the selected tab + } + + if (tab.ImageList != null && page.ImageIndex >= 0 && page.ImageIndex < tab.ImageList.Images.Count) { + int image_x; + if (tab.SizeMode != TabSizeMode.Fixed) { + image_x = str_rect.X; + } + else { + image_x = str_rect.X + (str_rect.Width - tab.ImageList.ImageSize.Width) / 2; + if (page.Text != null) { + SizeF textSize = dc.MeasureString(page.Text, page.Font, str_rect.Size); + image_x -= (int)(textSize.Width / 2); + } + } + int image_y = str_rect.Y + (str_rect.Height - tab.ImageList.ImageSize.Height) / 2; + tab.ImageList.Draw (dc, new Point (image_x, image_y), page.ImageIndex); + str_rect.X += tab.ImageList.ImageSize.Width + 2; + str_rect.Width -= tab.ImageList.ImageSize.Width + 2; + } + dc.DrawString (page.Text, tab.Font, + SystemBrushes.ControlText, + str_rect, + defaultFormatting); + + } + } else if (page.Text != null) { + DrawItemState state = DrawItemState.None; + if (page == tab.SelectedTab) + state |= DrawItemState.Selected; + DrawItemEventArgs e = new DrawItemEventArgs (dc, + tab.Font, bounds, tab.IndexForTabPage (page), + state, page.ForeColor, page.BackColor); + tab.OnDrawItemInternal (e); + return res; + } + + // TabWidget ignores the value of ShowFocusCues + if (page.Parent.Focused && is_selected) { + Rectangle focus_rect = bounds; + focus_rect.Inflate (-2, -2); + ThemeEngine.Current.CPDrawFocusRectangle (dc, focus_rect, tab.BackColor, tab.ForeColor); + } + + return res; + } + + public virtual bool HasHotElementStyles (TabWidget tabWidget) { + return false; + } + } +} diff --git a/source/ShiftUI/Theming/Default/ToolStripPainter.cs b/source/ShiftUI/Theming/Default/ToolStripPainter.cs new file mode 100644 index 0000000..4876dd5 --- /dev/null +++ b/source/ShiftUI/Theming/Default/ToolStripPainter.cs @@ -0,0 +1,189 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) + +using System; +using System.Drawing; + +namespace ShiftUI.Theming.Default +{ + internal class ToolStripPainter + { + public ToolStripPainter () + { + } + + protected SystemResPool ResPool { get { return ThemeEngine.Current.ResPool; } } + + #region Painting + public virtual void OnRenderButtonBackground (ToolStripItemRenderEventArgs e) + { + if (e.Item.Enabled == false) + return; + + Rectangle paint_here = new Rectangle (0, 0, e.Item.Width, e.Item.Height); + + ToolStripButton tsb = e.Item as ToolStripButton; + + if (e.Item.Pressed || (tsb != null && tsb.Checked)) + WidgetPaint.DrawBorder3D (e.Graphics, paint_here, Border3DStyle.SunkenOuter); + else if (e.Item.Selected) + WidgetPaint.DrawBorder3D (e.Graphics, paint_here, Border3DStyle.RaisedInner); + else if (e.Item.BackColor != Widget.DefaultBackColor && e.Item.BackColor != Color.Empty) + e.Graphics.FillRectangle (ResPool.GetSolidBrush (e.Item.BackColor), paint_here); + } + + public virtual void OnRenderDropDownButtonBackground (ToolStripItemRenderEventArgs e) + { + if (e.Item.Enabled == false) + return; + + Rectangle paint_here = new Rectangle (0, 0, e.Item.Width, e.Item.Height); + + if (e.Item.Pressed) + WidgetPaint.DrawBorder3D (e.Graphics, paint_here, Border3DStyle.SunkenOuter); + else if (e.Item.Selected) + WidgetPaint.DrawBorder3D (e.Graphics, paint_here, Border3DStyle.RaisedInner); + else if (e.Item.BackColor != Widget.DefaultBackColor && e.Item.BackColor != Color.Empty) + e.Graphics.FillRectangle (ResPool.GetSolidBrush (e.Item.BackColor), paint_here); + } + + public virtual void OnRenderGrip (ToolStripGripRenderEventArgs e) + { + if (e.GripStyle == ToolStripGripStyle.Hidden) + return; + + if (e.GripDisplayStyle == ToolStripGripDisplayStyle.Vertical) { + e.Graphics.DrawLine (Pens.White, 0, 2, 1, 2); + e.Graphics.DrawLine (Pens.White, 0, 2, 0, e.GripBounds.Height - 3); + e.Graphics.DrawLine (SystemPens.ControlDark, 2, 2, 2, e.GripBounds.Height - 3); + e.Graphics.DrawLine (SystemPens.ControlDark, 2, e.GripBounds.Height - 3, 0, e.GripBounds.Height - 3); + } + else { + e.Graphics.DrawLine (Pens.White, 2, 0, e.GripBounds.Width - 3, 0); + e.Graphics.DrawLine (Pens.White, 2, 0, 2, 1); + e.Graphics.DrawLine (SystemPens.ControlDark, e.GripBounds.Width - 3, 0, e.GripBounds.Width - 3, 2); + e.Graphics.DrawLine (SystemPens.ControlDark, 2, 2, e.GripBounds.Width - 3, 2); + } + } + + public virtual void OnRenderMenuItemBackground (ToolStripItemRenderEventArgs e) + { + ToolStripMenuItem tsmi = (ToolStripMenuItem)e.Item; + Rectangle paint_here = new Rectangle (Point.Empty, tsmi.Size); + + if (tsmi.IsOnDropDown) { + // Drop down menu item + if (e.Item.Selected || e.Item.Pressed) + e.Graphics.FillRectangle (SystemBrushes.Highlight, paint_here); + } else { + // Top level menu item + if (e.Item.Pressed) + WidgetPaint.DrawBorder3D (e.Graphics, paint_here, Border3DStyle.SunkenOuter); + else if (e.Item.Selected) + WidgetPaint.DrawBorder3D (e.Graphics, paint_here, Border3DStyle.RaisedInner); + else if (e.Item.BackColor != Widget.DefaultBackColor && e.Item.BackColor != Color.Empty) + e.Graphics.FillRectangle (ResPool.GetSolidBrush (e.Item.BackColor), paint_here); + } + } + + public virtual void OnRenderOverflowButtonBackground (ToolStripItemRenderEventArgs e) + { + Rectangle paint_here = new Rectangle (Point.Empty, e.Item.Size); + + if (e.Item.Pressed) + WidgetPaint.DrawBorder3D (e.Graphics, paint_here, Border3DStyle.SunkenOuter); + else if (e.Item.Selected) + WidgetPaint.DrawBorder3D (e.Graphics, paint_here, Border3DStyle.RaisedInner); + else if (e.Item.BackColor != Widget.DefaultBackColor && e.Item.BackColor != Color.Empty) + e.Graphics.FillRectangle (ResPool.GetSolidBrush (e.Item.BackColor), paint_here); + + // Paint the arrow + ToolStripRenderer.DrawDownArrow (e.Graphics, SystemPens.ControlText, e.Item.Width / 2 - 3, e.Item.Height / 2 - 1); + } + + public virtual void OnRenderSeparator (ToolStripSeparatorRenderEventArgs e) + { + if (e.Vertical) { + e.Graphics.DrawLine (Pens.White, 4, 3, 4, e.Item.Height - 1); + e.Graphics.DrawLine (SystemPens.ControlDark, 3, 3, 3, e.Item.Height - 1); + } else { + if (!e.Item.IsOnDropDown) { + e.Graphics.DrawLine (Pens.White, 2, 4, e.Item.Right - 1, 4); + e.Graphics.DrawLine (SystemPens.ControlDark, 2, 3, e.Item.Right - 1, 3); + } else { + e.Graphics.DrawLine (Pens.White, 3, 4, e.Item.Right - 4, 4); + e.Graphics.DrawLine (SystemPens.ControlDark, 3, 3, e.Item.Right - 4, 3); + } + } + } + + public virtual void OnRenderSplitButtonBackground (ToolStripItemRenderEventArgs e) + { + ToolStripSplitButton tssb = (ToolStripSplitButton)e.Item; + + Rectangle button_part = new Rectangle (Point.Empty, tssb.ButtonBounds.Size); + Point drop_start = new Point (tssb.Width - tssb.DropDownButtonBounds.Width, 0); + Rectangle drop_part = new Rectangle (drop_start, tssb.DropDownButtonBounds.Size); + + // Regular button part + if (tssb.ButtonPressed) + WidgetPaint.DrawBorder3D (e.Graphics, button_part, Border3DStyle.SunkenOuter); + else if (tssb.ButtonSelected) + WidgetPaint.DrawBorder3D (e.Graphics, button_part, Border3DStyle.RaisedInner); + else if (e.Item.BackColor != Widget.DefaultBackColor && e.Item.BackColor != Color.Empty) + e.Graphics.FillRectangle (ResPool.GetSolidBrush (e.Item.BackColor), button_part); + + // Drop down button part + if (tssb.DropDownButtonPressed || tssb.ButtonPressed) + WidgetPaint.DrawBorder3D (e.Graphics, drop_part, Border3DStyle.SunkenOuter); + else if (tssb.DropDownButtonSelected || tssb.ButtonSelected) + WidgetPaint.DrawBorder3D (e.Graphics, drop_part, Border3DStyle.RaisedInner); + else if (e.Item.BackColor != Widget.DefaultBackColor && e.Item.BackColor != Color.Empty) + e.Graphics.FillRectangle (ResPool.GetSolidBrush (e.Item.BackColor), drop_part); + } + + public virtual void OnRenderToolStripBackground (ToolStripRenderEventArgs e) + { + if (e.ToolStrip.BackgroundImage == null) + e.Graphics.Clear (e.BackColor); + + if (e.ToolStrip is StatusStrip) + e.Graphics.DrawLine (Pens.White, e.AffectedBounds.Left, e.AffectedBounds.Top, e.AffectedBounds.Right, e.AffectedBounds.Top); + } + + public virtual void OnRenderToolStripBorder (ToolStripRenderEventArgs e) + { + if (e.ToolStrip is StatusStrip) + return; + + if (e.ToolStrip is ToolStripDropDown) + WidgetPaint.DrawBorder3D (e.Graphics, e.AffectedBounds, Border3DStyle.Raised); + else { + e.Graphics.DrawLine (SystemPens.ControlDark, new Point (e.ToolStrip.Left, e.ToolStrip.Height - 2), new Point (e.ToolStrip.Right, e.ToolStrip.Height - 2)); + e.Graphics.DrawLine (Pens.White, new Point (e.ToolStrip.Left, e.ToolStrip.Height - 1), new Point (e.ToolStrip.Right, e.ToolStrip.Height - 1)); + } + } + #endregion + } +} diff --git a/source/ShiftUI/Theming/Nice/.gitattributes b/source/ShiftUI/Theming/Nice/.gitattributes new file mode 100644 index 0000000..2ea73f7 --- /dev/null +++ b/source/ShiftUI/Theming/Nice/.gitattributes @@ -0,0 +1 @@ +/TabWidgetPainter.cs -crlf diff --git a/source/ShiftUI/Theming/Nice/TabControlPainter.cs b/source/ShiftUI/Theming/Nice/TabControlPainter.cs new file mode 100644 index 0000000..17b71db --- /dev/null +++ b/source/ShiftUI/Theming/Nice/TabControlPainter.cs @@ -0,0 +1,38 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Andreia Gaita (avidigal@novell.com) + +using System; +using System.Drawing; +using ShiftUI; + +namespace ShiftUI.Theming.Nice +{ + /// + /// Summary description for TabWidget. + /// + internal class TabWidgetPainter: Default.TabWidgetPainter + { + + } +} diff --git a/source/ShiftUI/Theming/ShiftOS.cs b/source/ShiftUI/Theming/ShiftOS.cs new file mode 100644 index 0000000..1cc00e1 --- /dev/null +++ b/source/ShiftUI/Theming/ShiftOS.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ShiftUI.ShiftOS +{ + public abstract class Skin + { + #region Button + public int ButtonBorderWidth = 2; + public Color ButtonBorderColor = Color.Black; + public Color ButtonBackColor = Color.White; + public Color ButtonBackColor_Pressed = Color.Gray; + #endregion + + #region Global + public string DefaultFont = "Microsoft Sans Serif"; + public int DefaultFontSize = 9; + public FontStyle DefaultFontStyle = FontStyle.Regular; + public Color WindowBackColor = Color.Gray; + public Color DefaultForeColor = Color.Black; + #endregion + + #region ScrollBar + public int ScrollbarWidth = 24; + #endregion + + #region 3D borders + public Color Border3DTopLeftInner = Color.LightGray; + public Color Border3DBottomRight = Color.DarkGray; + public Color Border3DBottomRightInner = Color.Gray; + #endregion + + #region MessageBox + public Color MessageBox_BottomPanel = Color.Gray; + #endregion + + #region ProgressBar + + public Color ProgressBar_BackgroundColor = Color.Gray; + public Color ProgressBar_BlockColor = Color.Black; + + #endregion + + // No reason to have ShiftOS deal with window borders itself + // when I can do it inside ShiftUI. + #region Form + public int titlebarlayout = 3; + public int borderleftlayout = 3; + public int borderrightlayout = 3; + public int borderbottomlayout = 3; + public int closebtnlayout = 3; + public int rollbtnlayout = 3; + public int minbtnlayout = 3; + public int rightcornerlayout = 3; + public int leftcornerlayout = 3; + // Late entry: need to fix window code to include this + public int bottomleftcornerlayout = 3; + public int bottomrightcornerlayout = 3; + public Color bottomleftcornercolour = Color.Gray; + + public Color bottomrightcornercolour = Color.Gray; + + public bool enablebordercorners = false; + // settings + public Size closebtnsize = new Size(22, 22); + public Size rollbtnsize = new Size(22, 22); + public Size minbtnsize = new Size(22, 22); + public int titlebarheight = 30; + public int titlebariconsize = 16; + public int closebtnfromtop = 5; + public int closebtnfromside = 2; + public int rollbtnfromtop = 5; + public int rollbtnfromside = 26; + public int minbtnfromtop = 5; + public int minbtnfromside = 52; + public int borderwidth = 2; + public bool enablecorners = false; + public int titlebarcornerwidth = 5; + public int titleiconfromside = 4; + public int titleiconfromtop = 4; + //colours + public Color titlebarcolour = Color.Gray; + public Color borderleftcolour = Color.Gray; + public Color borderrightcolour = Color.Gray; + public Color borderbottomcolour = Color.Gray; + public Color closebtncolour = Color.Black; + public Color closebtnhovercolour = Color.Black; + public Color closebtnclickcolour = Color.Black; + public Color rollbtncolour = Color.Black; + public Color rollbtnhovercolour = Color.Black; + public Color rollbtnclickcolour = Color.Black; + public Color minbtncolour = Color.Black; + public Color minbtnhovercolour = Color.Black; + public Color minbtnclickcolour = Color.Black; + public Color rightcornercolour = Color.Gray; + public Color leftcornercolour = Color.Gray; + // Text + public string titletextfontfamily = "Microsoft Sans Serif"; + public int titletextfontsize = 10; + public FontStyle titletextfontstyle = FontStyle.Bold; + public string titletextpos = "Left"; + public int titletextfromtop = 3; + public int titletextfromside = 24; + + public Color titletextcolour = Color.White; + + #endregion + } + + public class DefaultSkin : Skin + { + + } +} diff --git a/source/ShiftUI/Theming/ThemeElements.cs b/source/ShiftUI/Theming/ThemeElements.cs new file mode 100644 index 0000000..e1bd740 --- /dev/null +++ b/source/ShiftUI/Theming/ThemeElements.cs @@ -0,0 +1,223 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// Everaldo Canuto + +using System; +using System.Drawing; +using System.Reflection; + +namespace ShiftUI.Theming +{ + internal class MemphisThemeElements + { + private static ThemeElementsDefault theme; + public static ThemeElementsDefault CurrentTheme + { + get { return theme; } + } + + static MemphisThemeElements() + { + Init(); + } + + public static void Init() + { + theme = LoadTheme("memphis"); + } + + private static ThemeElementsDefault LoadTheme(string themeName) + { + return new ThemeElementsMemphis(); + } + + #region Buttons + public static void DrawButton(Graphics g, Rectangle bounds, ButtonThemeState state, Color backColor, Color foreColor) + { + theme.ButtonPainter.Draw(g, bounds, state, backColor, foreColor); + } + + public static void DrawFlatButton(Graphics g, Rectangle bounds, ButtonThemeState state, Color backColor, Color foreColor, FlatButtonAppearance appearance) + { + theme.ButtonPainter.DrawFlat(g, bounds, state, backColor, foreColor, appearance); + } + + public static void DrawPopupButton(Graphics g, Rectangle bounds, ButtonThemeState state, Color backColor, Color foreColor) + { + theme.ButtonPainter.DrawPopup(g, bounds, state, backColor, foreColor); + } + #endregion + + #region Painters + + public virtual Default.ButtonPainter ButtonPainter + { + get { return theme.ButtonPainter; } + } + + public static Default.LabelPainter LabelPainter + { + get { return theme.LabelPainter; } + } + + public static Default.LinkLabelPainter LinkLabelPainter + { + get { return theme.LinkLabelPainter; } + } + + public virtual Default.TabWidgetPainter TabWidgetPainter + { + get { return theme.TabWidgetPainter; } + } + + public virtual Default.CheckBoxPainter CheckBoxPainter + { + get { return theme.CheckBoxPainter; } + } + + public virtual Default.RadioButtonPainter RadioButtonPainter + { + get { return theme.RadioButtonPainter; } + } + + public virtual Default.ToolStripPainter ToolStripPainter + { + get { return theme.ToolStripPainter; } + } + + #endregion + } + + + internal class ThemeElements + { + private static ThemeElementsDefault theme; + public static ThemeElementsDefault CurrentTheme { + get { return theme; } + } + + static ThemeElements () + { + string theme_var; + + theme_var = Environment.GetEnvironmentVariable ("MONO_THEME"); + + if (theme_var == null) + theme_var = "win32"; + else + theme_var = theme_var.ToLower (); + + theme = LoadTheme (theme_var); + + } + + private static ThemeElementsDefault LoadTheme (string themeName) + { + if (themeName == "visualstyles") + if (Application.VisualStylesEnabled) + return new ThemeElementsVisualStyles (); + else + return new ThemeElementsDefault (); + Assembly ass = Assembly.GetExecutingAssembly (); + string iname = typeof(ThemeElements).FullName; + string assemblyname = iname + themeName; + Type type = ass.GetType (assemblyname, false, true); + if (type != null) { + object o = ass.CreateInstance (type.FullName); + if (o != null) + return (ThemeElementsDefault) o; + } + return new ThemeElementsDefault (); + } + + #region Buttons + public static void DrawButton (Graphics g, Rectangle bounds, ButtonThemeState state, Color backColor, Color foreColor) + { + theme.ButtonPainter.Draw (g, bounds, state, backColor, foreColor); + } + + public static void DrawFlatButton (Graphics g, Rectangle bounds, ButtonThemeState state, Color backColor, Color foreColor, FlatButtonAppearance appearance) + { + theme.ButtonPainter.DrawFlat (g, bounds, state, backColor, foreColor, appearance); + } + + public static void DrawPopupButton (Graphics g, Rectangle bounds, ButtonThemeState state, Color backColor, Color foreColor) + { + theme.ButtonPainter.DrawPopup (g, bounds, state, backColor, foreColor); + } + #endregion + + #region Painters + + public virtual Default.ButtonPainter ButtonPainter { + get { return theme.ButtonPainter; } + } + + public static Default.LabelPainter LabelPainter { + get { return theme.LabelPainter; } + } + + public static Default.LinkLabelPainter LinkLabelPainter { + get { return theme.LinkLabelPainter; } + } + + public virtual Default.TabWidgetPainter TabWidgetPainter { + get { return theme.TabWidgetPainter; } + } + + public virtual Default.CheckBoxPainter CheckBoxPainter { + get { return theme.CheckBoxPainter; } + } + + public virtual Default.RadioButtonPainter RadioButtonPainter { + get { return theme.RadioButtonPainter; } + } + + public virtual Default.ToolStripPainter ToolStripPainter { + get { return theme.ToolStripPainter; } + } + + #endregion + } + + #region Internal Enums + [Flags] + internal enum ButtonThemeState + { + Normal = 1, + Entered = 2, + Pressed = 4, + Disabled = 8, + Default = 16 + } + + internal enum ElementState + { + Normal = 1, + Hot = 2, + Pressed = 3, + Disabled = 4 + } + #endregion +} \ No newline at end of file diff --git a/source/ShiftUI/Theming/ThemeElementsClearlooks.cs b/source/ShiftUI/Theming/ThemeElementsClearlooks.cs new file mode 100644 index 0000000..8a1375e --- /dev/null +++ b/source/ShiftUI/Theming/ThemeElementsClearlooks.cs @@ -0,0 +1,35 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Andreia Gaita (avidigal@novell.com) + +using System; + +namespace ShiftUI.Theming +{ + /// + /// Summary description for ThemeElementsClearlooks. + /// + internal class ThemeElementsClearlooks: ThemeElementsDefault + { + } +} diff --git a/source/ShiftUI/Theming/ThemeElementsDefault.cs b/source/ShiftUI/Theming/ThemeElementsDefault.cs new file mode 100644 index 0000000..02126d6 --- /dev/null +++ b/source/ShiftUI/Theming/ThemeElementsDefault.cs @@ -0,0 +1,95 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// Andreia Gaita (avidigal@novell.com) + +using System; + +namespace ShiftUI.Theming +{ + internal class ThemeElementsDefault + { + protected Default.TabWidgetPainter tabWidgetPainter; + public virtual Default.TabWidgetPainter TabWidgetPainter { + get { + if (tabWidgetPainter == null) + tabWidgetPainter = new Default.TabWidgetPainter (); + return tabWidgetPainter; + } + } + + protected Default.ButtonPainter buttonPainter; + public virtual Default.ButtonPainter ButtonPainter { + get { + if (buttonPainter == null) + buttonPainter = new Default.ButtonPainter (); + return buttonPainter; + } + } + + protected Default.LabelPainter labelPainter; + public virtual Default.LabelPainter LabelPainter { + get { + if (labelPainter == null) + labelPainter = new Default.LabelPainter (); + return labelPainter; + } + } + + protected Default.LinkLabelPainter linklabelPainter; + public virtual Default.LinkLabelPainter LinkLabelPainter { + get { + if (linklabelPainter == null) + linklabelPainter = new Default.LinkLabelPainter (); + return linklabelPainter; + } + } + + protected Default.ToolStripPainter toolStripPainter; + public virtual Default.ToolStripPainter ToolStripPainter { + get { + if (toolStripPainter == null) + toolStripPainter = new Default.ToolStripPainter (); + return toolStripPainter; + } + } + + protected Default.CheckBoxPainter checkBoxPainter; + public virtual Default.CheckBoxPainter CheckBoxPainter { + get { + if (checkBoxPainter == null) + checkBoxPainter = new Default.CheckBoxPainter (); + return checkBoxPainter; + } + } + + protected Default.RadioButtonPainter radioButtonPainter; + public virtual Default.RadioButtonPainter RadioButtonPainter { + get { + if (radioButtonPainter == null) + radioButtonPainter = new Default.RadioButtonPainter (); + return radioButtonPainter; + } + } + } +} diff --git a/source/ShiftUI/Theming/ThemeElementsGtk.cs b/source/ShiftUI/Theming/ThemeElementsGtk.cs new file mode 100644 index 0000000..97582d3 --- /dev/null +++ b/source/ShiftUI/Theming/ThemeElementsGtk.cs @@ -0,0 +1,35 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Andreia Gaita (avidigal@novell.com) + +using System; + +namespace ShiftUI.Theming +{ + /// + /// Summary description for ThemeElementsGtk. + /// + internal class ThemeElementsGtk: ThemeElementsDefault + { + } +} diff --git a/source/ShiftUI/Theming/ThemeElementsMemphis.cs b/source/ShiftUI/Theming/ThemeElementsMemphis.cs new file mode 100644 index 0000000..1a2e892 --- /dev/null +++ b/source/ShiftUI/Theming/ThemeElementsMemphis.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ShiftUI.Theming.Default; +using System.Drawing; +using ShiftUI.ShiftOS; + +namespace ShiftUI.Theming +{ + class ThemeElementsMemphis : ThemeElementsDefault + { + + public ThemeElementsMemphis() + { + } + + public override ButtonPainter ButtonPainter + { + get + { + return new Memphis.ButtonPainter(); + } + } + } + + namespace Memphis + { + internal class ButtonPainter : Default.ButtonPainter + { + + #region Buttons + #region Standard Button + public override void Draw(Graphics g, Rectangle bounds, ButtonThemeState state, Color backColor, Color foreColor) + { + bool is_themecolor = backColor.ToArgb() == ThemeEngine.Current.ColorControl.ToArgb() || backColor == Color.Empty ? true : false; + CPColor cpcolor = is_themecolor ? CPColor.Empty : ResPool.GetCPColor(backColor); + Pen pen; + + switch (state) + { + case ButtonThemeState.Disabled: + case ButtonThemeState.Normal: + case ButtonThemeState.Entered: + case ButtonThemeState.Default: + pen = new Pen(foreColor, Application.CurrentSkin.ButtonBorderWidth); + g.DrawRectangle(pen, bounds); + break; + case ButtonThemeState.Pressed: + g.FillRectangle(new SolidBrush(backColor), bounds); + pen = new Pen(foreColor, Application.CurrentSkin.ButtonBorderWidth); + g.DrawRectangle(pen, bounds); + break; + } + } + #endregion + + #region FlatStyle Button + public override void DrawFlat(Graphics g, Rectangle bounds, ButtonThemeState state, Color backColor, Color foreColor, FlatButtonAppearance appearance) + { + Draw(g, bounds, state, backColor, foreColor); + } + #endregion + + #region Popup Button + public override void DrawPopup(Graphics g, Rectangle bounds, ButtonThemeState state, Color backColor, Color foreColor) + { + Draw(g, bounds, state, backColor, foreColor); + } + #endregion + #endregion + + private static Color ChangeIntensity(Color baseColor, float percent) + { + int H, I, S; + + WidgetPaint.Color2HBS(baseColor, out H, out I, out S); + int NewIntensity = Math.Min(255, (int)(I * percent)); + + return WidgetPaint.HBS2Color(H, NewIntensity, S); + } + + } + } +} diff --git a/source/ShiftUI/Theming/ThemeElementsNice.cs b/source/ShiftUI/Theming/ThemeElementsNice.cs new file mode 100644 index 0000000..ff2ff45 --- /dev/null +++ b/source/ShiftUI/Theming/ThemeElementsNice.cs @@ -0,0 +1,43 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Andreia Gaita (avidigal@novell.com) + +using System; + +namespace ShiftUI.Theming +{ + internal class ThemeElementsNice: ThemeElementsDefault + { + /* If we want to add a custom-themed Widget, add an override here + * like this: + + public override Default.TabWidgetPainter TabWidgetPainter { + get { + if (tabWidgetPainter == null) + tabWidgetPainter = (Default.TabWidgetPainter) new Nice.TabWidgetPainter (); + return tabWidgetPainter; + } + } + */ + } +} diff --git a/source/ShiftUI/Theming/ThemeElementsVisualStyles.cs b/source/ShiftUI/Theming/ThemeElementsVisualStyles.cs new file mode 100644 index 0000000..1e5bf1c --- /dev/null +++ b/source/ShiftUI/Theming/ThemeElementsVisualStyles.cs @@ -0,0 +1,59 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2008 George Giolfan +// +// Authors: +// George Giolfan (georgegiolfan@yahoo.com) +using ShiftUI.Theming.Default; + +namespace ShiftUI.Theming +{ + class ThemeElementsVisualStyles : ThemeElementsDefault + { + public override CheckBoxPainter CheckBoxPainter { + get { + if (checkBoxPainter == null) + checkBoxPainter = new VisualStyles.CheckBoxPainter (); + return checkBoxPainter; + } + } + public override RadioButtonPainter RadioButtonPainter { + get { + if (radioButtonPainter == null) + radioButtonPainter = new VisualStyles.RadioButtonPainter (); + return radioButtonPainter; + } + } + public override ToolStripPainter ToolStripPainter { + get { + if (toolStripPainter == null) + toolStripPainter = new VisualStyles.ToolStripPainter (); + return toolStripPainter; + } + } + public override TabWidgetPainter TabWidgetPainter { + get { + if (tabWidgetPainter == null) + tabWidgetPainter = new VisualStyles.TabWidgetPainter (); + return tabWidgetPainter; + } + } + } +} diff --git a/source/ShiftUI/Theming/ThemeEngine.cs b/source/ShiftUI/Theming/ThemeEngine.cs new file mode 100644 index 0000000..89d2804 --- /dev/null +++ b/source/ShiftUI/Theming/ThemeEngine.cs @@ -0,0 +1,62 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// +// + + +using ShiftUI.Theming; +using System; + +namespace ShiftUI +{ + internal class ThemeEngine + { + static private Theme theme = null; + + static ThemeEngine () + { + string theme_var; + + theme_var = Environment.GetEnvironmentVariable("MONO_THEME"); + + if (theme_var == null) { + theme_var = "memphis"; //Screw win32. Memphis all the way! + } else { + theme_var = theme_var.ToLower (); + } + + if (Application.VisualStylesEnabled) { + theme = new ThemeSkinnable(); //ShiftOS skin engine will be moved into here, possibly. + } else { + theme = new ThemeWin32Classic (); + } + } + + + public static Theme Current { + get { return theme; } + } + + } +} diff --git a/source/ShiftUI/Theming/ThemeSkinnable.cs b/source/ShiftUI/Theming/ThemeSkinnable.cs new file mode 100644 index 0000000..bf8b56f --- /dev/null +++ b/source/ShiftUI/Theming/ThemeSkinnable.cs @@ -0,0 +1,8351 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// Peter Bartok, pbartok@novell.com +// John BouAntoun, jba-mono@optusnet.com.au +// Marek Safar, marek.safar@seznam.cz +// Alexander Olk, alex.olk@googlemail.com +// + +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.Drawing.Printing; +using System.Drawing.Text; +using System.Text; +using ShiftUI.Theming; +using System; + +namespace ShiftUI +{ + + internal class ThemeSkinnable : Theme + { + public void LoadSkin(ShiftOS.Skin skin) + { + Application.LoadSkin(skin); + MemphisThemeElements.Init(); + } + + public override Version Version + { + get + { + return new Version("0.0.1.alpha1"); + } + } + + /* Hardcoded colour values not exposed in the API constants in all configurations */ + protected static readonly Color arrow_color = Color.Black; + protected static readonly Color pen_ticks_color = Color.Black; + protected static StringFormat string_format_menu_text; + protected static StringFormat string_format_menu_shortcut; + protected static StringFormat string_format_menu_menubar_text; + static ImageAttributes imagedisabled_attributes; + Font window_border_font; + const int SEPARATOR_HEIGHT = 6; + const int SEPARATOR_MIN_WIDTH = 20; + const int SM_CXBORDER = 1; + const int SM_CYBORDER = 1; + const int MENU_TAB_SPACE = 8; // Pixels added to the width of an item because of a tabd + const int MENU_BAR_ITEMS_SPACE = 8; // Space between menu bar items + const int CheckSize = 13; + + #region Principal Theme Methods + public ThemeSkinnable() + { + if (Application.CurrentSkin == null) + Application.LoadSkin(new ShiftOS.DefaultSkin()); + ResetDefaults(); + } + + public override void ResetDefaults() + { + defaultWindowBackColor = Application.CurrentSkin.WindowBackColor; + defaultWindowForeColor = Application.CurrentSkin.DefaultForeColor; + window_border_font = new Font("Microsoft Sans Serif", 9, FontStyle.Bold); + + /* Menu string formats */ + string_format_menu_text = new StringFormat(); + string_format_menu_text.LineAlignment = StringAlignment.Center; + string_format_menu_text.Alignment = StringAlignment.Near; + string_format_menu_text.HotkeyPrefix = HotkeyPrefix.Show; + string_format_menu_text.SetTabStops(0f, new float[] { 50f }); + string_format_menu_text.FormatFlags |= StringFormatFlags.NoWrap; + + string_format_menu_shortcut = new StringFormat(); + string_format_menu_shortcut.LineAlignment = StringAlignment.Center; + string_format_menu_shortcut.Alignment = StringAlignment.Far; + + string_format_menu_menubar_text = new StringFormat(); + string_format_menu_menubar_text.LineAlignment = StringAlignment.Center; + string_format_menu_menubar_text.Alignment = StringAlignment.Center; + string_format_menu_menubar_text.HotkeyPrefix = HotkeyPrefix.Show; + } + + public override bool DoubleBufferingSupported + { + get { return true; } + } + + public override int HorizontalScrollBarHeight + { + get + { + return Application.CurrentSkin.ScrollbarWidth; + } + } + + public override int VerticalScrollBarWidth + { + get + { + return Application.CurrentSkin.ScrollbarWidth; + } + } + + public override Font WindowBorderFont + { + get + { + return window_border_font ?? (window_border_font = new Font(FontFamily.GenericSansSerif, 8.25f, FontStyle.Bold)); + } + } + + #endregion // Principal Theme Methods + + #region Internal Methods + protected Brush GetControlBackBrush(Color c) + { + if (c.ToArgb() == DefaultControlBackColor.ToArgb()) + return SystemBrushes.Control; + return ResPool.GetSolidBrush(c); + } + + protected Brush GetControlForeBrush(Color c) + { + if (c.ToArgb() == DefaultControlForeColor.ToArgb()) + return SystemBrushes.ControlText; + return ResPool.GetSolidBrush(c); + } + #endregion // Internal Methods + + #region Widget + public override Font GetLinkFont(Widget control) + { + return new Font(control.Font.FontFamily, control.Font.Size, control.Font.Style | FontStyle.Underline, control.Font.Unit); + } + #endregion // Widget + + #region OwnerDraw Support + public override void DrawOwnerDrawBackground(DrawItemEventArgs e) + { + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) + { + e.Graphics.FillRectangle(SystemBrushes.Highlight, e.Bounds); + return; + } + + e.Graphics.FillRectangle(ResPool.GetSolidBrush(e.BackColor), e.Bounds); + } + + public override void DrawOwnerDrawFocusRectangle(DrawItemEventArgs e) + { + if (e.State == DrawItemState.Focus) + CPDrawFocusRectangle(e.Graphics, e.Bounds, e.ForeColor, e.BackColor); + } + #endregion // OwnerDraw Support + + #region Button + #region Standard Button Style + public override void DrawButton(Graphics g, Button b, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle) + { + // Draw Button Background + DrawButtonBackground(g, b, clipRectangle); + + // If we have an image, draw it + if (imageBounds.Size != Size.Empty) + DrawButtonImage(g, b, imageBounds); + + // If we're focused, draw a focus rectangle + if (b.Focused && b.Enabled && b.ShowFocusCues) + DrawButtonFocus(g, b); + + // If we have text, draw it + if (textBounds != Rectangle.Empty) + DrawButtonText(g, b, textBounds); + } + + public virtual void DrawButtonBackground(Graphics g, Button button, Rectangle clipArea) + { + var fc = button.ForeColor; + if (fc == null) + fc = Application.CurrentSkin.DefaultForeColor; + + if (button.Pressed) + MemphisThemeElements.DrawButton(g, button.ClientRectangle, ButtonThemeState.Pressed, Application.CurrentSkin.ButtonBackColor_Pressed, fc); + else if (button.InternalSelected) + MemphisThemeElements.DrawButton(g, button.ClientRectangle, ButtonThemeState.Default, Application.CurrentSkin.ButtonBackColor, fc); + else if (button.Entered) + MemphisThemeElements.DrawButton(g, button.ClientRectangle, ButtonThemeState.Entered, Application.CurrentSkin.ButtonBackColor, fc); + else if (!button.Enabled) + MemphisThemeElements.DrawButton(g, button.ClientRectangle, ButtonThemeState.Disabled, Application.CurrentSkin.ButtonBackColor, fc); + else + MemphisThemeElements.DrawButton(g, button.ClientRectangle, ButtonThemeState.Normal, Application.CurrentSkin.ButtonBackColor, fc); + } + + public virtual void DrawButtonFocus(Graphics g, Button button) + { + WidgetPaint.DrawFocusRectangle(g, Rectangle.Inflate(button.ClientRectangle, -4, -4)); + } + + public virtual void DrawButtonImage(Graphics g, ButtonBase button, Rectangle imageBounds) + { + if (button.Enabled) + g.DrawImage(button.Image, imageBounds); + else + CPDrawImageDisabled(g, button.Image, imageBounds.Left, imageBounds.Top, ColorControl); + } + + public virtual void DrawButtonText(Graphics g, ButtonBase button, Rectangle textBounds) + { + // Ensure that at least one line is going to get displayed. + // Line limit does not ensure that despite its description. + if (button.Font != null && button.Font.Height > 0) + textBounds.Height = Math.Max(textBounds.Height, button.Font.Height); + + if (button.Enabled) + TextRenderer.DrawTextInternal(g, button.Text, button.Font, textBounds, button.ForeColor, button.TextFormatFlags, button.UseCompatibleTextRendering); + else + DrawStringDisabled20(g, button.Text, button.Font, textBounds, button.BackColor, button.TextFormatFlags, button.UseCompatibleTextRendering); + } + #endregion + + #region FlatStyle Button Style + public override void DrawFlatButton(Graphics g, ButtonBase b, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle) + { + // Draw Button Background + if (b.BackgroundImage == null) + DrawFlatButtonBackground(g, b, clipRectangle); + + // If we have an image, draw it + if (imageBounds.Size != Size.Empty) + DrawFlatButtonImage(g, b, imageBounds); + + // If we're focused, draw a focus rectangle + if (b.Focused && b.Enabled && b.ShowFocusCues) + DrawFlatButtonFocus(g, b); + + // If we have text, draw it + if (textBounds != Rectangle.Empty) + DrawFlatButtonText(g, b, textBounds); + } + + public virtual void DrawFlatButtonBackground(Graphics g, ButtonBase button, Rectangle clipArea) + { + if (button.Pressed) + MemphisThemeElements.DrawFlatButton(g, button.ClientRectangle, ButtonThemeState.Pressed, button.BackColor, button.ForeColor, button.FlatAppearance); + else if (button.InternalSelected) + { + if (button.Entered) + MemphisThemeElements.DrawFlatButton(g, button.ClientRectangle, ButtonThemeState.Default | ButtonThemeState.Entered, button.BackColor, button.ForeColor, button.FlatAppearance); + else + MemphisThemeElements.DrawFlatButton(g, button.ClientRectangle, ButtonThemeState.Default, button.BackColor, button.ForeColor, button.FlatAppearance); + } + else if (button.Entered) + MemphisThemeElements.DrawFlatButton(g, button.ClientRectangle, ButtonThemeState.Entered, button.BackColor, button.ForeColor, button.FlatAppearance); + else if (!button.Enabled) + MemphisThemeElements.DrawFlatButton(g, button.ClientRectangle, ButtonThemeState.Disabled, button.BackColor, button.ForeColor, button.FlatAppearance); + else + MemphisThemeElements.DrawFlatButton(g, button.ClientRectangle, ButtonThemeState.Normal, button.BackColor, button.ForeColor, button.FlatAppearance); + } + + public virtual void DrawFlatButtonFocus(Graphics g, ButtonBase button) + { + if (!button.Pressed) + { + Color focus_color = WidgetPaint.Dark(button.BackColor); + g.DrawRectangle(ResPool.GetPen(focus_color), new Rectangle(button.ClientRectangle.Left + 4, button.ClientRectangle.Top + 4, button.ClientRectangle.Width - 9, button.ClientRectangle.Height - 9)); + } + } + + public virtual void DrawFlatButtonImage(Graphics g, ButtonBase button, Rectangle imageBounds) + { + // No changes from Standard for image for this theme + DrawButtonImage(g, button, imageBounds); + } + + public virtual void DrawFlatButtonText(Graphics g, ButtonBase button, Rectangle textBounds) + { + // No changes from Standard for text for this theme + DrawButtonText(g, button, textBounds); + } + #endregion + + #region Popup Button Style + public override void DrawPopupButton(Graphics g, Button b, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle) + { + // Draw Button Background + DrawPopupButtonBackground(g, b, clipRectangle); + + // If we have an image, draw it + if (imageBounds.Size != Size.Empty) + DrawPopupButtonImage(g, b, imageBounds); + + // If we're focused, draw a focus rectangle + if (b.Focused && b.Enabled && b.ShowFocusCues) + DrawPopupButtonFocus(g, b); + + // If we have text, draw it + if (textBounds != Rectangle.Empty) + DrawPopupButtonText(g, b, textBounds); + } + + public virtual void DrawPopupButtonBackground(Graphics g, Button button, Rectangle clipArea) + { + if (button.Pressed) + MemphisThemeElements.DrawPopupButton(g, button.ClientRectangle, ButtonThemeState.Pressed, button.BackColor, button.ForeColor); + else if (button.Entered) + MemphisThemeElements.DrawPopupButton(g, button.ClientRectangle, ButtonThemeState.Entered, button.BackColor, button.ForeColor); + else if (button.InternalSelected) + MemphisThemeElements.DrawPopupButton(g, button.ClientRectangle, ButtonThemeState.Default, button.BackColor, button.ForeColor); + else if (!button.Enabled) + MemphisThemeElements.DrawPopupButton(g, button.ClientRectangle, ButtonThemeState.Disabled, button.BackColor, button.ForeColor); + else + MemphisThemeElements.DrawPopupButton(g, button.ClientRectangle, ButtonThemeState.Normal, button.BackColor, button.ForeColor); + } + + public virtual void DrawPopupButtonFocus(Graphics g, Button button) + { + // No changes from Standard for image for this theme + DrawButtonFocus(g, button); + } + + public virtual void DrawPopupButtonImage(Graphics g, Button button, Rectangle imageBounds) + { + // No changes from Standard for image for this theme + DrawButtonImage(g, button, imageBounds); + } + + public virtual void DrawPopupButtonText(Graphics g, Button button, Rectangle textBounds) + { + // No changes from Standard for image for this theme + DrawButtonText(g, button, textBounds); + } + #endregion + + #region Button Layout Calculations + public override Size CalculateButtonAutoSize(Button button) + { + Size ret_size = Size.Empty; + Size text_size = TextRenderer.MeasureTextInternal(button.Text, button.Font, button.UseCompatibleTextRendering); + Size image_size = button.Image == null ? Size.Empty : button.Image.Size; + + // Pad the text size + if (button.Text.Length != 0) + { + text_size.Height += 4; + text_size.Width += 4; + } + + switch (button.TextImageRelation) + { + case TextImageRelation.Overlay: + ret_size.Height = Math.Max(button.Text.Length == 0 ? 0 : text_size.Height, image_size.Height); + ret_size.Width = Math.Max(text_size.Width, image_size.Width); + break; + case TextImageRelation.ImageAboveText: + case TextImageRelation.TextAboveImage: + ret_size.Height = text_size.Height + image_size.Height; + ret_size.Width = Math.Max(text_size.Width, image_size.Width); + break; + case TextImageRelation.ImageBeforeText: + case TextImageRelation.TextBeforeImage: + ret_size.Height = Math.Max(text_size.Height, image_size.Height); + ret_size.Width = text_size.Width + image_size.Width; + break; + } + + // Pad the result + ret_size.Height += (button.Padding.Vertical + 6); + ret_size.Width += (button.Padding.Horizontal + 6); + + return ret_size; + } + + public override void CalculateButtonTextAndImageLayout(Graphics g, ButtonBase button, out Rectangle textRectangle, out Rectangle imageRectangle) + { + Image image = button.Image; + string text = button.Text; + Rectangle content_rect = button.PaddingClientRectangle; + Size text_size = TextRenderer.MeasureTextInternal(g, text, button.Font, content_rect.Size, button.TextFormatFlags, button.UseCompatibleTextRendering); + Size image_size = image == null ? Size.Empty : image.Size; + + textRectangle = Rectangle.Inflate(content_rect, -4, -4); + imageRectangle = Rectangle.Empty; + + bool displayEllipsis = (button.TextFormatFlags & (TextFormatFlags.EndEllipsis | TextFormatFlags.PathEllipsis | TextFormatFlags.WordEllipsis)) != 0; + + switch (button.TextImageRelation) + { + case TextImageRelation.Overlay: + // Overlay is easy, text always goes here + + // Image is dependent on ImageAlign + if (image == null) + { + if (button.Pressed) + textRectangle.Offset(1, 1); + return; + } + + int image_x = 0; + int image_y = 0; + int image_height = image.Height; + int image_width = image.Width; + + switch (button.ImageAlign) + { + case System.Drawing.ContentAlignment.TopLeft: + image_x = 5; + image_y = 5; + break; + case System.Drawing.ContentAlignment.TopCenter: + image_x = (content_rect.Width - image_width) / 2; + image_y = 5; + break; + case System.Drawing.ContentAlignment.TopRight: + image_x = content_rect.Width - image_width - 5; + image_y = 5; + break; + case System.Drawing.ContentAlignment.MiddleLeft: + image_x = 5; + image_y = (content_rect.Height - image_height) / 2; + break; + case System.Drawing.ContentAlignment.MiddleCenter: + image_x = (content_rect.Width - image_width) / 2; + image_y = (content_rect.Height - image_height) / 2; + break; + case System.Drawing.ContentAlignment.MiddleRight: + image_x = content_rect.Width - image_width - 4; + image_y = (content_rect.Height - image_height) / 2; + break; + case System.Drawing.ContentAlignment.BottomLeft: + image_x = 5; + image_y = content_rect.Height - image_height - 4; + break; + case System.Drawing.ContentAlignment.BottomCenter: + image_x = (content_rect.Width - image_width) / 2; + image_y = content_rect.Height - image_height - 4; + break; + case System.Drawing.ContentAlignment.BottomRight: + image_x = content_rect.Width - image_width - 4; + image_y = content_rect.Height - image_height - 4; + break; + default: + image_x = 5; + image_y = 5; + break; + } + + imageRectangle = new Rectangle(image_x, image_y, image_width, image_height); + break; + case TextImageRelation.ImageAboveText: + LayoutTextAboveOrBelowImage(textRectangle, false, text_size, image_size, button.TextAlign, button.ImageAlign, displayEllipsis, out textRectangle, out imageRectangle); + break; + case TextImageRelation.TextAboveImage: + LayoutTextAboveOrBelowImage(textRectangle, true, text_size, image_size, button.TextAlign, button.ImageAlign, displayEllipsis, out textRectangle, out imageRectangle); + break; + case TextImageRelation.ImageBeforeText: + LayoutTextBeforeOrAfterImage(textRectangle, false, text_size, image_size, button.TextAlign, button.ImageAlign, out textRectangle, out imageRectangle); + break; + case TextImageRelation.TextBeforeImage: + LayoutTextBeforeOrAfterImage(textRectangle, true, text_size, image_size, button.TextAlign, button.ImageAlign, out textRectangle, out imageRectangle); + break; + } + if (button.Pressed) + textRectangle.Offset(1, 1); + } + + private void LayoutTextBeforeOrAfterImage(Rectangle totalArea, bool textFirst, Size textSize, Size imageSize, System.Drawing.ContentAlignment textAlign, System.Drawing.ContentAlignment imageAlign, out Rectangle textRect, out Rectangle imageRect) + { + int element_spacing = 0; // Spacing between the Text and the Image + int total_width = textSize.Width + element_spacing + imageSize.Width; + + if (!textFirst) + element_spacing += 2; + + // If the text is too big, chop it down to the size we have available to it + if (total_width > totalArea.Width) + { + textSize.Width = totalArea.Width - element_spacing - imageSize.Width; + total_width = totalArea.Width; + } + + int excess_width = totalArea.Width - total_width; + int offset = 0; + + Rectangle final_text_rect; + Rectangle final_image_rect; + + HorizontalAlignment h_text = GetHorizontalAlignment(textAlign); + HorizontalAlignment h_image = GetHorizontalAlignment(imageAlign); + + if (h_image == HorizontalAlignment.Left) + offset = 0; + else if (h_image == HorizontalAlignment.Right && h_text == HorizontalAlignment.Right) + offset = excess_width; + else if (h_image == HorizontalAlignment.Center && (h_text == HorizontalAlignment.Left || h_text == HorizontalAlignment.Center)) + offset += (int)(excess_width / 3); + else + offset += (int)(2 * (excess_width / 3)); + + if (textFirst) + { + final_text_rect = new Rectangle(totalArea.Left + offset, AlignInRectangle(totalArea, textSize, textAlign).Top, textSize.Width, textSize.Height); + final_image_rect = new Rectangle(final_text_rect.Right + element_spacing, AlignInRectangle(totalArea, imageSize, imageAlign).Top, imageSize.Width, imageSize.Height); + } + else + { + final_image_rect = new Rectangle(totalArea.Left + offset, AlignInRectangle(totalArea, imageSize, imageAlign).Top, imageSize.Width, imageSize.Height); + final_text_rect = new Rectangle(final_image_rect.Right + element_spacing, AlignInRectangle(totalArea, textSize, textAlign).Top, textSize.Width, textSize.Height); + } + + textRect = final_text_rect; + imageRect = final_image_rect; + } + + private void LayoutTextAboveOrBelowImage(Rectangle totalArea, bool textFirst, Size textSize, Size imageSize, System.Drawing.ContentAlignment textAlign, System.Drawing.ContentAlignment imageAlign, bool displayEllipsis, out Rectangle textRect, out Rectangle imageRect) + { + int element_spacing = 0; // Spacing between the Text and the Image + int total_height = textSize.Height + element_spacing + imageSize.Height; + + if (textFirst) + element_spacing += 2; + + if (textSize.Width > totalArea.Width) + textSize.Width = totalArea.Width; + + // If the there isn't enough room and we're text first, cut out the image + if (total_height > totalArea.Height && textFirst) + { + imageSize = Size.Empty; + total_height = totalArea.Height; + } + + int excess_height = totalArea.Height - total_height; + int offset = 0; + + Rectangle final_text_rect; + Rectangle final_image_rect; + + VerticalAlignment v_text = GetVerticalAlignment(textAlign); + VerticalAlignment v_image = GetVerticalAlignment(imageAlign); + + if (v_image == VerticalAlignment.Top) + offset = 0; + else if (v_image == VerticalAlignment.Bottom && v_text == VerticalAlignment.Bottom) + offset = excess_height; + else if (v_image == VerticalAlignment.Center && (v_text == VerticalAlignment.Top || v_text == VerticalAlignment.Center)) + offset += (int)(excess_height / 3); + else + offset += (int)(2 * (excess_height / 3)); + + if (textFirst) + { + var textHeight = excess_height >= 0 ? totalArea.Height - imageSize.Height - element_spacing : textSize.Height; + final_text_rect = new Rectangle(AlignInRectangle(totalArea, textSize, textAlign).Left, totalArea.Top + offset, textSize.Width, textHeight); + final_image_rect = new Rectangle(AlignInRectangle(totalArea, imageSize, imageAlign).Left, final_text_rect.Bottom + element_spacing, imageSize.Width, imageSize.Height); + } + else + { + final_image_rect = new Rectangle(AlignInRectangle(totalArea, imageSize, imageAlign).Left, totalArea.Top + offset, imageSize.Width, imageSize.Height); + var textHeight = excess_height >= 0 ? totalArea.Height - final_image_rect.Height : textSize.Height; + final_text_rect = new Rectangle(AlignInRectangle(totalArea, textSize, textAlign).Left, final_image_rect.Bottom + element_spacing, textSize.Width, textHeight); + + if (final_text_rect.Bottom > totalArea.Bottom) + { + final_text_rect.Y -= (final_text_rect.Bottom - totalArea.Bottom); + if (final_text_rect.Y < totalArea.Top) + final_text_rect.Y = totalArea.Top; + } + } + + if (displayEllipsis) + { + // Don't use more space than is available otherwise ellipsis won't show + if (final_text_rect.Height > totalArea.Bottom) + final_text_rect.Height = totalArea.Bottom - final_text_rect.Top; + } + + textRect = final_text_rect; + imageRect = final_image_rect; + } + + private HorizontalAlignment GetHorizontalAlignment(System.Drawing.ContentAlignment align) + { + switch (align) + { + case System.Drawing.ContentAlignment.BottomLeft: + case System.Drawing.ContentAlignment.MiddleLeft: + case System.Drawing.ContentAlignment.TopLeft: + return HorizontalAlignment.Left; + case System.Drawing.ContentAlignment.BottomCenter: + case System.Drawing.ContentAlignment.MiddleCenter: + case System.Drawing.ContentAlignment.TopCenter: + return HorizontalAlignment.Center; + case System.Drawing.ContentAlignment.BottomRight: + case System.Drawing.ContentAlignment.MiddleRight: + case System.Drawing.ContentAlignment.TopRight: + return HorizontalAlignment.Right; + } + + return HorizontalAlignment.Left; + } + + private enum VerticalAlignment + { + Top = 0, + Center = 1, + Bottom = 2 + } + + private VerticalAlignment GetVerticalAlignment(System.Drawing.ContentAlignment align) + { + switch (align) + { + case System.Drawing.ContentAlignment.TopLeft: + case System.Drawing.ContentAlignment.TopCenter: + case System.Drawing.ContentAlignment.TopRight: + return VerticalAlignment.Top; + case System.Drawing.ContentAlignment.MiddleLeft: + case System.Drawing.ContentAlignment.MiddleCenter: + case System.Drawing.ContentAlignment.MiddleRight: + return VerticalAlignment.Center; + case System.Drawing.ContentAlignment.BottomLeft: + case System.Drawing.ContentAlignment.BottomCenter: + case System.Drawing.ContentAlignment.BottomRight: + return VerticalAlignment.Bottom; + } + + return VerticalAlignment.Top; + } + + internal Rectangle AlignInRectangle(Rectangle outer, Size inner, System.Drawing.ContentAlignment align) + { + int x = 0; + int y = 0; + + if (align == System.Drawing.ContentAlignment.BottomLeft || align == System.Drawing.ContentAlignment.MiddleLeft || align == System.Drawing.ContentAlignment.TopLeft) + x = outer.X; + else if (align == System.Drawing.ContentAlignment.BottomCenter || align == System.Drawing.ContentAlignment.MiddleCenter || align == System.Drawing.ContentAlignment.TopCenter) + x = Math.Max(outer.X + ((outer.Width - inner.Width) / 2), outer.Left); + else if (align == System.Drawing.ContentAlignment.BottomRight || align == System.Drawing.ContentAlignment.MiddleRight || align == System.Drawing.ContentAlignment.TopRight) + x = outer.Right - inner.Width; + if (align == System.Drawing.ContentAlignment.TopCenter || align == System.Drawing.ContentAlignment.TopLeft || align == System.Drawing.ContentAlignment.TopRight) + y = outer.Y; + else if (align == System.Drawing.ContentAlignment.MiddleCenter || align == System.Drawing.ContentAlignment.MiddleLeft || align == System.Drawing.ContentAlignment.MiddleRight) + y = outer.Y + (outer.Height - inner.Height) / 2; + else if (align == System.Drawing.ContentAlignment.BottomCenter || align == System.Drawing.ContentAlignment.BottomRight || align == System.Drawing.ContentAlignment.BottomLeft) + y = outer.Bottom - inner.Height; + + return new Rectangle(x, y, Math.Min(inner.Width, outer.Width), Math.Min(inner.Height, outer.Height)); + } + #endregion + #endregion + + #region ButtonBase + public override void DrawButtonBase(Graphics dc, Rectangle clip_area, ButtonBase button) + { + // Draw the button: Draw border, etc. + ButtonBase_DrawButton(button, dc); + + // Draw the image + if (button.FlatStyle != FlatStyle.System && ((button.image != null) || (button.image_list != null))) + ButtonBase_DrawImage(button, dc); + + // Draw the focus rectangle + if (ShouldPaintFocusRectagle(button)) + ButtonBase_DrawFocus(button, dc); + + // Now the text + if (button.Text != null && button.Text != String.Empty) + ButtonBase_DrawText(button, dc); + } + + protected static bool ShouldPaintFocusRectagle(ButtonBase button) + { + return (button.Focused || button.paint_as_acceptbutton) && button.Enabled && button.ShowFocusCues; + } + + protected virtual void ButtonBase_DrawButton(ButtonBase button, Graphics dc) + { + Rectangle borderRectangle; + bool check_or_radio = false; + bool check_or_radio_checked = false; + + bool is_ColorControl = button.BackColor.ToArgb() == ColorControl.ToArgb() ? true : false; + + CPColor cpcolor = is_ColorControl ? CPColor.Empty : ResPool.GetCPColor(button.BackColor); + + if (button is CheckBox) + { + check_or_radio = true; + check_or_radio_checked = ((CheckBox)button).Checked; + } + else if (button is RadioButton) + { + check_or_radio = true; + check_or_radio_checked = ((RadioButton)button).Checked; + } + + if (button.Focused && button.Enabled && !check_or_radio) + { + // shrink the rectangle for the normal button drawing inside the focus rectangle + borderRectangle = Rectangle.Inflate(button.ClientRectangle, -1, -1); + } + else + { + borderRectangle = button.ClientRectangle; + } + + if (button.FlatStyle == FlatStyle.Popup) + { + if (!button.is_pressed && !button.is_entered && !check_or_radio_checked) + Internal_DrawButton(dc, borderRectangle, 1, cpcolor, is_ColorControl, button.BackColor); + else if (!button.is_pressed && button.is_entered && !check_or_radio_checked) + Internal_DrawButton(dc, borderRectangle, 2, cpcolor, is_ColorControl, button.BackColor); + else if (button.is_pressed || check_or_radio_checked) + Internal_DrawButton(dc, borderRectangle, 1, cpcolor, is_ColorControl, button.BackColor); + } + else if (button.FlatStyle == FlatStyle.Flat) + { + if (button.is_entered && !button.is_pressed && !check_or_radio_checked) + { + if ((button.image == null) && (button.image_list == null)) + { + Brush brush = is_ColorControl ? SystemBrushes.ControlDark : ResPool.GetSolidBrush(cpcolor.Dark); + dc.FillRectangle(brush, borderRectangle); + } + } + else if (button.is_pressed || check_or_radio_checked) + { + if ((button.image == null) && (button.image_list == null)) + { + Brush brush = is_ColorControl ? SystemBrushes.ControlLightLight : ResPool.GetSolidBrush(cpcolor.LightLight); + dc.FillRectangle(brush, borderRectangle); + } + + Pen pen = is_ColorControl ? SystemPens.ControlDark : ResPool.GetPen(cpcolor.Dark); + dc.DrawRectangle(pen, borderRectangle.X + 4, borderRectangle.Y + 4, + borderRectangle.Width - 9, borderRectangle.Height - 9); + } + + Internal_DrawButton(dc, borderRectangle, 3, cpcolor, is_ColorControl, button.BackColor); + } + else + { + if ((!button.is_pressed || !button.Enabled) && !check_or_radio_checked) + Internal_DrawButton(dc, borderRectangle, 0, cpcolor, is_ColorControl, button.BackColor); + else + Internal_DrawButton(dc, borderRectangle, 1, cpcolor, is_ColorControl, button.BackColor); + } + } + + private void Internal_DrawButton(Graphics dc, Rectangle rect, int state, CPColor cpcolor, bool is_ColorControl, Color backcolor) + { + switch (state) + { + case 0: // normal or normal disabled button + Pen pen = is_ColorControl ? SystemPens.ControlLightLight : ResPool.GetPen(cpcolor.LightLight); + dc.DrawLine(pen, rect.X, rect.Y, rect.X, rect.Bottom - 2); + dc.DrawLine(pen, rect.X + 1, rect.Y, rect.Right - 2, rect.Y); + + pen = is_ColorControl ? SystemPens.Control : ResPool.GetPen(backcolor); + dc.DrawLine(pen, rect.X + 1, rect.Y + 1, rect.X + 1, rect.Bottom - 3); + dc.DrawLine(pen, rect.X + 2, rect.Y + 1, rect.Right - 3, rect.Y + 1); + + pen = is_ColorControl ? SystemPens.ControlDark : ResPool.GetPen(cpcolor.Dark); + dc.DrawLine(pen, rect.X + 1, rect.Bottom - 2, rect.Right - 2, rect.Bottom - 2); + dc.DrawLine(pen, rect.Right - 2, rect.Y + 1, rect.Right - 2, rect.Bottom - 3); + + pen = is_ColorControl ? SystemPens.ControlDarkDark : ResPool.GetPen(cpcolor.DarkDark); + dc.DrawLine(pen, rect.X, rect.Bottom - 1, rect.Right - 1, rect.Bottom - 1); + dc.DrawLine(pen, rect.Right - 1, rect.Y, rect.Right - 1, rect.Bottom - 2); + break; + case 1: // popup button normal (or pressed normal or popup button) + pen = is_ColorControl ? SystemPens.ControlDark : ResPool.GetPen(cpcolor.Dark); + dc.DrawRectangle(pen, rect.X, rect.Y, rect.Width - 1, rect.Height - 1); + break; + case 2: // popup button poped up + pen = is_ColorControl ? SystemPens.ControlLightLight : ResPool.GetPen(cpcolor.LightLight); + dc.DrawLine(pen, rect.X, rect.Y, rect.X, rect.Bottom - 2); + dc.DrawLine(pen, rect.X + 1, rect.Y, rect.Right - 2, rect.Y); + + pen = is_ColorControl ? SystemPens.ControlDark : ResPool.GetPen(cpcolor.Dark); + dc.DrawLine(pen, rect.X, rect.Bottom - 1, rect.Right - 1, rect.Bottom - 1); + dc.DrawLine(pen, rect.Right - 1, rect.Y, rect.Right - 1, rect.Bottom - 2); + break; + case 3: // flat button not entered + pen = is_ColorControl ? SystemPens.ControlDarkDark : ResPool.GetPen(cpcolor.DarkDark); + dc.DrawRectangle(pen, rect.X, rect.Y, rect.Width - 1, rect.Height - 1); + break; + default: + break; + } + } + + protected virtual void ButtonBase_DrawImage(ButtonBase button, Graphics dc) + { + // Need to draw a picture + Image i; + int image_x; + int image_y; + int image_width; + int image_height; + + int width = button.ClientSize.Width; + int height = button.ClientSize.Height; + + if (button.ImageIndex != -1) + { // We use ImageIndex instead of image_index since it will return -1 if image_list is null + i = button.image_list.Images[button.ImageIndex]; + } + else + { + i = button.image; + } + + image_width = i.Width; + image_height = i.Height; + + switch (button.ImageAlign) + { + case ContentAlignment.TopLeft: + { + image_x = 5; + image_y = 5; + break; + } + + case ContentAlignment.TopCenter: + { + image_x = (width - image_width) / 2; + image_y = 5; + break; + } + + case ContentAlignment.TopRight: + { + image_x = width - image_width - 5; + image_y = 5; + break; + } + + case ContentAlignment.MiddleLeft: + { + image_x = 5; + image_y = (height - image_height) / 2; + break; + } + + case ContentAlignment.MiddleCenter: + { + image_x = (width - image_width) / 2; + image_y = (height - image_height) / 2; + break; + } + + case ContentAlignment.MiddleRight: + { + image_x = width - image_width - 4; + image_y = (height - image_height) / 2; + break; + } + + case ContentAlignment.BottomLeft: + { + image_x = 5; + image_y = height - image_height - 4; + break; + } + + case ContentAlignment.BottomCenter: + { + image_x = (width - image_width) / 2; + image_y = height - image_height - 4; + break; + } + + case ContentAlignment.BottomRight: + { + image_x = width - image_width - 4; + image_y = height - image_height - 4; + break; + } + + default: + { + image_x = 5; + image_y = 5; + break; + } + } + + dc.SetClip(new Rectangle(3, 3, width - 5, height - 5)); + + if (button.Enabled) + dc.DrawImage(i, image_x, image_y, image_width, image_height); + else + CPDrawImageDisabled(dc, i, image_x, image_y, ColorControl); + + dc.ResetClip(); + } + + protected virtual void ButtonBase_DrawFocus(ButtonBase button, Graphics dc) + { + Color focus_color = button.ForeColor; + + int inflate_value = -3; + + if (!(button is CheckBox) && !(button is RadioButton)) + { + inflate_value = -4; + + if (button.FlatStyle == FlatStyle.Popup && !button.is_pressed) + focus_color = WidgetPaint.Dark(button.BackColor); + + dc.DrawRectangle(ResPool.GetPen(focus_color), button.ClientRectangle.X, button.ClientRectangle.Y, + button.ClientRectangle.Width - 1, button.ClientRectangle.Height - 1); + } + + if (button.Focused) + { + Rectangle rect = Rectangle.Inflate(button.ClientRectangle, inflate_value, inflate_value); + WidgetPaint.DrawFocusRectangle(dc, rect); + } + } + + protected virtual void ButtonBase_DrawText(ButtonBase button, Graphics dc) + { + Rectangle buttonRectangle = button.ClientRectangle; + Rectangle text_rect = Rectangle.Inflate(buttonRectangle, -4, -4); + + if (button.is_pressed) + { + text_rect.X++; + text_rect.Y++; + } + + // Ensure that at least one line is going to get displayed. + // Line limit does not ensure that despite its description. + text_rect.Height = Math.Max(button.Font.Height, text_rect.Height); + + if (button.Enabled) + { + dc.DrawString(button.Text, button.Font, ResPool.GetSolidBrush(button.ForeColor), text_rect, button.text_format); + } + else + { + if (button.FlatStyle == FlatStyle.Flat || button.FlatStyle == FlatStyle.Popup) + { + dc.DrawString(button.Text, button.Font, ResPool.GetSolidBrush(ColorGrayText), text_rect, button.text_format); + } + else + { + CPDrawStringDisabled(dc, button.Text, button.Font, button.BackColor, text_rect, button.text_format); + } + } + } + + public override Size ButtonBaseDefaultSize + { + get + { + return new Size(75, 23); + } + } + #endregion // ButtonBase + + #region CheckBox + public override void DrawCheckBox(Graphics g, CheckBox cb, Rectangle glyphArea, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle) + { + // Draw Button Background + if (cb.Appearance == Appearance.Button && cb.FlatStyle != FlatStyle.Flat) + ButtonBase_DrawButton(cb, g); + else if (cb.Appearance != Appearance.Button) + DrawCheckBoxGlyph(g, cb, glyphArea); + + // Draw the borders and such for a Flat CheckBox Button + if (cb.Appearance == Appearance.Button && cb.FlatStyle == FlatStyle.Flat) + DrawFlatButton(g, cb, textBounds, imageBounds, clipRectangle); + + // If we have an image, draw it + if (imageBounds.Size != Size.Empty) + DrawCheckBoxImage(g, cb, imageBounds); + + if (cb.Focused && cb.Enabled && cb.ShowFocusCues && textBounds != Rectangle.Empty) + DrawCheckBoxFocus(g, cb, textBounds); + + // If we have text, draw it + if (textBounds != Rectangle.Empty) + DrawCheckBoxText(g, cb, textBounds); + } + + public virtual void DrawCheckBoxGlyph(Graphics g, CheckBox cb, Rectangle glyphArea) + { + if (cb.Pressed) + MemphisThemeElements.CurrentTheme.CheckBoxPainter.PaintCheckBox(g, glyphArea, cb.BackColor, cb.ForeColor, ElementState.Pressed, cb.FlatStyle, cb.CheckState); + else if (cb.InternalSelected) + MemphisThemeElements.CurrentTheme.CheckBoxPainter.PaintCheckBox(g, glyphArea, cb.BackColor, cb.ForeColor, ElementState.Normal, cb.FlatStyle, cb.CheckState); + else if (cb.Entered) + MemphisThemeElements.CurrentTheme.CheckBoxPainter.PaintCheckBox(g, glyphArea, cb.BackColor, cb.ForeColor, ElementState.Hot, cb.FlatStyle, cb.CheckState); + else if (!cb.Enabled) + MemphisThemeElements.CurrentTheme.CheckBoxPainter.PaintCheckBox(g, glyphArea, cb.BackColor, cb.ForeColor, ElementState.Disabled, cb.FlatStyle, cb.CheckState); + else + MemphisThemeElements.CurrentTheme.CheckBoxPainter.PaintCheckBox(g, glyphArea, cb.BackColor, cb.ForeColor, ElementState.Normal, cb.FlatStyle, cb.CheckState); + } + + public virtual void DrawCheckBoxFocus(Graphics g, CheckBox cb, Rectangle focusArea) + { + WidgetPaint.DrawFocusRectangle(g, focusArea); + } + + public virtual void DrawCheckBoxImage(Graphics g, CheckBox cb, Rectangle imageBounds) + { + if (cb.Enabled) + g.DrawImage(cb.Image, imageBounds); + else + CPDrawImageDisabled(g, cb.Image, imageBounds.Left, imageBounds.Top, ColorControl); + } + + public virtual void DrawCheckBoxText(Graphics g, CheckBox cb, Rectangle textBounds) + { + if (cb.Enabled) + TextRenderer.DrawTextInternal(g, cb.Text, cb.Font, textBounds, cb.ForeColor, cb.TextFormatFlags, cb.UseCompatibleTextRendering); + else + DrawStringDisabled20(g, cb.Text, cb.Font, textBounds, cb.BackColor, cb.TextFormatFlags, cb.UseCompatibleTextRendering); + } + + public override void CalculateCheckBoxTextAndImageLayout(ButtonBase button, Point p, out Rectangle glyphArea, out Rectangle textRectangle, out Rectangle imageRectangle) + { + int check_size = CheckSize; + + if (button is CheckBox) + check_size = (button as CheckBox).Appearance == Appearance.Normal ? check_size : 0; + + glyphArea = new Rectangle(button.Padding.Left, button.Padding.Top, check_size, check_size); + + Rectangle content_rect = button.PaddingClientRectangle; + ContentAlignment align = ContentAlignment.TopLeft; + + if (button is CheckBox) + align = (button as CheckBox).CheckAlign; + else if (button is RadioButton) + align = (button as RadioButton).CheckAlign; + + switch (align) + { + case ContentAlignment.BottomCenter: + glyphArea.Y += content_rect.Height - check_size - 2; + glyphArea.X += (content_rect.Width - check_size) / 2; + break; + case ContentAlignment.BottomLeft: + glyphArea.Y += content_rect.Height - check_size - 2; + content_rect.Width -= check_size; + content_rect.Offset(check_size, 0); + break; + case ContentAlignment.BottomRight: + glyphArea.Y += content_rect.Height - check_size - 2; + glyphArea.X += content_rect.Width - check_size; + content_rect.Width -= check_size; + break; + case ContentAlignment.MiddleCenter: + glyphArea.Y += (content_rect.Height - check_size) / 2; + glyphArea.X += (content_rect.Width - check_size) / 2; + break; + case ContentAlignment.MiddleLeft: + glyphArea.Y += (content_rect.Height - check_size) / 2; + content_rect.Width -= check_size; + content_rect.Offset(check_size, 0); + break; + case ContentAlignment.MiddleRight: + glyphArea.Y += (content_rect.Height - check_size) / 2; + glyphArea.X += content_rect.Width - check_size; + content_rect.Width -= check_size; + break; + case ContentAlignment.TopCenter: + glyphArea.X += (content_rect.Width - check_size) / 2; + break; + case ContentAlignment.TopLeft: + content_rect.Width -= check_size; + content_rect.Offset(check_size, 0); + break; + case ContentAlignment.TopRight: + glyphArea.X += content_rect.Width - check_size; + content_rect.Width -= check_size; + break; + } + + Image image = button.Image; + string text = button.Text; + + Size proposed = Size.Empty; + + // Force wrapping if we aren't AutoSize and our text is too long + if (!button.AutoSize) + proposed.Width = button.PaddingClientRectangle.Width - glyphArea.Width - 2; + + Size text_size = TextRenderer.MeasureTextInternal(text, button.Font, proposed, button.TextFormatFlags, button.UseCompatibleTextRendering); + + // Text can't be bigger than the content rectangle + text_size.Height = Math.Min(text_size.Height, content_rect.Height); + text_size.Width = Math.Min(text_size.Width, content_rect.Width); + + Size image_size = image == null ? Size.Empty : image.Size; + + textRectangle = Rectangle.Empty; + imageRectangle = Rectangle.Empty; + + switch (button.TextImageRelation) + { + case TextImageRelation.Overlay: + // Text is centered vertically, and 2 pixels to the right + textRectangle.X = content_rect.Left + 2; + textRectangle.Y = button.PaddingClientRectangle.Top + ((content_rect.Height - text_size.Height) / 2) - 1; + textRectangle.Size = text_size; + + // Image is dependent on ImageAlign + if (image == null) + return; + + int image_x = button.PaddingClientRectangle.Left; + int image_y = button.PaddingClientRectangle.Top; + int image_height = image.Height; + int image_width = image.Width; + + switch (button.ImageAlign) + { + case System.Drawing.ContentAlignment.TopLeft: + image_x += 5; + image_y += 5; + break; + case System.Drawing.ContentAlignment.TopCenter: + image_x += (content_rect.Width - image_width) / 2; + image_y += 5; + break; + case System.Drawing.ContentAlignment.TopRight: + image_x += content_rect.Width - image_width - 5; + image_y += 5; + break; + case System.Drawing.ContentAlignment.MiddleLeft: + image_x += 5; + image_y += (content_rect.Height - image_height) / 2; + break; + case System.Drawing.ContentAlignment.MiddleCenter: + image_x += (content_rect.Width - image_width) / 2; + image_y += (content_rect.Height - image_height) / 2; + break; + case System.Drawing.ContentAlignment.MiddleRight: + image_x += content_rect.Width - image_width - 4; + image_y += (content_rect.Height - image_height) / 2; + break; + case System.Drawing.ContentAlignment.BottomLeft: + image_x += 5; + image_y += content_rect.Height - image_height - 4; + break; + case System.Drawing.ContentAlignment.BottomCenter: + image_x += (content_rect.Width - image_width) / 2; + image_y += content_rect.Height - image_height - 4; + break; + case System.Drawing.ContentAlignment.BottomRight: + image_x += content_rect.Width - image_width - 4; + image_y += content_rect.Height - image_height - 4; + break; + default: + image_x += 5; + image_y += 5; + break; + } + + imageRectangle = new Rectangle(image_x + check_size, image_y, image_width, image_height); + break; + case TextImageRelation.ImageAboveText: + content_rect.Inflate(-4, -4); + LayoutTextAboveOrBelowImage(content_rect, false, text_size, image_size, button.TextAlign, button.ImageAlign, false, out textRectangle, out imageRectangle); + break; + case TextImageRelation.TextAboveImage: + content_rect.Inflate(-4, -4); + LayoutTextAboveOrBelowImage(content_rect, true, text_size, image_size, button.TextAlign, button.ImageAlign, false, out textRectangle, out imageRectangle); + break; + case TextImageRelation.ImageBeforeText: + content_rect.Inflate(-4, -4); + LayoutTextBeforeOrAfterImage(content_rect, false, text_size, image_size, button.TextAlign, button.ImageAlign, out textRectangle, out imageRectangle); + break; + case TextImageRelation.TextBeforeImage: + content_rect.Inflate(-4, -4); + LayoutTextBeforeOrAfterImage(content_rect, true, text_size, image_size, button.TextAlign, button.ImageAlign, out textRectangle, out imageRectangle); + break; + } + } + + public override Size CalculateCheckBoxAutoSize(CheckBox checkBox) + { + Size ret_size = Size.Empty; + Size text_size = TextRenderer.MeasureTextInternal(checkBox.Text, checkBox.Font, checkBox.UseCompatibleTextRendering); + Size image_size = checkBox.Image == null ? Size.Empty : checkBox.Image.Size; + + // Pad the text size + if (checkBox.Text.Length != 0) + { + text_size.Height += 4; + text_size.Width += 4; + } + + switch (checkBox.TextImageRelation) + { + case TextImageRelation.Overlay: + ret_size.Height = Math.Max(checkBox.Text.Length == 0 ? 0 : text_size.Height, image_size.Height); + ret_size.Width = Math.Max(text_size.Width, image_size.Width); + break; + case TextImageRelation.ImageAboveText: + case TextImageRelation.TextAboveImage: + ret_size.Height = text_size.Height + image_size.Height; + ret_size.Width = Math.Max(text_size.Width, image_size.Width); + break; + case TextImageRelation.ImageBeforeText: + case TextImageRelation.TextBeforeImage: + ret_size.Height = Math.Max(text_size.Height, image_size.Height); + ret_size.Width = text_size.Width + image_size.Width; + break; + } + + // Pad the result + ret_size.Height += (checkBox.Padding.Vertical); + ret_size.Width += (checkBox.Padding.Horizontal) + 15; + + // There seems to be a minimum height + if (ret_size.Height == checkBox.Padding.Vertical) + ret_size.Height += 14; + + return ret_size; + } + + public override void DrawCheckBox(Graphics dc, Rectangle clip_area, CheckBox checkbox) + { + StringFormat text_format; + Rectangle client_rectangle; + Rectangle text_rectangle; + Rectangle checkbox_rectangle; + int checkmark_size = CheckSize; + int checkmark_space = 4; + + client_rectangle = checkbox.ClientRectangle; + text_rectangle = client_rectangle; + checkbox_rectangle = new Rectangle(text_rectangle.X, text_rectangle.Y, checkmark_size, checkmark_size); + + text_format = new StringFormat(); + text_format.Alignment = StringAlignment.Near; + text_format.LineAlignment = StringAlignment.Center; + if (checkbox.ShowKeyboardCuesInternal) + text_format.HotkeyPrefix = HotkeyPrefix.Show; + else + text_format.HotkeyPrefix = HotkeyPrefix.Hide; + + /* Calculate the position of text and checkbox rectangle */ + if (checkbox.appearance != Appearance.Button) + { + switch (checkbox.check_alignment) + { + case ContentAlignment.BottomCenter: + { + checkbox_rectangle.X = (client_rectangle.Right - client_rectangle.Left) / 2 - checkmark_size / 2; + checkbox_rectangle.Y = client_rectangle.Bottom - checkmark_size; + text_rectangle.X = client_rectangle.X; + text_rectangle.Width = client_rectangle.Width; + text_rectangle.Height = client_rectangle.Height - checkbox_rectangle.Y - checkmark_space; + break; + } + + case ContentAlignment.BottomLeft: + { + checkbox_rectangle.X = client_rectangle.Left; + checkbox_rectangle.Y = client_rectangle.Bottom - checkmark_size; + text_rectangle.X = client_rectangle.X + checkmark_size + checkmark_space; + text_rectangle.Width = client_rectangle.Width - checkmark_size - checkmark_space; + break; + } + + case ContentAlignment.BottomRight: + { + checkbox_rectangle.X = client_rectangle.Right - checkmark_size; + checkbox_rectangle.Y = client_rectangle.Bottom - checkmark_size; + text_rectangle.X = client_rectangle.X; + text_rectangle.Width = client_rectangle.Width - checkmark_size - checkmark_space; + break; + } + + case ContentAlignment.MiddleCenter: + { + checkbox_rectangle.X = (client_rectangle.Right - client_rectangle.Left) / 2 - checkmark_size / 2; + checkbox_rectangle.Y = (client_rectangle.Bottom - client_rectangle.Top) / 2 - checkmark_size / 2; + text_rectangle.X = client_rectangle.X; + text_rectangle.Width = client_rectangle.Width; + break; + } + + default: + case ContentAlignment.MiddleLeft: + { + checkbox_rectangle.X = client_rectangle.Left; + checkbox_rectangle.Y = (client_rectangle.Bottom - client_rectangle.Top) / 2 - checkmark_size / 2; + text_rectangle.X = client_rectangle.X + checkmark_size + checkmark_space; + text_rectangle.Width = client_rectangle.Width - checkmark_size - checkmark_space; + break; + } + + case ContentAlignment.MiddleRight: + { + checkbox_rectangle.X = client_rectangle.Right - checkmark_size; + checkbox_rectangle.Y = (client_rectangle.Bottom - client_rectangle.Top) / 2 - checkmark_size / 2; + text_rectangle.X = client_rectangle.X; + text_rectangle.Width = client_rectangle.Width - checkmark_size - checkmark_space; + break; + } + + case ContentAlignment.TopCenter: + { + checkbox_rectangle.X = (client_rectangle.Right - client_rectangle.Left) / 2 - checkmark_size / 2; + checkbox_rectangle.Y = client_rectangle.Top; + text_rectangle.X = client_rectangle.X; + text_rectangle.Width = client_rectangle.Width; + text_rectangle.Y = checkmark_size + checkmark_space; + text_rectangle.Height = client_rectangle.Height - checkmark_size - checkmark_space; + break; + } + + case ContentAlignment.TopLeft: + { + checkbox_rectangle.X = client_rectangle.Left; + text_rectangle.X = client_rectangle.X + checkmark_size + checkmark_space; + text_rectangle.Width = client_rectangle.Width - checkmark_size - checkmark_space; + break; + } + + case ContentAlignment.TopRight: + { + checkbox_rectangle.X = client_rectangle.Right - checkmark_size; + text_rectangle.X = client_rectangle.X; + text_rectangle.Width = client_rectangle.Width - checkmark_size - checkmark_space; + break; + } + } + } + else + { + text_rectangle.X = client_rectangle.X; + text_rectangle.Width = client_rectangle.Width; + } + + /* Set the horizontal alignment of our text */ + switch (checkbox.text_alignment) + { + case ContentAlignment.BottomLeft: + case ContentAlignment.MiddleLeft: + case ContentAlignment.TopLeft: + { + text_format.Alignment = StringAlignment.Near; + break; + } + + case ContentAlignment.BottomCenter: + case ContentAlignment.MiddleCenter: + case ContentAlignment.TopCenter: + { + text_format.Alignment = StringAlignment.Center; + break; + } + + case ContentAlignment.BottomRight: + case ContentAlignment.MiddleRight: + case ContentAlignment.TopRight: + { + text_format.Alignment = StringAlignment.Far; + break; + } + } + + /* Set the vertical alignment of our text */ + switch (checkbox.text_alignment) + { + case ContentAlignment.TopLeft: + case ContentAlignment.TopCenter: + case ContentAlignment.TopRight: + { + text_format.LineAlignment = StringAlignment.Near; + break; + } + + case ContentAlignment.BottomLeft: + case ContentAlignment.BottomCenter: + case ContentAlignment.BottomRight: + { + text_format.LineAlignment = StringAlignment.Far; + break; + } + + case ContentAlignment.MiddleLeft: + case ContentAlignment.MiddleCenter: + case ContentAlignment.MiddleRight: + { + text_format.LineAlignment = StringAlignment.Center; + break; + } + } + + ButtonState state = ButtonState.Normal; + if (checkbox.FlatStyle == FlatStyle.Flat) + { + state |= ButtonState.Flat; + } + + if (checkbox.Checked) + { + state |= ButtonState.Checked; + } + + if (checkbox.ThreeState && (checkbox.CheckState == CheckState.Indeterminate)) + { + state |= ButtonState.Checked; + state |= ButtonState.Pushed; + } + + // finally make sure the pushed and inavtive states are rendered + if (!checkbox.Enabled) + { + state |= ButtonState.Inactive; + } + else if (checkbox.is_pressed) + { + state |= ButtonState.Pushed; + } + + // Start drawing + + CheckBox_DrawCheckBox(dc, checkbox, state, checkbox_rectangle); + + if ((checkbox.image != null) || (checkbox.image_list != null)) + ButtonBase_DrawImage(checkbox, dc); + + CheckBox_DrawText(checkbox, text_rectangle, dc, text_format); + + if (checkbox.Focused && checkbox.Enabled && checkbox.appearance != Appearance.Button && checkbox.Text != String.Empty && checkbox.ShowFocusCues) + { + SizeF text_size = dc.MeasureString(checkbox.Text, checkbox.Font); + + Rectangle focus_rect = Rectangle.Empty; + focus_rect.X = text_rectangle.X; + focus_rect.Y = (int)((text_rectangle.Height - text_size.Height) / 2); + focus_rect.Size = text_size.ToSize(); + CheckBox_DrawFocus(checkbox, dc, focus_rect); + } + + text_format.Dispose(); + } + + protected virtual void CheckBox_DrawCheckBox(Graphics dc, CheckBox checkbox, ButtonState state, Rectangle checkbox_rectangle) + { + Brush brush = checkbox.BackColor.ToArgb() == ColorControl.ToArgb() ? SystemBrushes.Control : ResPool.GetSolidBrush(checkbox.BackColor); + dc.FillRectangle(brush, checkbox.ClientRectangle); + // render as per normal button + if (checkbox.appearance == Appearance.Button) + { + ButtonBase_DrawButton(checkbox, dc); + + if ((checkbox.Focused) && checkbox.Enabled) + ButtonBase_DrawFocus(checkbox, dc); + } + else + { + // establish if we are rendering a flat style of some sort + if (checkbox.FlatStyle == FlatStyle.Flat || checkbox.FlatStyle == FlatStyle.Popup) + { + DrawFlatStyleCheckBox(dc, checkbox_rectangle, checkbox); + } + else + { + CPDrawCheckBox(dc, checkbox_rectangle, state); + } + } + } + + protected virtual void CheckBox_DrawText(CheckBox checkbox, Rectangle text_rectangle, Graphics dc, StringFormat text_format) + { + DrawCheckBox_and_RadioButtonText(checkbox, text_rectangle, dc, + text_format, checkbox.Appearance, checkbox.Checked); + } + + protected virtual void CheckBox_DrawFocus(CheckBox checkbox, Graphics dc, Rectangle text_rectangle) + { + DrawInnerFocusRectangle(dc, text_rectangle, checkbox.BackColor); + } + + // renders a checkBox with the Flat and Popup FlatStyle + protected virtual void DrawFlatStyleCheckBox(Graphics graphics, Rectangle rectangle, CheckBox checkbox) + { + Pen pen; + Rectangle rect; + Rectangle checkbox_rectangle; + Rectangle fill_rectangle; + int lineWidth; + int Scale; + + // set up our rectangles first + if (checkbox.FlatStyle == FlatStyle.Popup && checkbox.is_entered) + { + // clip one pixel from bottom right for non popup rendered checkboxes + checkbox_rectangle = new Rectangle(rectangle.X, rectangle.Y, Math.Max(rectangle.Width - 1, 0), Math.Max(rectangle.Height - 1, 0)); + fill_rectangle = new Rectangle(checkbox_rectangle.X + 1, checkbox_rectangle.Y + 1, Math.Max(checkbox_rectangle.Width - 3, 0), Math.Max(checkbox_rectangle.Height - 3, 0)); + } + else + { + // clip two pixels from bottom right for non popup rendered checkboxes + checkbox_rectangle = new Rectangle(rectangle.X, rectangle.Y, Math.Max(rectangle.Width - 2, 0), Math.Max(rectangle.Height - 2, 0)); + fill_rectangle = new Rectangle(checkbox_rectangle.X + 1, checkbox_rectangle.Y + 1, Math.Max(checkbox_rectangle.Width - 2, 0), Math.Max(checkbox_rectangle.Height - 2, 0)); + } + + + // if disabled render in disabled state + if (checkbox.Enabled) + { + // process the state of the checkbox + if (checkbox.is_entered || checkbox.Capture) + { + // decide on which background color to use + if (checkbox.FlatStyle == FlatStyle.Popup && checkbox.is_entered && checkbox.Capture) + { + graphics.FillRectangle(ResPool.GetSolidBrush(checkbox.BackColor), fill_rectangle); + } + else if (checkbox.FlatStyle == FlatStyle.Flat) + { + if (!checkbox.is_pressed) + { + graphics.FillRectangle(ResPool.GetSolidBrush(checkbox.BackColor), fill_rectangle); + } + else + graphics.FillRectangle(ResPool.GetSolidBrush(WidgetPaint.LightLight(checkbox.BackColor)), fill_rectangle); + } + else + { + // use regular window background color + graphics.FillRectangle(ResPool.GetSolidBrush(WidgetPaint.LightLight(checkbox.BackColor)), fill_rectangle); + } + + // render the outer border + if (checkbox.FlatStyle == FlatStyle.Flat) + { + WidgetPaint.DrawBorder(graphics, checkbox_rectangle, checkbox.ForeColor, ButtonBorderStyle.Solid); + } + else + { + // draw sunken effect + CPDrawBorder3D(graphics, checkbox_rectangle, Border3DStyle.SunkenInner, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom, checkbox.BackColor); + } + } + else + { + graphics.FillRectangle(ResPool.GetSolidBrush(WidgetPaint.LightLight(checkbox.BackColor)), fill_rectangle); + + if (checkbox.FlatStyle == FlatStyle.Flat) + { + WidgetPaint.DrawBorder(graphics, checkbox_rectangle, checkbox.ForeColor, ButtonBorderStyle.Solid); + } + else + { + // draw the outer border + WidgetPaint.DrawBorder(graphics, checkbox_rectangle, WidgetPaint.DarkDark(checkbox.BackColor), ButtonBorderStyle.Solid); + } + } + } + else + { + if (checkbox.FlatStyle == FlatStyle.Popup) + { + graphics.FillRectangle(SystemBrushes.Control, fill_rectangle); + } + + // draw disabled state, + WidgetPaint.DrawBorder(graphics, checkbox_rectangle, ColorControlDark, ButtonBorderStyle.Solid); + } + + if (checkbox.Checked) + { + /* Need to draw a check-mark */ + + /* Make sure we've got at least a line width of 1 */ + lineWidth = Math.Max(3, fill_rectangle.Width / 3); + Scale = Math.Max(1, fill_rectangle.Width / 9); + + // flat style check box is rendered inside a rectangle shifted down by one + rect = new Rectangle(fill_rectangle.X, fill_rectangle.Y + 1, fill_rectangle.Width, fill_rectangle.Height); + if (checkbox.Enabled) + { + pen = ResPool.GetPen(checkbox.ForeColor); + } + else + { + pen = SystemPens.ControlDark; + } + + for (int i = 0; i < lineWidth; i++) + { + graphics.DrawLine(pen, rect.Left + lineWidth / 2, rect.Top + lineWidth + i, rect.Left + lineWidth / 2 + 2 * Scale, rect.Top + lineWidth + 2 * Scale + i); + graphics.DrawLine(pen, rect.Left + lineWidth / 2 + 2 * Scale, rect.Top + lineWidth + 2 * Scale + i, rect.Left + lineWidth / 2 + 6 * Scale, rect.Top + lineWidth - 2 * Scale + i); + } + } + } + + private void DrawCheckBox_and_RadioButtonText(ButtonBase button_base, Rectangle text_rectangle, Graphics dc, + StringFormat text_format, Appearance appearance, bool ischecked) + { + // offset the text if it's pressed and a button + if (appearance == Appearance.Button) + { + if (ischecked || (button_base.Capture && button_base.FlatStyle != FlatStyle.Flat)) + { + text_rectangle.X++; + text_rectangle.Y++; + } + + text_rectangle.Inflate(-4, -4); + } + + /* Place the text; to be compatible with Windows place it after the checkbox has been drawn */ + + // Windows seems to not wrap text in certain situations, this matches as close as I could get it + if ((float)(button_base.Font.Height * 1.5f) > text_rectangle.Height) + { + text_format.FormatFlags |= StringFormatFlags.NoWrap; + } + if (button_base.Enabled) + { + dc.DrawString(button_base.Text, button_base.Font, ResPool.GetSolidBrush(button_base.ForeColor), text_rectangle, text_format); + } + else if (button_base.FlatStyle == FlatStyle.Flat || button_base.FlatStyle == FlatStyle.Popup) + { + dc.DrawString(button_base.Text, button_base.Font, SystemBrushes.ControlDarkDark, text_rectangle, text_format); + } + else + { + CPDrawStringDisabled(dc, button_base.Text, button_base.Font, button_base.BackColor, text_rectangle, text_format); + } + } + #endregion // CheckBox + + #region CheckedListBox + + public override void DrawCheckedListBoxItem(CheckedListBox ctrl, DrawItemEventArgs e) + { + Color back_color, fore_color; + Rectangle item_rect = e.Bounds; + ButtonState state; + + /* Draw checkbox */ + + if ((e.State & DrawItemState.Checked) == DrawItemState.Checked) + { + state = ButtonState.Checked; + if ((e.State & DrawItemState.Inactive) == DrawItemState.Inactive) + state |= ButtonState.Inactive; + } + else + state = ButtonState.Normal; + + if (ctrl.ThreeDCheckBoxes == false) + state |= ButtonState.Flat; + + Rectangle checkbox_rect = new Rectangle(2, (item_rect.Height - 11) / 2, CheckSize, CheckSize); + WidgetPaint.DrawCheckBox(e.Graphics, + item_rect.X + checkbox_rect.X, item_rect.Y + checkbox_rect.Y, + checkbox_rect.Width, checkbox_rect.Height, + state); + + item_rect.X += checkbox_rect.Right; + item_rect.Width -= checkbox_rect.Right; + + /* Draw text*/ + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) + { + back_color = ColorHighlight; + fore_color = ColorHighlightText; + } + else + { + back_color = e.BackColor; + fore_color = e.ForeColor; + } + + e.Graphics.FillRectangle(ResPool.GetSolidBrush + (back_color), item_rect); + + e.Graphics.DrawString(ctrl.GetItemText(ctrl.Items[e.Index]), e.Font, + ResPool.GetSolidBrush(fore_color), + item_rect, ctrl.StringFormat); + + if ((e.State & DrawItemState.Focus) == DrawItemState.Focus) + { + CPDrawFocusRectangle(e.Graphics, item_rect, + fore_color, back_color); + } + } + + #endregion // CheckedListBox + + #region ComboBox + public override void DrawComboBoxItem(ComboBox ctrl, DrawItemEventArgs e) + { + Color back_color, fore_color; + Rectangle text_draw = e.Bounds; + StringFormat string_format = new StringFormat(); + string_format.FormatFlags = StringFormatFlags.LineLimit; + + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) + { + back_color = ColorHighlight; + fore_color = ColorHighlightText; + } + else + { + back_color = e.BackColor; + fore_color = e.ForeColor; + } + + if (!ctrl.Enabled) + fore_color = ColorInactiveCaptionText; + + e.Graphics.FillRectangle(ResPool.GetSolidBrush(back_color), e.Bounds); + + if (e.Index != -1) + { + e.Graphics.DrawString(ctrl.GetItemText(ctrl.Items[e.Index]), e.Font, + ResPool.GetSolidBrush(fore_color), + text_draw, string_format); + } + + if ((e.State & DrawItemState.Focus) == DrawItemState.Focus) + { + CPDrawFocusRectangle(e.Graphics, e.Bounds, fore_color, back_color); + } + + string_format.Dispose(); + } + + public override void DrawFlatStyleComboButton(Graphics graphics, Rectangle rectangle, ButtonState state) + { + Point[] arrow = new Point[3]; + Point P1; + Point P2; + Point P3; + int centerX; + int centerY; + int shiftX; + int shiftY; + Rectangle rect; + + rect = new Rectangle(rectangle.X + rectangle.Width / 4, rectangle.Y + rectangle.Height / 4, rectangle.Width / 2, rectangle.Height / 2); + centerX = rect.Left + rect.Width / 2; + centerY = rect.Top + rect.Height / 2; + shiftX = Math.Max(1, rect.Width / 8); + shiftY = Math.Max(1, rect.Height / 8); + + if ((state & ButtonState.Pushed) != 0) + { + shiftX++; + shiftY++; + } + + rect.Y -= shiftY; + centerY -= shiftY; + P1 = new Point(rect.Left + 1, centerY); + P2 = new Point(rect.Right - 1, centerY); + P3 = new Point(centerX, rect.Bottom - 1); + + arrow[0] = P1; + arrow[1] = P2; + arrow[2] = P3; + + /* Draw the arrow */ + if ((state & ButtonState.Inactive) != 0) + { + /* Move away from the shadow */ + arrow[0].X += 1; arrow[0].Y += 1; + arrow[1].X += 1; arrow[1].Y += 1; + arrow[2].X += 1; arrow[2].Y += 1; + + graphics.FillPolygon(SystemBrushes.ControlLightLight, arrow, FillMode.Winding); + + arrow[0] = P1; + arrow[1] = P2; + arrow[2] = P3; + + graphics.FillPolygon(SystemBrushes.ControlDark, arrow, FillMode.Winding); + } + else + { + graphics.FillPolygon(SystemBrushes.ControlText, arrow, FillMode.Winding); + } + } + public override void ComboBoxDrawNormalDropDownButton(ComboBox comboBox, Graphics g, Rectangle clippingArea, Rectangle area, ButtonState state) + { + CPDrawComboButton(g, area, state); + } + public override bool ComboBoxNormalDropDownButtonHasTransparentBackground(ComboBox comboBox, ButtonState state) + { + return true; + } + public override bool ComboBoxDropDownButtonHasHotElementStyle(ComboBox comboBox) + { + return false; + } + public override void ComboBoxDrawBackground(ComboBox comboBox, Graphics g, Rectangle clippingArea, FlatStyle style) + { + if (!comboBox.Enabled) + g.FillRectangle(ResPool.GetSolidBrush(ColorControl), comboBox.ClientRectangle); + + if (comboBox.DropDownStyle == ComboBoxStyle.Simple) + g.FillRectangle(ResPool.GetSolidBrush(comboBox.Parent.BackColor), comboBox.ClientRectangle); + + if (style == FlatStyle.Popup && (comboBox.Entered || comboBox.Focused)) + { + Rectangle area = comboBox.TextArea; + area.Height -= 1; + area.Width -= 1; + g.DrawRectangle(ResPool.GetPen(SystemColors.ControlDark), area); + g.DrawLine(ResPool.GetPen(SystemColors.ControlDark), comboBox.ButtonArea.X - 1, comboBox.ButtonArea.Top, comboBox.ButtonArea.X - 1, comboBox.ButtonArea.Bottom); + } + bool is_flat = style == FlatStyle.Flat || style == FlatStyle.Popup; + if (!is_flat && clippingArea.IntersectsWith(comboBox.TextArea)) + WidgetPaint.DrawBorder3D(g, comboBox.TextArea, Border3DStyle.Sunken); + } + public override bool CombBoxBackgroundHasHotElementStyle(ComboBox comboBox) + { + return false; + } + #endregion ComboBox + + /* FIXME: NEIN. I will NOT port DataGrids over. + #region Datagrid + public override int DataGridPreferredColumnWidth { get { return 75;} } + public override int DataGridMinimumColumnCheckBoxHeight { get { return 16;} } + public override int DataGridMinimumColumnCheckBoxWidth { get { return 16;} } + public override Color DataGridAlternatingBackColor { get { return ColorWindow;} } + public override Color DataGridBackColor { get { return ColorWindow;} } + public override Color DataGridBackgroundColor { get { return ColorAppWorkspace;} } + public override Color DataGridCaptionBackColor { get { return ColorActiveCaption;} } + public override Color DataGridCaptionForeColor { get { return ColorActiveCaptionText;} } + public override Color DataGridGridLineColor { get { return ColorControl;} } + public override Color DataGridHeaderBackColor { get { return ColorControl;} } + public override Color DataGridHeaderForeColor { get { return ColorControlText;} } + public override Color DataGridLinkColor { get { return ColorHotTrack;} } + public override Color DataGridLinkHoverColor { get { return ColorHotTrack;} } + public override Color DataGridParentRowsBackColor { get { return ColorControl;} } + public override Color DataGridParentRowsForeColor { get { return ColorWindowText;} } + public override Color DataGridSelectionBackColor { get { return ColorActiveCaption;} } + public override Color DataGridSelectionForeColor { get { return ColorActiveCaptionText;} } + + public override void DataGridPaint (PaintEventArgs pe, DataGrid grid) + { + DataGridPaintCaption (pe.Graphics, pe.ClipRectangle, grid); + DataGridPaintParentRows (pe.Graphics, pe.ClipRectangle, grid); + DataGridPaintColumnHeaders (pe.Graphics, pe.ClipRectangle, grid); + DataGridPaintRows (pe.Graphics, grid.cells_area, pe.ClipRectangle, grid); + + // Paint scrollBar corner + if (grid.VScrollBar.Visible && grid.HScrollBar.Visible) { + + Rectangle corner = new Rectangle (grid.ClientRectangle.X + grid.ClientRectangle.Width - grid.VScrollBar.Width, + grid.ClientRectangle.Y + grid.ClientRectangle.Height - grid.HScrollBar.Height, + grid.VScrollBar.Width, grid.HScrollBar.Height); + + if (pe.ClipRectangle.IntersectsWith (corner)) { + pe.Graphics.FillRectangle (ResPool.GetSolidBrush (grid.ParentRowsBackColor), + corner); + } + } + } + + public override void DataGridPaintCaption (Graphics g, Rectangle clip, DataGrid grid) + { + Rectangle bounds = clip; + bounds.Intersect (grid.caption_area); + + // Background + g.FillRectangle (ResPool.GetSolidBrush (grid.CaptionBackColor), bounds); + + // Bottom line + g.DrawLine (ResPool.GetPen (grid.CurrentTableStyle.CurrentHeaderForeColor), + bounds.X, bounds.Y + bounds.Height -1, + bounds.X + bounds.Width, bounds.Y + bounds.Height -1); + + // Caption text + if (grid.CaptionText != String.Empty) { + Rectangle text_rect = grid.caption_area; + text_rect.Y += text_rect.Height / 2 - grid.CaptionFont.Height / 2; + text_rect.Height = grid.CaptionFont.Height; + + g.DrawString (grid.CaptionText, grid.CaptionFont, + ResPool.GetSolidBrush (grid.CaptionForeColor), + text_rect); + } + + // Back button + if (bounds.IntersectsWith (grid.back_button_rect)) { + g.DrawImage (grid.back_button_image, grid.back_button_rect); + if (grid.back_button_mouseover) { + CPDrawBorder3D (g, grid.back_button_rect, grid.back_button_active ? Border3DStyle.Sunken : Border3DStyle.Raised, all_sides); + } + } + + // Rows button + if (bounds.IntersectsWith (grid.parent_rows_button_rect)) { + g.DrawImage (grid.parent_rows_button_image, grid.parent_rows_button_rect); + if (grid.parent_rows_button_mouseover) { + CPDrawBorder3D (g, grid.parent_rows_button_rect, grid.parent_rows_button_active ? Border3DStyle.Sunken : Border3DStyle.Raised, all_sides); + } + } + } + + public override void DataGridPaintColumnHeaders (Graphics g, Rectangle clip, DataGrid grid) + { + if (!grid.CurrentTableStyle.ColumnHeadersVisible) + return; + + Rectangle columns_area = grid.column_headers_area; + + // Paint corner shared between row and column header + if (grid.CurrentTableStyle.CurrentRowHeadersVisible) { + Rectangle rect_bloc = grid.column_headers_area; + rect_bloc.Width = grid.RowHeaderWidth; + if (clip.IntersectsWith (rect_bloc)) { + if (grid.FlatMode) + g.FillRectangle (ResPool.GetSolidBrush (grid.CurrentTableStyle.CurrentHeaderBackColor), rect_bloc); + else + CPDrawBorder3D (g, rect_bloc, Border3DStyle.RaisedInner, + Border3DSide.Left | Border3DSide.Right | + Border3DSide.Top | Border3DSide.Bottom | Border3DSide.Middle, + grid.CurrentTableStyle.CurrentHeaderBackColor); + } + + columns_area.X += grid.RowHeaderWidth; + columns_area.Width -= grid.RowHeaderWidth; + } + + // Set column painting + Rectangle rect_columnhdr = new Rectangle (); + int col_pixel; + Region current_clip; + Region prev_clip = g.Clip; + rect_columnhdr.Y = columns_area.Y; + rect_columnhdr.Height = columns_area.Height; + + int column_cnt = grid.FirstVisibleColumn + grid.VisibleColumnCount; + for (int column = grid.FirstVisibleColumn; column < column_cnt; column++) { + if (grid.CurrentTableStyle.GridColumnStyles[column].bound == false) + continue; + + col_pixel = grid.GetColumnStartingPixel (column); + rect_columnhdr.X = columns_area.X + col_pixel - grid.HorizPixelOffset; + rect_columnhdr.Width = grid.CurrentTableStyle.GridColumnStyles[column].Width; + + if (clip.IntersectsWith (rect_columnhdr) == false) + continue; + + current_clip = new Region (rect_columnhdr); + current_clip.Intersect (columns_area); + current_clip.Intersect (prev_clip); + g.Clip = current_clip; + + DataGridPaintColumnHeader (g, rect_columnhdr, grid, column); + + current_clip.Dispose (); + } + + g.Clip = prev_clip; + + Rectangle not_usedarea = grid.column_headers_area; + not_usedarea.X = (column_cnt == 0) ? grid.RowHeaderWidth : rect_columnhdr.X + rect_columnhdr.Width; + not_usedarea.Width = grid.ClientRectangle.X + grid.ClientRectangle.Width - not_usedarea.X; + g.FillRectangle (ResPool.GetSolidBrush (grid.BackgroundColor), not_usedarea); + } + + public override void DataGridPaintColumnHeader (Graphics g, Rectangle bounds, DataGrid grid, int col) + { + // Background + g.FillRectangle (ResPool.GetSolidBrush (grid.CurrentTableStyle.HeaderBackColor), bounds); + + // Paint Borders + if (!grid.FlatMode) { + g.DrawLine (ResPool.GetPen (ColorControlLightLight), + bounds.X, bounds.Y, bounds.X + bounds.Width, bounds.Y); + + if (col == 0) { + g.DrawLine (ResPool.GetPen (ColorControlLightLight), + bounds.X, bounds.Y, bounds.X, bounds.Y + bounds.Height); + } else { + g.DrawLine (ResPool.GetPen (ColorControlLightLight), + bounds.X, bounds.Y + 2, bounds.X, bounds.Y + bounds.Height - 3); + } + + if (col == (grid.VisibleColumnCount -1)) { + g.DrawLine (ResPool.GetPen (ColorControlDark), + bounds.X + bounds.Width - 1, bounds.Y, + bounds.X + bounds.Width - 1, bounds.Y + bounds.Height); + } else { + g.DrawLine (ResPool.GetPen (ColorControlDark), + bounds.X + bounds.Width - 1, bounds.Y + 2, + bounds.X + bounds.Width - 1, bounds.Y + bounds.Height - 3); + } + + g.DrawLine (ResPool.GetPen (ColorControlDark), + bounds.X, bounds.Y + bounds.Height - 1, + bounds.X + bounds.Width, bounds.Y + bounds.Height - 1); + } + + bounds.X += 2; + bounds.Width -= 2; + + DataGridColumnStyle style = grid.CurrentTableStyle.GridColumnStyles[col]; + + if (style.ArrowDrawingMode != DataGridColumnStyle.ArrowDrawing.No) + bounds.Width -= 16; + + // Caption + StringFormat format = new StringFormat (); + format.FormatFlags |= StringFormatFlags.NoWrap; + format.LineAlignment = StringAlignment.Center; + format.Trimming = StringTrimming.Character; + + g.DrawString (style.HeaderText, grid.CurrentTableStyle.HeaderFont, + ResPool.GetSolidBrush (grid.CurrentTableStyle.CurrentHeaderForeColor), + bounds, format); + + // Arrow (6 x 6) + if (style.ArrowDrawingMode != DataGridColumnStyle.ArrowDrawing.No) { + Point pnt = new Point (bounds.X + bounds.Width + 4, bounds.Y + ((bounds.Height - 6)/2)); + + if (style.ArrowDrawingMode == DataGridColumnStyle.ArrowDrawing.Ascending) { + g.DrawLine (SystemPens.ControlLightLight, pnt.X + 6, pnt.Y + 6, pnt.X + 3, pnt.Y); + g.DrawLine (SystemPens.ControlDark, pnt.X, pnt.Y + 6, pnt.X + 6, pnt.Y + 6); + g.DrawLine (SystemPens.ControlDark, pnt.X, pnt.Y + 6, pnt.X + 3, pnt.Y); + } else { + g.DrawLine (SystemPens.ControlLightLight, pnt.X + 6, pnt.Y, pnt.X + 3, pnt.Y + 6); + g.DrawLine (SystemPens.ControlDark, pnt.X, pnt.Y, pnt.X + 6, pnt.Y); + g.DrawLine (SystemPens.ControlDark, pnt.X, pnt.Y, pnt.X + 3, pnt.Y + 6); + } + } + } + + public override void DataGridPaintParentRows (Graphics g, Rectangle clip, DataGrid grid) + { + Rectangle rect_row = new Rectangle (); + + rect_row.X = grid.ParentRowsArea.X; + rect_row.Width = grid.ParentRowsArea.Width; + rect_row.Height = (grid.CaptionFont.Height + 3); + + object[] parentRows = grid.data_source_stack.ToArray(); + + Region current_clip; + Region prev_clip = g.Clip; + for (int row = 0; row < parentRows.Length; row++) { + rect_row.Y = grid.ParentRowsArea.Y + row * rect_row.Height; + + if (clip.IntersectsWith (rect_row) == false) + continue; + + current_clip = new Region (rect_row); + current_clip.Intersect (prev_clip); + g.Clip = current_clip; + + DataGridPaintParentRow (g, rect_row, (DataGridDataSource)parentRows[parentRows.Length - row - 1], grid); + + current_clip.Dispose (); + } + + g.Clip = prev_clip; + } + + public override void DataGridPaintParentRow (Graphics g, Rectangle bounds, DataGridDataSource row, DataGrid grid) + { + // Background + g.FillRectangle (ResPool.GetSolidBrush (grid.ParentRowsBackColor), + bounds); + + Font bold_font = new Font (grid.Font.FontFamily, grid.Font.Size, grid.Font.Style | FontStyle.Bold); + // set up some standard string formating variables + StringFormat text_format = new StringFormat(); + text_format.LineAlignment = StringAlignment.Center; + text_format.Alignment = StringAlignment.Near; + + string table_name = ""; + if (row.view is DataRowView) + table_name = ((ITypedList)((DataRowView)row.view).DataView).GetListName (null) + ": "; + // XXX else? + + Rectangle text_rect; + Size text_size; + + text_size = g.MeasureString (table_name, bold_font).ToSize(); + text_rect = new Rectangle(new Point(bounds.X + 3, bounds.Y + bounds.Height - text_size.Height), text_size); + + g.DrawString (table_name, + bold_font, ResPool.GetSolidBrush (grid.ParentRowsForeColor), text_rect, text_format); + + foreach (PropertyDescriptor pd in ((ICustomTypeDescriptor)row.view).GetProperties()) { + if (typeof(IBindingList).IsAssignableFrom (pd.PropertyType)) + continue; + + text_rect.X += text_rect.Size.Width + 5; + + string text = String.Format ("{0}: {1}", + pd.Name, + pd.GetValue (row.view)); + + text_rect.Size = g.MeasureString (text, grid.Font).ToSize(); + text_rect.Y = bounds.Y + bounds.Height - text_rect.Height; // XXX + + g.DrawString (text, + grid.Font, ResPool.GetSolidBrush (grid.ParentRowsForeColor), text_rect, text_format); + } + + // Paint Borders + if (!grid.FlatMode) { + CPDrawBorder3D (g, bounds, Border3DStyle.RaisedInner, + Border3DSide.Left | Border3DSide.Right | + Border3DSide.Top | Border3DSide.Bottom); + } + } + + public override void DataGridPaintRowHeaderArrow (Graphics g, Rectangle bounds, DataGrid grid) + { + Point[] arrow = new Point[3]; + Point P1, P2, P3; + int centerX, centerY, shiftX; + Rectangle rect; + + rect = new Rectangle (bounds.X + bounds.Width /4, + bounds.Y + bounds.Height/4, bounds.Width / 2, bounds.Height / 2); + + centerX = rect.Left + rect.Width / 2; + centerY = rect.Top + rect.Height / 2; + shiftX = Math.Max (1, rect.Width / 8); + rect.X -= shiftX; + centerX -= shiftX; + P1 = new Point (centerX, rect.Top - 1); + P2 = new Point (centerX, rect.Bottom); + P3 = new Point (rect.Right, centerY); + arrow[0] = P1; + arrow[1] = P2; + arrow[2] = P3; + + g.FillPolygon (ResPool.GetSolidBrush + (grid.CurrentTableStyle.CurrentHeaderForeColor), arrow, FillMode.Winding); + } + + public override void DataGridPaintRowHeaderStar (Graphics g, Rectangle bounds, DataGrid grid) + { + int x = bounds.X + 4; + int y = bounds.Y + 3; + Pen pen = ResPool.GetPen (grid.CurrentTableStyle.CurrentHeaderForeColor); + + g.DrawLine (pen, x + 4, y, x + 4, y + 8); + g.DrawLine (pen, x, y + 4, x + 8, y + 4); + g.DrawLine (pen, x + 1, y + 1, x + 7, y + 7); + g.DrawLine (pen, x + 7, y + 1, x + 1, y + 7); + } + + public override void DataGridPaintRowHeader (Graphics g, Rectangle bounds, int row, DataGrid grid) + { + bool is_add_row = grid.ShowEditRow && row == grid.DataGridRows.Length - 1; + bool is_current_row = row == grid.CurrentCell.RowNumber; + + // Background + g.FillRectangle (ResPool.GetSolidBrush (grid.CurrentTableStyle.CurrentHeaderBackColor), bounds); + + // Draw arrow + if (is_current_row) { + if (grid.IsChanging) { + g.DrawString ("..", grid.Font, + ResPool.GetSolidBrush (grid.CurrentTableStyle.CurrentHeaderForeColor), + bounds); + } else { + Rectangle rect = new Rectangle (bounds.X - 2, bounds.Y, 18, 18); + DataGridPaintRowHeaderArrow (g, rect, grid); + } + } + else if (is_add_row) { + DataGridPaintRowHeaderStar (g, bounds, grid); + } + + if (!grid.FlatMode && !is_add_row) { + CPDrawBorder3D (g, bounds, Border3DStyle.RaisedInner, + Border3DSide.Left | Border3DSide.Right | + Border3DSide.Top | Border3DSide.Bottom); + } + } + + public override void DataGridPaintRows (Graphics g, Rectangle cells, Rectangle clip, DataGrid grid) + { + Rectangle rect_row = new Rectangle (); + Rectangle not_usedarea = new Rectangle (); + + int rowcnt = grid.VisibleRowCount; + + bool showing_add_row = false; + + if (grid.RowsCount < grid.DataGridRows.Length) { + /* the table has an add row + + if (grid.FirstVisibleRow + grid.VisibleRowCount >= grid.DataGridRows.Length) { + showing_add_row = true; + } + } + + rect_row.Width = cells.Width + grid.RowHeadersArea.Width; + for (int r = 0; r < rowcnt; r++) { + int row = grid.FirstVisibleRow + r; + if (row == grid.DataGridRows.Length - 1) + rect_row.Height = grid.DataGridRows[row].Height; + else + rect_row.Height = grid.DataGridRows[row + 1].VerticalOffset - grid.DataGridRows[row].VerticalOffset; + rect_row.Y = cells.Y + grid.DataGridRows[row].VerticalOffset - grid.DataGridRows[grid.FirstVisibleRow].VerticalOffset; + if (clip.IntersectsWith (rect_row)) { + if (grid.CurrentTableStyle.HasRelations + && !(showing_add_row && row == grid.DataGridRows.Length - 1)) + DataGridPaintRelationRow (g, row, rect_row, false, clip, grid); + else + DataGridPaintRow (g, row, rect_row, showing_add_row && row == grid.DataGridRows.Length - 1, clip, grid); + } + } + + not_usedarea.X = 0; + // the rowcnt == 0 check is needed because + // otherwise we'd draw over the caption on + // empty datasources (since rect_row would be + // Empty) + if (rowcnt == 0) + not_usedarea.Y = cells.Y; + else + not_usedarea.Y = rect_row.Y + rect_row.Height; + not_usedarea.Height = cells.Y + cells.Height - rect_row.Y - rect_row.Height; + not_usedarea.Width = cells.Width + grid.RowHeadersArea.Width; + + g.FillRectangle (ResPool.GetSolidBrush (grid.BackgroundColor), not_usedarea); + } + + public override void DataGridPaintRelationRow (Graphics g, int row, Rectangle row_rect, bool is_newrow, + Rectangle clip, DataGrid grid) + { + Rectangle rect_header; + Rectangle icon_bounds = new Rectangle (); + Pen pen = ThemeEngine.Current.ResPool.GetPen (grid.CurrentTableStyle.ForeColor); + + /* paint the header if it's visible and intersects the clip + if (grid.CurrentTableStyle.CurrentRowHeadersVisible) { + rect_header = row_rect; + rect_header.Width = grid.RowHeaderWidth; + row_rect.X += grid.RowHeaderWidth; + if (clip.IntersectsWith (rect_header)) { + DataGridPaintRowHeader (g, rect_header, row, grid); + } + + icon_bounds = rect_header; + icon_bounds.X += icon_bounds.Width / 2; + icon_bounds.Y += 3; + icon_bounds.Width = 8; + icon_bounds.Height = 8; + + g.DrawRectangle (pen, icon_bounds); + + /* the - part of the icon + g.DrawLine (pen, + icon_bounds.X + 2, icon_bounds.Y + icon_bounds.Height / 2, + icon_bounds.X + icon_bounds.Width - 2, icon_bounds.Y + icon_bounds.Height / 2); + + if (!grid.IsExpanded (row)) { + /* the | part of the icon + g.DrawLine (pen, + icon_bounds.X + icon_bounds.Width / 2, icon_bounds.Y + 2, + icon_bounds.X + icon_bounds.Width / 2, icon_bounds.Y + icon_bounds.Height - 2); + } + } + + Rectangle nested_rect = row_rect; + + if (grid.DataGridRows[row].IsExpanded) + nested_rect.Height -= grid.DataGridRows[row].RelationHeight; + + DataGridPaintRowContents (g, row, nested_rect, is_newrow, clip, grid); + + if (grid.DataGridRows[row].IsExpanded) { + // XXX we should create this in the + // datagrid and cache it for use by + // the theme instead of doing it each + // time through here + string[] relations = grid.CurrentTableStyle.Relations; + StringBuilder relation_builder = new StringBuilder (""); + + for (int i = 0; i < relations.Length; i ++) { + if (i > 0) + relation_builder.Append ("\n"); + + relation_builder.Append (relations[i]); + } + string relation_text = relation_builder.ToString (); + + StringFormat string_format = new StringFormat (); + string_format.FormatFlags |= StringFormatFlags.NoWrap; + + + //Region prev_clip = g.Clip; + //Region current_clip; + Rectangle rect_cell = row_rect; + + rect_cell.X = nested_rect.X + grid.GetColumnStartingPixel (grid.FirstVisibleColumn) - grid.HorizPixelOffset; + rect_cell.Y += nested_rect.Height; + rect_cell.Height = grid.DataGridRows[row].RelationHeight; + + rect_cell.Width = 0; + int column_cnt = grid.FirstVisibleColumn + grid.VisibleColumnCount; + for (int column = grid.FirstVisibleColumn; column < column_cnt; column++) { + if (grid.CurrentTableStyle.GridColumnStyles[column].bound == false) + continue; + rect_cell.Width += grid.CurrentTableStyle.GridColumnStyles[column].Width; + } + rect_cell.Width = Math.Max (rect_cell.Width, grid.DataGridRows[row].relation_area.Width); + + g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (grid.CurrentTableStyle.BackColor), + rect_cell); + + + /* draw the line leading from the +/- to the relation area + Rectangle outline = grid.DataGridRows[row].relation_area; + outline.Y = rect_cell.Y; + outline.Height --; + + g.DrawLine (pen, + icon_bounds.X + icon_bounds.Width / 2, icon_bounds.Y + icon_bounds.Height, + icon_bounds.X + icon_bounds.Width / 2, outline.Y + outline.Height / 2); + + g.DrawLine (pen, + icon_bounds.X + icon_bounds.Width / 2, outline.Y + outline.Height / 2, + outline.X, outline.Y + outline.Height / 2); + + g.DrawRectangle (pen, outline); + + g.DrawString (relation_text, grid.LinkFont, ResPool.GetSolidBrush (grid.LinkColor), + outline, string_format); + + if (row_rect.X + row_rect.Width > rect_cell.X + rect_cell.Width) { + Rectangle not_usedarea = new Rectangle (); + not_usedarea.X = rect_cell.X + rect_cell.Width; + not_usedarea.Width = row_rect.X + row_rect.Width - rect_cell.X - rect_cell.Width; + not_usedarea.Y = row_rect.Y; + not_usedarea.Height = row_rect.Height; + if (clip.IntersectsWith (not_usedarea)) + g.FillRectangle (ResPool.GetSolidBrush (grid.BackgroundColor), + not_usedarea); + } + } + } + + public override void DataGridPaintRowContents (Graphics g, int row, Rectangle row_rect, bool is_newrow, + Rectangle clip, DataGrid grid) + { + Rectangle rect_cell = new Rectangle (); + int col_pixel; + Color backcolor, forecolor; + Brush backBrush, foreBrush; + Rectangle not_usedarea = Rectangle.Empty; + + rect_cell.Y = row_rect.Y; + rect_cell.Height = row_rect.Height; + + if (grid.IsSelected (row)) { + backcolor = grid.SelectionBackColor; + forecolor = grid.SelectionForeColor; + } else { + if (row % 2 == 0) { + backcolor = grid.BackColor; + } else { + backcolor = grid.AlternatingBackColor; + } + + forecolor = grid.ForeColor; + } + + + backBrush = ResPool.GetSolidBrush (backcolor); + foreBrush = ResPool.GetSolidBrush (forecolor); + + // PaintCells at row, column + int column_cnt = grid.FirstVisibleColumn + grid.VisibleColumnCount; + DataGridCell current_cell = grid.CurrentCell; + + if (column_cnt > 0) { + Region prev_clip = g.Clip; + Region current_clip; + + for (int column = grid.FirstVisibleColumn; column < column_cnt; column++) { + if (grid.CurrentTableStyle.GridColumnStyles[column].bound == false) + continue; + + col_pixel = grid.GetColumnStartingPixel (column); + + rect_cell.X = row_rect.X + col_pixel - grid.HorizPixelOffset; + rect_cell.Width = grid.CurrentTableStyle.GridColumnStyles[column].Width; + + if (clip.IntersectsWith (rect_cell)) { + current_clip = new Region (rect_cell); + current_clip.Intersect (row_rect); + current_clip.Intersect (prev_clip); + g.Clip = current_clip; + + Brush colBackBrush = backBrush; + Brush colForeBrush = foreBrush; + + // If we are in the precise cell we are editing, then use the normal colors + // even if we are selected. + if (grid.is_editing && column == current_cell.ColumnNumber && row == current_cell.RowNumber) { + colBackBrush = ResPool.GetSolidBrush (grid.BackColor); + colForeBrush = ResPool.GetSolidBrush (grid.ForeColor); + } + + if (is_newrow) { + grid.CurrentTableStyle.GridColumnStyles[column].PaintNewRow (g, rect_cell, + colBackBrush, + colForeBrush); + } else { + grid.CurrentTableStyle.GridColumnStyles[column].Paint (g, rect_cell, grid.ListManager, row, + colBackBrush, + colForeBrush, + grid.RightToLeft == RightToLeft.Yes); + } + + current_clip.Dispose (); + } + } + + g.Clip = prev_clip; + + if (row_rect.X + row_rect.Width > rect_cell.X + rect_cell.Width) { + not_usedarea.X = rect_cell.X + rect_cell.Width; + not_usedarea.Width = row_rect.X + row_rect.Width - rect_cell.X - rect_cell.Width; + not_usedarea.Y = row_rect.Y; + not_usedarea.Height = row_rect.Height; + } + } + else { + not_usedarea = row_rect; + } + + if (!not_usedarea.IsEmpty && clip.IntersectsWith (not_usedarea)) + g.FillRectangle (ResPool.GetSolidBrush (grid.BackgroundColor), + not_usedarea); + } + + public override void DataGridPaintRow (Graphics g, int row, Rectangle row_rect, bool is_newrow, + Rectangle clip, DataGrid grid) + { + /* paint the header if it's visible and intersects the clip + if (grid.CurrentTableStyle.CurrentRowHeadersVisible) { + Rectangle rect_header = row_rect; + rect_header.Width = grid.RowHeaderWidth; + row_rect.X += grid.RowHeaderWidth; + if (clip.IntersectsWith (rect_header)) { + DataGridPaintRowHeader (g, rect_header, row, grid); + } + } + + DataGridPaintRowContents (g, row, row_rect, is_newrow, clip, grid); + } + + #endregion // Datagrid + + #region DataGridView + #region DataGridViewHeaderCell + #region DataGridViewRowHeaderCell + public override bool DataGridViewRowHeaderCellDrawBackground (DataGridViewRowHeaderCell cell, Graphics g, Rectangle bounds) + { + return false; + } + + public override bool DataGridViewRowHeaderCellDrawSelectionBackground (DataGridViewRowHeaderCell cell) + { + return false; + } + + public override bool DataGridViewRowHeaderCellDrawBorder (DataGridViewRowHeaderCell cell, Graphics g, Rectangle bounds) + { + return false; + } + #endregion + + #region DataGridViewColumnHeaderCell + public override bool DataGridViewColumnHeaderCellDrawBackground (DataGridViewColumnHeaderCell cell, Graphics g, Rectangle bounds) + { + return false; + } + + public override bool DataGridViewColumnHeaderCellDrawBorder (DataGridViewColumnHeaderCell cell, Graphics g, Rectangle bounds) + { + return false; + } + #endregion + + public override bool DataGridViewHeaderCellHasPressedStyle (DataGridView dataGridView) + { + return false; + } + + public override bool DataGridViewHeaderCellHasHotStyle (DataGridView dataGridView) + { + return false; + } + #endregion + #endregion +*/ + + #region DateTimePicker + protected virtual void DateTimePickerDrawBorder(DateTimePicker dateTimePicker, Graphics g, Rectangle clippingArea) + { + this.CPDrawBorder3D(g, dateTimePicker.ClientRectangle, Border3DStyle.Sunken, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom, dateTimePicker.BackColor); + } + + protected virtual void DateTimePickerDrawDropDownButton(DateTimePicker dateTimePicker, Graphics g, Rectangle clippingArea) + { + ButtonState state = dateTimePicker.is_drop_down_visible ? ButtonState.Pushed : ButtonState.Normal; + g.FillRectangle(ResPool.GetSolidBrush(ColorControl), dateTimePicker.drop_down_arrow_rect); + this.CPDrawComboButton( + g, + dateTimePicker.drop_down_arrow_rect, + state); + } + + public override void DrawDateTimePicker(Graphics dc, Rectangle clip_rectangle, DateTimePicker dtp) + { + + if (!clip_rectangle.IntersectsWith(dtp.ClientRectangle)) + return; + + // draw the outer border + Rectangle button_bounds = dtp.ClientRectangle; + DateTimePickerDrawBorder(dtp, dc, clip_rectangle); + + // deflate by the border width + if (clip_rectangle.IntersectsWith(dtp.drop_down_arrow_rect)) + { + button_bounds.Inflate(-2, -2); + if (!dtp.ShowUpDown) + { + DateTimePickerDrawDropDownButton(dtp, dc, clip_rectangle); + } + else + { + ButtonState up_state = dtp.is_up_pressed ? ButtonState.Pushed : ButtonState.Normal; + ButtonState down_state = dtp.is_down_pressed ? ButtonState.Pushed : ButtonState.Normal; + Rectangle up_bounds = dtp.drop_down_arrow_rect; + Rectangle down_bounds = dtp.drop_down_arrow_rect; + + up_bounds.Height = up_bounds.Height / 2; + down_bounds.Y = up_bounds.Height; + down_bounds.Height = dtp.Height - up_bounds.Height; + if (down_bounds.Height > up_bounds.Height) + { + down_bounds.Y += 1; + down_bounds.Height -= 1; + } + + up_bounds.Inflate(-1, -1); + down_bounds.Inflate(-1, -1); + + WidgetPaint.DrawScrollButton(dc, up_bounds, ScrollButton.Up, up_state); + WidgetPaint.DrawScrollButton(dc, down_bounds, ScrollButton.Down, down_state); + } + } + + // render the date part + if (!clip_rectangle.IntersectsWith(dtp.date_area_rect)) + return; + + // fill the background + dc.FillRectangle(SystemBrushes.Window, dtp.date_area_rect); + + // Update date_area_rect if we are drawing the checkbox + Rectangle date_area_rect = dtp.date_area_rect; + if (dtp.ShowCheckBox) + { + Rectangle check_box_rect = dtp.CheckBoxRect; + date_area_rect.X = date_area_rect.X + check_box_rect.Width + DateTimePicker.check_box_space * 2; + date_area_rect.Width = date_area_rect.Width - check_box_rect.Width - DateTimePicker.check_box_space * 2; + + ButtonState bs = dtp.Checked ? ButtonState.Checked : ButtonState.Normal; + CPDrawCheckBox(dc, check_box_rect, bs); + + if (dtp.is_checkbox_selected) + CPDrawFocusRectangle(dc, check_box_rect, dtp.foreground_color, dtp.background_color); + } + + // render each text part + using (StringFormat text_format = StringFormat.GenericTypographic) + { + text_format.LineAlignment = StringAlignment.Near; + text_format.Alignment = StringAlignment.Near; + text_format.FormatFlags = text_format.FormatFlags | StringFormatFlags.MeasureTrailingSpaces | StringFormatFlags.NoWrap | StringFormatFlags.FitBlackBox; + text_format.FormatFlags &= ~StringFormatFlags.NoClip; + + // Calculate the rectangles for each part + if (dtp.part_data.Length > 0 && dtp.part_data[0].drawing_rectangle.IsEmpty) + { + Graphics gr = dc; + for (int i = 0; i < dtp.part_data.Length; i++) + { + DateTimePicker.PartData fd = dtp.part_data[i]; + RectangleF text_rect = new RectangleF(); + string text = fd.GetText(dtp.Value); + text_rect.Size = gr.MeasureString(text, dtp.Font, 250, text_format); + if (!fd.is_literal) + text_rect.Width = Math.Max(dtp.CalculateMaxWidth(fd.value, gr, text_format), text_rect.Width); + + if (i > 0) + { + text_rect.X = dtp.part_data[i - 1].drawing_rectangle.Right; + } + else + { + text_rect.X = date_area_rect.X; + } + text_rect.Y = 2; + text_rect.Inflate(1, 0); + fd.drawing_rectangle = text_rect; + } + } + + // draw the text part + Brush text_brush = ResPool.GetSolidBrush(dtp.ShowCheckBox && dtp.Checked == false ? + SystemColors.GrayText : dtp.ForeColor); // Use GrayText if Checked is false + RectangleF clip_rectangleF = clip_rectangle; + + for (int i = 0; i < dtp.part_data.Length; i++) + { + DateTimePicker.PartData fd = dtp.part_data[i]; + string text; + + if (!clip_rectangleF.IntersectsWith(fd.drawing_rectangle)) + continue; + + text = dtp.editing_part_index == i ? dtp.editing_text : fd.GetText(dtp.Value); + + PointF text_position = new PointF(); + SizeF text_size; + RectangleF text_rect; + + text_size = dc.MeasureString(text, dtp.Font, 250, text_format); + text_position.X = (fd.drawing_rectangle.Left + fd.drawing_rectangle.Width / 2) - text_size.Width / 2; + text_position.Y = (fd.drawing_rectangle.Top + fd.drawing_rectangle.Height / 2) - text_size.Height / 2; + text_rect = new RectangleF(text_position, text_size); + text_rect = RectangleF.Intersect(text_rect, date_area_rect); + + if (text_rect.IsEmpty) + break; + + if (text_rect.Right >= date_area_rect.Right) + text_format.FormatFlags &= ~StringFormatFlags.NoClip; + else + text_format.FormatFlags |= StringFormatFlags.NoClip; + + if (fd.Selected) + { + dc.FillRectangle(SystemBrushes.Highlight, text_rect); + dc.DrawString(text, dtp.Font, SystemBrushes.HighlightText, text_rect, text_format); + + } + else + { + dc.DrawString(text, dtp.Font, text_brush, text_rect, text_format); + } + + if (fd.drawing_rectangle.Right > date_area_rect.Right) + break; // the next part would be not be visible, so don't draw anything more. + } + } + } + + public override bool DateTimePickerBorderHasHotElementStyle + { + get + { + return false; + } + } + + public override Rectangle DateTimePickerGetDropDownButtonArea(DateTimePicker dateTimePicker) + { + Rectangle rect = dateTimePicker.ClientRectangle; + rect.X = rect.Right - SystemInformation.VerticalScrollBarWidth - 2; + if (rect.Width > (SystemInformation.VerticalScrollBarWidth + 2)) + { + rect.Width = SystemInformation.VerticalScrollBarWidth; + } + else + { + rect.Width = Math.Max(rect.Width - 2, 0); + } + + rect.Inflate(0, -2); + return rect; + } + + public override Rectangle DateTimePickerGetDateArea(DateTimePicker dateTimePicker) + { + Rectangle rect = dateTimePicker.ClientRectangle; + if (dateTimePicker.ShowUpDown) + { + // set the space to the left of the up/down button + if (rect.Width > (DateTimePicker.up_down_width + 4)) + { + rect.Width -= (DateTimePicker.up_down_width + 4); + } + else + { + rect.Width = 0; + } + } + else + { + // set the space to the left of the up/down button + // TODO make this use up down button + if (rect.Width > (SystemInformation.VerticalScrollBarWidth + 4)) + { + rect.Width -= SystemInformation.VerticalScrollBarWidth; + } + else + { + rect.Width = 0; + } + } + + rect.Inflate(-2, -2); + return rect; + } + public override bool DateTimePickerDropDownButtonHasHotElementStyle + { + get + { + return false; + } + } + #endregion // DateTimePicker + + #region GroupBox + public override void DrawGroupBox(Graphics dc, Rectangle area, GroupBox box) + { + StringFormat text_format; + SizeF size; + int width; + int y; + + dc.FillRectangle(GetControlBackBrush(box.BackColor), box.ClientRectangle); + + text_format = new StringFormat(); + text_format.HotkeyPrefix = HotkeyPrefix.Show; + + size = dc.MeasureString(box.Text, box.Font); + width = 0; + + if (size.Width > 0) + { + width = ((int)size.Width) + 7; + + if (width > box.Width - 16) + width = box.Width - 16; + } + + y = box.Font.Height / 2; + + // Clip the are that the text will be in + Region prev_clip = dc.Clip; + dc.SetClip(new Rectangle(10, 0, width, box.Font.Height), CombineMode.Exclude); + /* Draw group box*/ + CPDrawBorder3D(dc, new Rectangle(0, y, box.Width, box.Height - y), Border3DStyle.Etched, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom, box.BackColor); + dc.Clip = prev_clip; + + /* Text */ + if (box.Text.Length != 0) + { + if (box.Enabled) + { + dc.DrawString(box.Text, box.Font, ResPool.GetSolidBrush(box.ForeColor), 10, 0, text_format); + } + else + { + CPDrawStringDisabled(dc, box.Text, box.Font, box.BackColor, + new RectangleF(10, 0, width, box.Font.Height), text_format); + } + } + + text_format.Dispose(); + } + + public override Size GroupBoxDefaultSize + { + get + { + return new Size(200, 100); + } + } + #endregion + + #region HScrollBar + public override Size HScrollBarDefaultSize + { + get + { + return new Size(80, this.ScrollBarButtonSize); + } + } + + #endregion // HScrollBar + + #region ListBox + + public override void DrawListBoxItem(ListBox ctrl, DrawItemEventArgs e) + { + Color back_color, fore_color; + + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) + { + back_color = ColorHighlight; + fore_color = ColorHighlightText; + } + else + { + back_color = e.BackColor; + fore_color = e.ForeColor; + } + + e.Graphics.FillRectangle(ResPool.GetSolidBrush(back_color), e.Bounds); + + e.Graphics.DrawString(ctrl.GetItemText(ctrl.Items[e.Index]), e.Font, + ResPool.GetSolidBrush(fore_color), + e.Bounds, ctrl.StringFormat); + + if ((e.State & DrawItemState.Focus) == DrawItemState.Focus) + CPDrawFocusRectangle(e.Graphics, e.Bounds, fore_color, back_color); + } + + #endregion ListBox + + #region ListView + // Drawing + public override void DrawListViewItems(Graphics dc, Rectangle clip, ListView control) + { + bool details = control.View == View.Details; + int first = control.FirstVisibleIndex; + int lastvisibleindex = control.LastVisibleIndex; + + if (control.VirtualMode) + control.OnCacheVirtualItems(new CacheVirtualItemsEventArgs(first, lastvisibleindex)); + + for (int i = first; i <= lastvisibleindex; i++) + { + ListViewItem item = control.GetItemAtDisplayIndex(i); + if (clip.IntersectsWith(item.Bounds)) + { + bool owner_draw = false; + if (control.OwnerDraw) + owner_draw = DrawListViewItemOwnerDraw(dc, item, i); + if (!owner_draw) + { + DrawListViewItem(dc, control, item); + if (control.View == View.Details) + DrawListViewSubItems(dc, control, item); + } + } + } + + if (control.UsingGroups) + { + // Use InternalCount instead of Count to take into account Default Group as needed + for (int i = 0; i < control.Groups.InternalCount; i++) + { + ListViewGroup group = control.Groups.GetInternalGroup(i); + if (group.ItemCount > 0 && clip.IntersectsWith(group.HeaderBounds)) + DrawListViewGroupHeader(dc, control, group); + } + } + + ListViewInsertionMark insertion_mark = control.InsertionMark; + int insertion_mark_index = insertion_mark.Index; + if (Application.VisualStylesEnabled && insertion_mark.Bounds != Rectangle.Empty && + (control.View != View.Details && control.View != View.List) && + insertion_mark_index > -1 && insertion_mark_index < control.Items.Count) + { + + Brush brush = ResPool.GetSolidBrush(insertion_mark.Color); + dc.FillRectangle(brush, insertion_mark.Line); + dc.FillPolygon(brush, insertion_mark.TopTriangle); + dc.FillPolygon(brush, insertion_mark.BottomTriangle); + } + + // draw the gridlines + if (details && control.GridLines && !control.UsingGroups) + { + Size control_size = control.ClientSize; + int top = (control.HeaderStyle == ColumnHeaderStyle.None) ? + 0 : control.header_control.Height; + + // draw vertical gridlines + foreach (ColumnHeader col in control.Columns) + { + int column_right = col.Rect.Right - control.h_marker; + dc.DrawLine(SystemPens.Control, + column_right, top, + column_right, control_size.Height); + } + + // draw horizontal gridlines + int item_height = control.ItemSize.Height; + if (item_height == 0) + item_height = control.Font.Height + 2; + + int y = top + item_height - (control.v_marker % item_height); // scroll bar offset + while (y < control_size.Height) + { + dc.DrawLine(SystemPens.Control, 0, y, control_size.Width, y); + y += item_height; + } + } + + // Draw corner between the two scrollbars + if (control.h_scroll.Visible == true && control.v_scroll.Visible == true) + { + Rectangle rect = new Rectangle(); + rect.X = control.h_scroll.Location.X + control.h_scroll.Width; + rect.Width = control.v_scroll.Width; + rect.Y = control.v_scroll.Location.Y + control.v_scroll.Height; + rect.Height = control.h_scroll.Height; + dc.FillRectangle(SystemBrushes.Control, rect); + } + + Rectangle box_select_rect = control.item_control.BoxSelectRectangle; + if (!box_select_rect.Size.IsEmpty) + dc.DrawRectangle(ResPool.GetDashPen(ColorControlText, DashStyle.Dot), box_select_rect); + + } + + public override void DrawListViewHeader(Graphics dc, Rectangle clip, ListView control) + { + bool details = (control.View == View.Details); + + // border is drawn directly in the Paint method + if (details && control.HeaderStyle != ColumnHeaderStyle.None) + { + dc.FillRectangle(SystemBrushes.Control, + 0, 0, control.TotalWidth, control.Font.Height + 5); + if (control.Columns.Count > 0) + { + foreach (ColumnHeader col in control.Columns) + { + Rectangle rect = col.Rect; + rect.X -= control.h_marker; + + bool owner_draw = false; + if (control.OwnerDraw) + owner_draw = DrawListViewColumnHeaderOwnerDraw(dc, control, col, rect); + if (owner_draw) + continue; + + ListViewDrawColumnHeaderBackground(control, col, dc, rect, clip); + rect.X += 5; + rect.Width -= 10; + if (rect.Width <= 0) + continue; + + int image_index; + if (control.SmallImageList == null) + image_index = -1; + else + image_index = col.ImageKey == String.Empty ? col.ImageIndex : control.SmallImageList.Images.IndexOfKey(col.ImageKey); + + if (image_index > -1 && image_index < control.SmallImageList.Images.Count) + { + int image_width = control.SmallImageList.ImageSize.Width + 5; + int text_width = (int)dc.MeasureString(col.Text, control.Font).Width; + int x_origin = rect.X; + int y_origin = rect.Y + ((rect.Height - control.SmallImageList.ImageSize.Height) / 2); + + switch (col.TextAlign) + { + case HorizontalAlignment.Left: + break; + case HorizontalAlignment.Right: + x_origin = rect.Right - (text_width + image_width); + break; + case HorizontalAlignment.Center: + x_origin = (rect.Width - (text_width + image_width)) / 2 + rect.X; + break; + } + + if (x_origin < rect.X) + x_origin = rect.X; + + control.SmallImageList.Draw(dc, new Point(x_origin, y_origin), image_index); + rect.X += image_width; + rect.Width -= image_width; + } + + dc.DrawString(col.Text, control.Font, SystemBrushes.ControlText, rect, col.Format); + } + int right = control.GetReorderedColumn(control.Columns.Count - 1).Rect.Right - control.h_marker; + if (right < control.Right) + { + Rectangle rect = control.Columns[0].Rect; + rect.X = right; + rect.Width = control.Right - right; + ListViewDrawUnusedHeaderBackground(control, dc, rect, clip); + } + } + } + } + + protected virtual void ListViewDrawColumnHeaderBackground(ListView listView, ColumnHeader columnHeader, Graphics g, Rectangle area, Rectangle clippingArea) + { + ButtonState state; + if (listView.HeaderStyle == ColumnHeaderStyle.Clickable) + state = columnHeader.Pressed ? ButtonState.Pushed : ButtonState.Normal; + else + state = ButtonState.Flat; + CPDrawButton(g, area, state); + } + + protected virtual void ListViewDrawUnusedHeaderBackground(ListView listView, Graphics g, Rectangle area, Rectangle clippingArea) + { + ButtonState state; + if (listView.HeaderStyle == ColumnHeaderStyle.Clickable) + state = ButtonState.Normal; + else + state = ButtonState.Flat; + CPDrawButton(g, area, state); + } + + public override void DrawListViewHeaderDragDetails(Graphics dc, ListView view, ColumnHeader col, int target_x) + { + Rectangle rect = col.Rect; + rect.X -= view.h_marker; + Color color = Color.FromArgb(0x7f, ColorControlDark.R, ColorControlDark.G, ColorControlDark.B); + dc.FillRectangle(ResPool.GetSolidBrush(color), rect); + rect.X += 3; + rect.Width -= 8; + if (rect.Width <= 0) + return; + color = Color.FromArgb(0x7f, ColorControlText.R, ColorControlText.G, ColorControlText.B); + dc.DrawString(col.Text, view.Font, ResPool.GetSolidBrush(color), rect, col.Format); + dc.DrawLine(ResPool.GetSizedPen(ColorHighlight, 2), target_x, 0, target_x, col.Rect.Height); + } + + protected virtual bool DrawListViewColumnHeaderOwnerDraw(Graphics dc, ListView control, ColumnHeader column, Rectangle bounds) + { + ListViewItemStates state = ListViewItemStates.ShowKeyboardCues; + if (column.Pressed) + state |= ListViewItemStates.Selected; + + DrawListViewColumnHeaderEventArgs args = new DrawListViewColumnHeaderEventArgs(dc, + bounds, column.Index, column, state, SystemColors.ControlText, ThemeEngine.Current.ColorControl, DefaultFont); + control.OnDrawColumnHeader(args); + + return !args.DrawDefault; + } + + protected virtual bool DrawListViewItemOwnerDraw(Graphics dc, ListViewItem item, int index) + { + ListViewItemStates item_state = ListViewItemStates.ShowKeyboardCues; + if (item.Selected) + item_state |= ListViewItemStates.Selected; + if (item.Focused) + item_state |= ListViewItemStates.Focused; + + DrawListViewItemEventArgs args = new DrawListViewItemEventArgs(dc, + item, item.Bounds, index, item_state); + item.ListView.OnDrawItem(args); + + if (args.DrawDefault) + return false; + + if (item.ListView.View == View.Details) + { + int count = Math.Min(item.ListView.Columns.Count, item.SubItems.Count); + + // Do system drawing for subitems if no owner draw is done + for (int j = 0; j < count; j++) + { + if (!DrawListViewSubItemOwnerDraw(dc, item, item_state, j)) + { + if (j == 0) // The first sub item contains the main item semantics + DrawListViewItem(dc, item.ListView, item); + else + DrawListViewSubItem(dc, item.ListView, item, j); + } + } + } + + return true; + } + + protected virtual void DrawListViewItem(Graphics dc, ListView control, ListViewItem item) + { + Rectangle rect_checkrect = item.CheckRectReal; + Rectangle icon_rect = item.GetBounds(ItemBoundsPortion.Icon); + Rectangle full_rect = item.GetBounds(ItemBoundsPortion.Entire); + Rectangle text_rect = item.GetBounds(ItemBoundsPortion.Label); + + // Tile view doesn't support CheckBoxes + if (control.CheckBoxes && control.View != View.Tile) + { + if (control.StateImageList == null) + { + // Make sure we've got at least a line width of 1 + int check_wd = Math.Max(3, rect_checkrect.Width / 6); + int scale = Math.Max(1, rect_checkrect.Width / 12); + + // set the checkbox background + dc.FillRectangle(SystemBrushes.Window, + rect_checkrect); + // define a rectangle inside the border area + Rectangle rect = new Rectangle(rect_checkrect.X + 2, + rect_checkrect.Y + 2, + rect_checkrect.Width - 4, + rect_checkrect.Height - 4); + Pen pen = ResPool.GetSizedPen(this.ColorWindowText, 2); + dc.DrawRectangle(pen, rect); + + // Need to draw a check-mark + if (item.Checked) + { + Pen check_pen = ResPool.GetSizedPen(this.ColorWindowText, 1); + // adjustments to get the check-mark at the right place + rect.X++; rect.Y++; + // following logic is taken from DrawFrameControl method + int x_offset = rect.Width / 5; + int y_offset = rect.Height / 3; + for (int i = 0; i < check_wd; i++) + { + dc.DrawLine(check_pen, rect.Left + x_offset, + rect.Top + y_offset + i, + rect.Left + x_offset + 2 * scale, + rect.Top + y_offset + 2 * scale + i); + dc.DrawLine(check_pen, + rect.Left + x_offset + 2 * scale, + rect.Top + y_offset + 2 * scale + i, + rect.Left + x_offset + 6 * scale, + rect.Top + y_offset - 2 * scale + i); + } + } + } + else + { + int simage_idx; + if (item.Checked) + simage_idx = control.StateImageList.Images.Count > 1 ? 1 : -1; + else + simage_idx = control.StateImageList.Images.Count > 0 ? 0 : -1; + + if (simage_idx > -1) + control.StateImageList.Draw(dc, rect_checkrect.Location, simage_idx); + } + } + + ImageList image_list = control.View == View.LargeIcon || control.View == View.Tile ? control.LargeImageList : control.SmallImageList; + if (image_list != null) + { + int idx; + + if (item.ImageKey != String.Empty) + idx = image_list.Images.IndexOfKey(item.ImageKey); + else + idx = item.ImageIndex; + + if (idx > -1 && idx < image_list.Images.Count) + { + // Draw a thumbnail image if it exists for a FileViewListViewItem, otherwise draw + // the standard icon. See https://bugzilla.xamarin.com/show_bug.cgi?id=28025. + image_list.Draw(dc, icon_rect.Location, idx); + } + } + + // draw the item text + // format for the item text + StringFormat format = new StringFormat(); + if (control.View == View.SmallIcon || control.View == View.LargeIcon) + format.LineAlignment = StringAlignment.Near; + else + format.LineAlignment = StringAlignment.Center; + if (control.View == View.LargeIcon) + format.Alignment = StringAlignment.Center; + else + format.Alignment = StringAlignment.Near; + + if (control.LabelWrap && control.View != View.Details && control.View != View.Tile) + format.FormatFlags = StringFormatFlags.LineLimit; + else + format.FormatFlags = StringFormatFlags.NoWrap; + + if ((control.View == View.LargeIcon && !item.Focused) || control.View == View.Details || control.View == View.Tile) + format.Trimming = StringTrimming.EllipsisCharacter; + + Rectangle highlight_rect = text_rect; + if (control.View == View.Details) + { // Adjustments for Details view + Size text_size = Size.Ceiling(dc.MeasureString(item.Text, item.Font)); + + if (!control.FullRowSelect) // Selection shouldn't be outside the item bounds + highlight_rect.Width = Math.Min(text_size.Width + 4, text_rect.Width); + } + + if (item.Selected && control.Focused) + dc.FillRectangle(SystemBrushes.Highlight, highlight_rect); + else if (item.Selected && !control.HideSelection) + dc.FillRectangle(SystemBrushes.Control, highlight_rect); + else + dc.FillRectangle(ResPool.GetSolidBrush(item.BackColor), text_rect); + + Brush textBrush = + !control.Enabled ? SystemBrushes.ControlLight : + (item.Selected && control.Focused) ? SystemBrushes.HighlightText : + this.ResPool.GetSolidBrush(item.ForeColor); + + // Tile view renders its Text in a different fashion + if (control.View == View.Tile && Application.VisualStylesEnabled) + { + // Item.Text is drawn using its first subitem's bounds + dc.DrawString(item.Text, item.Font, textBrush, item.SubItems[0].Bounds, format); + + int count = Math.Min(control.Columns.Count, item.SubItems.Count); + for (int i = 1; i < count; i++) + { + ListViewItem.ListViewSubItem sub_item = item.SubItems[i]; + if (sub_item.Text == null || sub_item.Text.Length == 0) + continue; + + Brush itemBrush = item.Selected && control.Focused ? + SystemBrushes.HighlightText : GetControlForeBrush(sub_item.ForeColor); + dc.DrawString(sub_item.Text, sub_item.Font, itemBrush, sub_item.Bounds, format); + } + } + else + + if (item.Text != null && item.Text.Length > 0) + { + Font font = item.Font; + + if (control.HotTracking && item.Hot) + font = item.HotFont; + + if (item.Selected && control.Focused) + dc.DrawString(item.Text, font, textBrush, highlight_rect, format); + else + dc.DrawString(item.Text, font, textBrush, text_rect, format); + } + + if (item.Focused && control.Focused) + { + Rectangle focus_rect = highlight_rect; + if (control.FullRowSelect && control.View == View.Details) + { + int width = 0; + foreach (ColumnHeader col in control.Columns) + width += col.Width; + focus_rect = new Rectangle(0, full_rect.Y, width, full_rect.Height); + } + if (control.ShowFocusCues) + { + if (item.Selected) + CPDrawFocusRectangle(dc, focus_rect, ColorHighlightText, ColorHighlight); + else + CPDrawFocusRectangle(dc, focus_rect, control.ForeColor, control.BackColor); + } + } + + format.Dispose(); + } + + protected virtual void DrawListViewSubItems(Graphics dc, ListView control, ListViewItem item) + { + int columns_count = control.Columns.Count; + int count = Math.Min(item.SubItems.Count, columns_count); + // 0th item already done (in this case) + for (int i = 1; i < count; i++) + DrawListViewSubItem(dc, control, item, i); + + // Fill in selection for remaining columns if Column.Count > SubItems.Count + Rectangle sub_item_rect = item.GetBounds(ItemBoundsPortion.Label); + if (item.Selected && (control.Focused || !control.HideSelection) && control.FullRowSelect) + { + for (int index = count; index < columns_count; index++) + { + ColumnHeader col = control.Columns[index]; + sub_item_rect.X = col.Rect.X - control.h_marker; + sub_item_rect.Width = col.Wd; + dc.FillRectangle(control.Focused ? SystemBrushes.Highlight : SystemBrushes.Control, + sub_item_rect); + } + } + } + + protected virtual void DrawListViewSubItem(Graphics dc, ListView control, ListViewItem item, int index) + { + ListViewItem.ListViewSubItem subItem = item.SubItems[index]; + ColumnHeader col = control.Columns[index]; + StringFormat format = new StringFormat(); + format.Alignment = col.Format.Alignment; + format.LineAlignment = StringAlignment.Center; + format.FormatFlags = StringFormatFlags.NoWrap; + format.Trimming = StringTrimming.EllipsisCharacter; + + Rectangle sub_item_rect = subItem.Bounds; + Rectangle sub_item_text_rect = sub_item_rect; + sub_item_text_rect.X += 3; + sub_item_text_rect.Width -= ListViewItemPaddingWidth; + + SolidBrush sub_item_back_br = null; + SolidBrush sub_item_fore_br = null; + Font sub_item_font = null; + + if (item.UseItemStyleForSubItems) + { + sub_item_back_br = ResPool.GetSolidBrush(item.BackColor); + sub_item_fore_br = ResPool.GetSolidBrush(item.ForeColor); + + // Hot tracking for subitems only applies when UseStyle is true + if (control.HotTracking && item.Hot) + sub_item_font = item.HotFont; + else + sub_item_font = item.Font; + } + else + { + sub_item_back_br = ResPool.GetSolidBrush(subItem.BackColor); + sub_item_fore_br = ResPool.GetSolidBrush(subItem.ForeColor); + sub_item_font = subItem.Font; + } + + if (item.Selected && (control.Focused || !control.HideSelection) && control.FullRowSelect) + { + Brush bg, text; + if (control.Focused) + { + bg = SystemBrushes.Highlight; + text = SystemBrushes.HighlightText; + } + else + { + bg = SystemBrushes.Control; + text = sub_item_fore_br; + + } + + dc.FillRectangle(bg, sub_item_rect); + if (subItem.Text != null && subItem.Text.Length > 0) + dc.DrawString(subItem.Text, sub_item_font, + text, sub_item_text_rect, format); + } + else + { + dc.FillRectangle(sub_item_back_br, sub_item_rect); + if (subItem.Text != null && subItem.Text.Length > 0) + dc.DrawString(subItem.Text, sub_item_font, + sub_item_fore_br, + sub_item_text_rect, format); + } + + format.Dispose(); + } + + protected virtual bool DrawListViewSubItemOwnerDraw(Graphics dc, ListViewItem item, ListViewItemStates state, int index) + { + ListView control = item.ListView; + ListViewItem.ListViewSubItem subitem = item.SubItems[index]; + + DrawListViewSubItemEventArgs args = new DrawListViewSubItemEventArgs(dc, subitem.Bounds, item, + subitem, item.Index, index, control.Columns[index], state); + control.OnDrawSubItem(args); + + return !args.DrawDefault; + } + + protected virtual void DrawListViewGroupHeader(Graphics dc, ListView control, ListViewGroup group) + { + Rectangle text_bounds = group.HeaderBounds; + Rectangle header_bounds = group.HeaderBounds; + text_bounds.Offset(8, 0); + text_bounds.Inflate(-8, 0); + int text_height = control.Font.Height + 2; // add a tiny padding between the text and the group line + + Font font = new Font(control.Font, control.Font.Style | FontStyle.Bold); + Brush brush = new LinearGradientBrush(new Point(header_bounds.Left, 0), new Point(header_bounds.Left + ListViewGroupLineWidth, 0), + SystemColors.Desktop, Color.White); + Pen pen = new Pen(brush); + + StringFormat sformat = new StringFormat(); + switch (group.HeaderAlignment) + { + case HorizontalAlignment.Left: + sformat.Alignment = StringAlignment.Near; + break; + case HorizontalAlignment.Center: + sformat.Alignment = StringAlignment.Center; + break; + case HorizontalAlignment.Right: + sformat.Alignment = StringAlignment.Far; + break; + } + + sformat.LineAlignment = StringAlignment.Near; + dc.DrawString(group.Header, font, SystemBrushes.ControlText, text_bounds, sformat); + dc.DrawLine(pen, header_bounds.Left, header_bounds.Top + text_height, header_bounds.Left + ListViewGroupLineWidth, + header_bounds.Top + text_height); + + sformat.Dispose(); + font.Dispose(); + pen.Dispose(); + brush.Dispose(); + } + + public override bool ListViewHasHotHeaderStyle + { + get + { + return false; + } + } + + // Sizing + public override int ListViewGetHeaderHeight(ListView listView, Font font) + { + return ListViewGetHeaderHeight(font); + } + + static int ListViewGetHeaderHeight(Font font) + { + return font.Height + 5; + } + + public static int ListViewGetHeaderHeight() + { + return ListViewGetHeaderHeight(ThemeEngine.Current.DefaultFont); + } + + public override Size ListViewCheckBoxSize + { + get { return new Size(16, 16); } + } + + public override int ListViewColumnHeaderHeight + { + get { return 16; } + } + + public override int ListViewDefaultColumnWidth + { + get { return 60; } + } + + public override int ListViewVerticalSpacing + { + get { return 22; } + } + + public override int ListViewEmptyColumnWidth + { + get { return 10; } + } + + public override int ListViewHorizontalSpacing + { + get { return 4; } + } + + public override int ListViewItemPaddingWidth + { + get { return 6; } + } + + public override Size ListViewDefaultSize + { + get { return new Size(121, 97); } + } + + public override int ListViewGroupHeight + { + get { return 20; } + } + + public int ListViewGroupLineWidth + { + get { return 200; } + } + + public override int ListViewTileWidthFactor + { + get { return 22; } + } + + public override int ListViewTileHeightFactor + { + get { return 3; } + } + #endregion // ListView + + #region Menus + + public override void CalcItemSize(Graphics dc, MenuItem item, int y, int x, bool menuBar) + { + item.X = x; + item.Y = y; + + if (item.Visible == false) + { + item.Width = 0; + item.Height = 0; + return; + } + + if (item.Separator == true) + { + item.Height = SEPARATOR_HEIGHT; + item.Width = SEPARATOR_MIN_WIDTH; + return; + } + + if (item.MeasureEventDefined) + { + MeasureItemEventArgs mi = new MeasureItemEventArgs(dc, item.Index); + item.PerformMeasureItem(mi); + item.Height = mi.ItemHeight; + item.Width = mi.ItemWidth; + return; + } + else + { + SizeF size; + size = dc.MeasureString(item.Text, MenuFont, int.MaxValue, string_format_menu_text); + item.Width = (int)size.Width; + item.Height = (int)size.Height; + + if (!menuBar) + { + if (item.Shortcut != Shortcut.None && item.ShowShortcut) + { + item.XTab = MenuCheckSize.Width + MENU_TAB_SPACE + (int)size.Width; + size = dc.MeasureString(" " + item.GetShortCutText(), MenuFont); + item.Width += MENU_TAB_SPACE + (int)size.Width; + } + + item.Width += 4 + (MenuCheckSize.Width * 2); + } + else + { + item.Width += MENU_BAR_ITEMS_SPACE; + x += item.Width; + } + + if (item.Height < MenuHeight) + item.Height = MenuHeight; + } + } + + // Updates the menu rect and returns the height + public override int CalcMenuBarSize(Graphics dc, Menu menu, int width) + { + int x = 0; + int y = 0; + menu.Height = 0; + + foreach (MenuItem item in menu.MenuItems) + { + + CalcItemSize(dc, item, y, x, true); + + if (x + item.Width > width) + { + item.X = 0; + y += item.Height; + item.Y = y; + x = 0; + } + + x += item.Width; + item.MenuBar = true; + + if (y + item.Height > menu.Height) + menu.Height = item.Height + y; + } + + menu.Width = width; + return menu.Height; + } + + public override void CalcPopupMenuSize(Graphics dc, Menu menu) + { + int x = 3; + int start = 0; + int i, n, y, max; + + menu.Height = 0; + + while (start < menu.MenuItems.Count) + { + y = 3; + max = 0; + for (i = start; i < menu.MenuItems.Count; i++) + { + MenuItem item = menu.MenuItems[i]; + + if ((i != start) && (item.Break || item.BarBreak)) + break; + + CalcItemSize(dc, item, y, x, false); + y += item.Height; + + if (item.Width > max) + max = item.Width; + } + + // Replace the -1 by the menu width (separators) + for (n = start; n < i; n++, start++) + menu.MenuItems[n].Width = max; + + if (y > menu.Height) + menu.Height = y; + + x += max; + } + + menu.Width = x; + + //space for border + menu.Width += 2; + menu.Height += 2; + + menu.Width += SM_CXBORDER; + menu.Height += SM_CYBORDER; + } + + // Draws a menu bar in a window + public override void DrawMenuBar(Graphics dc, Menu menu, Rectangle rect) + { + if (menu.Height == 0) + CalcMenuBarSize(dc, menu, rect.Width); + + bool keynav = (menu as MainMenu).tracker.hotkey_active; + HotkeyPrefix hp = MenuAccessKeysUnderlined || keynav ? HotkeyPrefix.Show : HotkeyPrefix.Hide; + string_format_menu_menubar_text.HotkeyPrefix = hp; + string_format_menu_text.HotkeyPrefix = hp; + + rect.Height = menu.Height; + dc.FillRectangle(SystemBrushes.Menu, rect); + + for (int i = 0; i < menu.MenuItems.Count; i++) + { + MenuItem item = menu.MenuItems[i]; + Rectangle item_rect = item.bounds; + item_rect.X += rect.X; + item_rect.Y += rect.Y; + item.MenuHeight = menu.Height; + item.PerformDrawItem(new DrawItemEventArgs(dc, MenuFont, item_rect, i, item.Status)); + } + } + + protected Bitmap CreateGlyphBitmap(Size size, MenuGlyph glyph, Color color) + { + Color bg_color; + if (color.R == 0 && color.G == 0 && color.B == 0) + bg_color = Color.White; + else + bg_color = Color.Black; + + Bitmap bmp = new Bitmap(size.Width, size.Height); + Graphics gr = Graphics.FromImage(bmp); + Rectangle rect = new Rectangle(Point.Empty, size); + gr.FillRectangle(ResPool.GetSolidBrush(bg_color), rect); + CPDrawMenuGlyph(gr, rect, glyph, color, Color.Empty); + bmp.MakeTransparent(bg_color); + gr.Dispose(); + + return bmp; + } + + public override void DrawMenuItem(MenuItem item, DrawItemEventArgs e) + { + StringFormat string_format; + Rectangle rect_text = e.Bounds; + + if (item.Visible == false) + return; + + if (item.MenuBar) + string_format = string_format_menu_menubar_text; + else + string_format = string_format_menu_text; + + if (item.Separator == true) + { + int liney = e.Bounds.Y + (e.Bounds.Height / 2); + + e.Graphics.DrawLine(SystemPens.ControlDark, + e.Bounds.X, liney, e.Bounds.X + e.Bounds.Width, liney); + + e.Graphics.DrawLine(SystemPens.ControlLight, + e.Bounds.X, liney + 1, e.Bounds.X + e.Bounds.Width, liney + 1); + + return; + } + + if (!item.MenuBar) + rect_text.X += MenuCheckSize.Width; + + if (item.BarBreak) + { /* Draw vertical break bar*/ + Rectangle rect = e.Bounds; + rect.Y++; + rect.Width = 3; + rect.Height = item.MenuHeight - 6; + + e.Graphics.DrawLine(SystemPens.ControlDark, + rect.X, rect.Y, rect.X, rect.Y + rect.Height); + + e.Graphics.DrawLine(SystemPens.ControlLight, + rect.X + 1, rect.Y, rect.X + 1, rect.Y + rect.Height); + } + + Color color_text; + Color color_back; + Brush brush_text = null; + Brush brush_back = null; + + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected && !item.MenuBar) + { + color_text = ColorHighlightText; + color_back = ColorHighlight; + brush_text = SystemBrushes.HighlightText; + brush_back = SystemBrushes.Highlight; + } + else + { + color_text = ColorMenuText; + color_back = ColorMenu; + brush_text = ResPool.GetSolidBrush(ColorMenuText); + brush_back = SystemBrushes.Menu; + } + + /* Draw background */ + if (!item.MenuBar) + e.Graphics.FillRectangle(brush_back, e.Bounds); + + if (item.Enabled) + { + e.Graphics.DrawString(item.Text, e.Font, + brush_text, + rect_text, string_format); + + if (item.MenuBar) + { + Border3DStyle border_style = Border3DStyle.Adjust; + if ((item.Status & DrawItemState.HotLight) != 0) + border_style = Border3DStyle.RaisedInner; + else if ((item.Status & DrawItemState.Selected) != 0) + border_style = Border3DStyle.SunkenOuter; + + if (border_style != Border3DStyle.Adjust) + CPDrawBorder3D(e.Graphics, e.Bounds, border_style, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom, ColorMenu); + } + } + else + { + if ((item.Status & DrawItemState.Selected) != DrawItemState.Selected) + { + e.Graphics.DrawString(item.Text, e.Font, Brushes.White, + new RectangleF(rect_text.X + 1, rect_text.Y + 1, rect_text.Width, rect_text.Height), + string_format); + + } + + e.Graphics.DrawString(item.Text, e.Font, ResPool.GetSolidBrush(ColorGrayText), rect_text, string_format); + } + + if (!item.MenuBar && item.Shortcut != Shortcut.None && item.ShowShortcut) + { + string str = item.GetShortCutText(); + Rectangle rect = rect_text; + rect.X = item.XTab; + rect.Width -= item.XTab; + + if (item.Enabled) + { + e.Graphics.DrawString(str, e.Font, brush_text, rect, string_format_menu_shortcut); + } + else + { + if ((item.Status & DrawItemState.Selected) != DrawItemState.Selected) + { + e.Graphics.DrawString(str, e.Font, Brushes.White, + new RectangleF(rect.X + 1, rect.Y + 1, rect.Width, rect_text.Height), + string_format_menu_shortcut); + + } + e.Graphics.DrawString(str, e.Font, ResPool.GetSolidBrush(ColorGrayText), rect, string_format_menu_shortcut); + } + } + + /* Draw arrow */ + if (item.MenuBar == false && (item.IsPopup || item.MdiList)) + { + + int cx = MenuCheckSize.Width; + int cy = MenuCheckSize.Height; + Bitmap bmp = CreateGlyphBitmap(new Size(cx, cy), MenuGlyph.Arrow, color_text); + + if (item.Enabled) + { + e.Graphics.DrawImage(bmp, e.Bounds.X + e.Bounds.Width - cx, + e.Bounds.Y + ((e.Bounds.Height - cy) / 2)); + } + else + { + WidgetPaint.DrawImageDisabled(e.Graphics, bmp, e.Bounds.X + e.Bounds.Width - cx, + e.Bounds.Y + ((e.Bounds.Height - cy) / 2), color_back); + } + + bmp.Dispose(); + } + + /* Draw checked or radio */ + if (item.MenuBar == false && item.Checked) + { + + Rectangle area = e.Bounds; + int cx = MenuCheckSize.Width; + int cy = MenuCheckSize.Height; + Bitmap bmp = CreateGlyphBitmap(new Size(cx, cy), item.RadioCheck ? MenuGlyph.Bullet : MenuGlyph.Checkmark, color_text); + + e.Graphics.DrawImage(bmp, area.X, e.Bounds.Y + ((e.Bounds.Height - cy) / 2)); + + bmp.Dispose(); + } + } + + public override void DrawPopupMenu(Graphics dc, Menu menu, Rectangle cliparea, Rectangle rect) + { + // Fill rectangle area + dc.FillRectangle(SystemBrushes.Menu, cliparea); + + + // Draw menu items + for (int i = 0; i < menu.MenuItems.Count; i++) + { + if (cliparea.IntersectsWith(menu.MenuItems[i].bounds)) + { + MenuItem item = menu.MenuItems[i]; + item.MenuHeight = menu.Height; + item.PerformDrawItem(new DrawItemEventArgs(dc, MenuFont, item.bounds, i, item.Status)); + } + } + } + + #endregion // Menus + + #region MonthCalendar + + // draw the month calendar + public override void DrawMonthCalendar(Graphics dc, Rectangle clip_rectangle, MonthCalendar mc) + { + Rectangle client_rectangle = mc.ClientRectangle; + Size month_size = mc.SingleMonthSize; + // cache local copies of Marshal-by-ref internal members (gets around error CS0197) + Size calendar_spacing = (Size)((object)mc.calendar_spacing); + Size date_cell_size = (Size)((object)mc.date_cell_size); + + // draw the singlecalendars + int x_offset = 1; + int y_offset = 1; + // adjust for the position of the specific month + for (int i = 0; i < mc.CalendarDimensions.Height; i++) + { + if (i > 0) + { + y_offset += month_size.Height + calendar_spacing.Height; + } + // now adjust for x position + for (int j = 0; j < mc.CalendarDimensions.Width; j++) + { + if (j > 0) + { + x_offset += month_size.Width + calendar_spacing.Width; + } + else + { + x_offset = 1; + } + + Rectangle month_rect = new Rectangle(x_offset, y_offset, month_size.Width, month_size.Height); + if (month_rect.IntersectsWith(clip_rectangle)) + { + DrawSingleMonth( + dc, + clip_rectangle, + month_rect, + mc, + i, + j); + } + } + } + + Rectangle bottom_rect = new Rectangle( + client_rectangle.X, + Math.Max(client_rectangle.Bottom - date_cell_size.Height - 3, 0), + client_rectangle.Width, + date_cell_size.Height + 2); + // draw the today date if it's set + if (mc.ShowToday && bottom_rect.IntersectsWith(clip_rectangle)) + { + dc.FillRectangle(GetControlBackBrush(mc.BackColor), bottom_rect); + if (mc.ShowToday) + { + int today_offset = 5; + if (mc.ShowTodayCircle) + { + Rectangle today_circle_rect = new Rectangle( + client_rectangle.X + 5, + Math.Max(client_rectangle.Bottom - date_cell_size.Height - 2, 0), + date_cell_size.Width, + date_cell_size.Height); + DrawTodayCircle(dc, today_circle_rect); + today_offset += date_cell_size.Width + 5; + } + // draw today's date + StringFormat text_format = new StringFormat(); + text_format.LineAlignment = StringAlignment.Center; + text_format.Alignment = StringAlignment.Near; + Rectangle today_rect = new Rectangle( + today_offset + client_rectangle.X, + Math.Max(client_rectangle.Bottom - date_cell_size.Height, 0), + Math.Max(client_rectangle.Width - today_offset, 0), + date_cell_size.Height); + dc.DrawString("Today: " + DateTime.Now.ToShortDateString(), mc.bold_font, GetControlForeBrush(mc.ForeColor), today_rect, text_format); + text_format.Dispose(); + } + } + + Brush border_brush; + + if (mc.owner == null) + border_brush = GetControlBackBrush(mc.BackColor); + else + border_brush = SystemBrushes.ControlDarkDark; + + // finally paint the borders of the calendars as required + for (int i = 0; i <= mc.CalendarDimensions.Width; i++) + { + if (i == 0 && clip_rectangle.X == client_rectangle.X) + { + dc.FillRectangle(border_brush, client_rectangle.X, client_rectangle.Y, 1, client_rectangle.Height); + } + else if (i == mc.CalendarDimensions.Width && clip_rectangle.Right == client_rectangle.Right) + { + dc.FillRectangle(border_brush, client_rectangle.Right - 1, client_rectangle.Y, 1, client_rectangle.Height); + } + else + { + Rectangle rect = new Rectangle( + client_rectangle.X + (month_size.Width * i) + (calendar_spacing.Width * (i - 1)) + 1, + client_rectangle.Y, + calendar_spacing.Width, + client_rectangle.Height); + if (i < mc.CalendarDimensions.Width && i > 0 && clip_rectangle.IntersectsWith(rect)) + { + dc.FillRectangle(border_brush, rect); + } + } + } + for (int i = 0; i <= mc.CalendarDimensions.Height; i++) + { + if (i == 0 && clip_rectangle.Y == client_rectangle.Y) + { + dc.FillRectangle(border_brush, client_rectangle.X, client_rectangle.Y, client_rectangle.Width, 1); + } + else if (i == mc.CalendarDimensions.Height && clip_rectangle.Bottom == client_rectangle.Bottom) + { + dc.FillRectangle(border_brush, client_rectangle.X, client_rectangle.Bottom - 1, client_rectangle.Width, 1); + } + else + { + Rectangle rect = new Rectangle( + client_rectangle.X, + client_rectangle.Y + (month_size.Height * i) + (calendar_spacing.Height * (i - 1)) + 1, + client_rectangle.Width, + calendar_spacing.Height); + if (i < mc.CalendarDimensions.Height && i > 0 && clip_rectangle.IntersectsWith(rect)) + { + dc.FillRectangle(border_brush, rect); + } + } + } + + // draw the drop down border if need + if (mc.owner != null) + { + Rectangle bounds = mc.ClientRectangle; + if (clip_rectangle.Contains(mc.Location)) + { + // find out if top or left line to draw + if (clip_rectangle.Contains(new Point(bounds.Left, bounds.Bottom))) + { + + dc.DrawLine(SystemPens.ControlText, bounds.X, bounds.Y, bounds.X, bounds.Bottom - 1); + } + if (clip_rectangle.Contains(new Point(bounds.Right, bounds.Y))) + { + dc.DrawLine(SystemPens.ControlText, bounds.X, bounds.Y, bounds.Right - 1, bounds.Y); + } + } + if (clip_rectangle.Contains(new Point(bounds.Right, bounds.Bottom))) + { + // find out if bottom or right line to draw + if (clip_rectangle.Contains(new Point(bounds.Left, bounds.Bottom))) + { + dc.DrawLine(SystemPens.ControlText, bounds.X, bounds.Bottom - 1, bounds.Right - 1, bounds.Bottom - 1); + } + if (clip_rectangle.Contains(new Point(bounds.Right, bounds.Y))) + { + dc.DrawLine(SystemPens.ControlText, bounds.Right - 1, bounds.Y, bounds.Right - 1, bounds.Bottom - 1); + } + } + } + } + + // darws a single part of the month calendar (with one month) + private void DrawSingleMonth(Graphics dc, Rectangle clip_rectangle, Rectangle rectangle, MonthCalendar mc, int row, int col) + { + // cache local copies of Marshal-by-ref internal members (gets around error CS0197) + Size title_size = (Size)((object)mc.title_size); + Size date_cell_size = (Size)((object)mc.date_cell_size); + DateTime current_month = (DateTime)((object)mc.current_month); + DateTime sunday = new DateTime(2006, 10, 1); + + // draw the title back ground + DateTime this_month = current_month.AddMonths(row * mc.CalendarDimensions.Width + col); + Rectangle title_rect = new Rectangle(rectangle.X, rectangle.Y, title_size.Width, title_size.Height); + if (title_rect.IntersectsWith(clip_rectangle)) + { + dc.FillRectangle(ResPool.GetSolidBrush(mc.TitleBackColor), title_rect); + // draw the title + string title_text = this_month.ToString("MMMM yyyy"); + dc.DrawString(title_text, mc.bold_font, ResPool.GetSolidBrush(mc.TitleForeColor), title_rect, mc.centered_format); + + if (mc.ShowYearUpDown) + { + Rectangle year_rect; + Rectangle upRect, downRect; + ButtonState upState, downState; + + mc.GetYearNameRectangles(title_rect, row * mc.CalendarDimensions.Width + col, out year_rect, out upRect, out downRect); + dc.FillRectangle(ResPool.GetSolidBrush(SystemColors.Control), year_rect); + dc.DrawString(this_month.ToString("yyyy"), mc.bold_font, ResPool.GetSolidBrush(Color.Black), year_rect, mc.centered_format); + + upState = mc.IsYearGoingUp ? ButtonState.Pushed : ButtonState.Normal; + downState = mc.IsYearGoingDown ? ButtonState.Pushed : ButtonState.Normal; + + WidgetPaint.DrawScrollButton(dc, upRect, ScrollButton.Up, upState); + WidgetPaint.DrawScrollButton(dc, downRect, ScrollButton.Down, downState); + } + + // draw previous and next buttons if it's time + if (row == 0 && col == 0) + { + // draw previous button + DrawMonthCalendarButton( + dc, + rectangle, + mc, + title_size, + mc.button_x_offset, + (System.Drawing.Size)((object)mc.button_size), + true); + } + if (row == 0 && col == mc.CalendarDimensions.Width - 1) + { + // draw next button + DrawMonthCalendarButton( + dc, + rectangle, + mc, + title_size, + mc.button_x_offset, + (System.Drawing.Size)((object)mc.button_size), + false); + } + } + + // set the week offset and draw week nums if needed + int col_offset = (mc.ShowWeekNumbers) ? 1 : 0; + Rectangle day_name_rect = new Rectangle( + rectangle.X, + rectangle.Y + title_size.Height, + (7 + col_offset) * date_cell_size.Width, + date_cell_size.Height); + if (day_name_rect.IntersectsWith(clip_rectangle)) + { + dc.FillRectangle(GetControlBackBrush(mc.BackColor), day_name_rect); + // draw the day names + DayOfWeek first_day_of_week = mc.GetDayOfWeek(mc.FirstDayOfWeek); + for (int i = 0; i < 7; i++) + { + int position = i - (int)first_day_of_week; + if (position < 0) + { + position = 7 + position; + } + // draw it + Rectangle day_rect = new Rectangle( + day_name_rect.X + ((i + col_offset) * date_cell_size.Width), + day_name_rect.Y, + date_cell_size.Width, + date_cell_size.Height); + dc.DrawString(sunday.AddDays(i + (int)first_day_of_week).ToString("ddd"), mc.Font, ResPool.GetSolidBrush(mc.TitleBackColor), day_rect, mc.centered_format); + } + + // draw the vertical divider + int vert_divider_y = Math.Max(title_size.Height + date_cell_size.Height - 1, 0); + dc.DrawLine( + ResPool.GetPen(mc.ForeColor), + rectangle.X + (col_offset * date_cell_size.Width) + mc.divider_line_offset, + rectangle.Y + vert_divider_y, + rectangle.Right - mc.divider_line_offset, + rectangle.Y + vert_divider_y); + } + + + // draw the actual date items in the grid (including the week numbers) + Rectangle date_rect = new Rectangle( + rectangle.X, + rectangle.Y + title_size.Height + date_cell_size.Height, + date_cell_size.Width, + date_cell_size.Height); + int month_row_count = 0; + bool draw_week_num_divider = false; + DateTime current_date = mc.GetFirstDateInMonthGrid(new DateTime(this_month.Year, this_month.Month, 1)); + for (int i = 0; i < 6; i++) + { + // establish if this row is in our clip_area + Rectangle row_rect = new Rectangle( + rectangle.X, + rectangle.Y + title_size.Height + (date_cell_size.Height * (i + 1)), + date_cell_size.Width * 7, + date_cell_size.Height); + if (mc.ShowWeekNumbers) + { + row_rect.Width += date_cell_size.Width; + } + + bool draw_row = row_rect.IntersectsWith(clip_rectangle); + if (draw_row) + { + dc.FillRectangle(GetControlBackBrush(mc.BackColor), row_rect); + } + // establish if this is a valid week to draw + if (mc.IsValidWeekToDraw(this_month, current_date, row, col)) + { + month_row_count = i; + } + + // draw the week number if required + if (mc.ShowWeekNumbers && month_row_count == i) + { + if (!draw_week_num_divider) + { + draw_week_num_divider = draw_row; + } + // get the week for this row + int week = mc.GetWeekOfYear(current_date); + + if (draw_row) + { + dc.DrawString( + week.ToString(), + mc.Font, + ResPool.GetSolidBrush(mc.TitleBackColor), + date_rect, + mc.centered_format); + } + date_rect.Offset(date_cell_size.Width, 0); + } + + // only draw the days if we have to + if (month_row_count == i) + { + for (int j = 0; j < 7; j++) + { + if (draw_row) + { + DrawMonthCalendarDate( + dc, + date_rect, + mc, + current_date, + this_month, + row, + col); + } + + // move the day on + current_date = current_date.AddDays(1); + date_rect.Offset(date_cell_size.Width, 0); + } + + // shift the rectangle down one row + int offset = (mc.ShowWeekNumbers) ? -8 : -7; + date_rect.Offset(offset * date_cell_size.Width, date_cell_size.Height); + } + } + + // month_row_count is zero based, so add one + month_row_count++; + + // draw week numbers if required + if (draw_week_num_divider) + { + col_offset = 1; + dc.DrawLine( + ResPool.GetPen(mc.ForeColor), + rectangle.X + date_cell_size.Width - 1, + rectangle.Y + title_size.Height + date_cell_size.Height + mc.divider_line_offset, + rectangle.X + date_cell_size.Width - 1, + rectangle.Y + title_size.Height + date_cell_size.Height + (month_row_count * date_cell_size.Height) - mc.divider_line_offset); + } + } + + // draws the pervious or next button + private void DrawMonthCalendarButton(Graphics dc, Rectangle rectangle, MonthCalendar mc, Size title_size, int x_offset, Size button_size, bool is_previous) + { + const int arrow_width = 4; + const int arrow_height = 7; + + bool is_clicked = false; + Rectangle button_rect; + PointF arrow_center; + PointF[] arrow_path = new PointF[3]; + + // prepare the button + if (is_previous) + { + is_clicked = mc.is_previous_clicked; + + button_rect = new Rectangle( + rectangle.X + 1 + x_offset, + rectangle.Y + 1 + ((title_size.Height - button_size.Height) / 2), + Math.Max(button_size.Width - 1, 0), + Math.Max(button_size.Height - 1, 0)); + + arrow_center = new PointF(button_rect.X + ((button_rect.Width + arrow_width) / 2.0f), + rectangle.Y + ((button_rect.Height + arrow_height) / 2) + 1); + if (is_clicked) + { + arrow_center.X += 1; + arrow_center.Y += 1; + } + + arrow_path[0].X = arrow_center.X; + arrow_path[0].Y = arrow_center.Y - arrow_height / 2.0f + 0.5f; + arrow_path[1].X = arrow_center.X; + arrow_path[1].Y = arrow_center.Y + arrow_height / 2.0f + 0.5f; + arrow_path[2].X = arrow_center.X - arrow_width; + arrow_path[2].Y = arrow_center.Y + 0.5f; + } + else + { + is_clicked = mc.is_next_clicked; + + button_rect = new Rectangle( + rectangle.Right - 1 - x_offset - button_size.Width, + rectangle.Y + 1 + ((title_size.Height - button_size.Height) / 2), + Math.Max(button_size.Width - 1, 0), + Math.Max(button_size.Height - 1, 0)); + + arrow_center = new PointF(button_rect.X + ((button_rect.Width + arrow_width) / 2.0f), + rectangle.Y + ((button_rect.Height + arrow_height) / 2) + 1); + if (is_clicked) + { + arrow_center.X += 1; + arrow_center.Y += 1; + } + + arrow_path[0].X = arrow_center.X - arrow_width; + arrow_path[0].Y = arrow_center.Y - arrow_height / 2.0f + 0.5f; + arrow_path[1].X = arrow_center.X - arrow_width; + arrow_path[1].Y = arrow_center.Y + arrow_height / 2.0f + 0.5f; + arrow_path[2].X = arrow_center.X; + arrow_path[2].Y = arrow_center.Y + 0.5f; + } + + // fill the background + dc.FillRectangle(SystemBrushes.Control, button_rect); + // draw the border + if (is_clicked) + { + dc.DrawRectangle(SystemPens.ControlDark, button_rect); + } + else + { + CPDrawBorder3D(dc, button_rect, Border3DStyle.Raised, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom); + } + // draw the arrow + dc.FillPolygon(SystemBrushes.ControlText, arrow_path); + //dc.FillPolygon (SystemBrushes.ControlText, arrow_path, FillMode.Winding); + } + + + // draws one day in the calendar grid + private void DrawMonthCalendarDate(Graphics dc, Rectangle rectangle, MonthCalendar mc, DateTime date, DateTime month, int row, int col) + { + Color date_color = mc.ForeColor; + Rectangle interior = new Rectangle(rectangle.X, rectangle.Y, Math.Max(rectangle.Width - 1, 0), Math.Max(rectangle.Height - 1, 0)); + + // find out if we are the lead of the first calendar or the trail of the last calendar + if (date.Year != month.Year || date.Month != month.Month) + { + DateTime check_date = month.AddMonths(-1); + // check if it's the month before + if (check_date.Year == date.Year && check_date.Month == date.Month && row == 0 && col == 0) + { + date_color = mc.TrailingForeColor; + } + else + { + // check if it's the month after + check_date = month.AddMonths(1); + if (check_date.Year == date.Year && check_date.Month == date.Month && row == mc.CalendarDimensions.Height - 1 && col == mc.CalendarDimensions.Width - 1) + { + date_color = mc.TrailingForeColor; + } + else + { + return; + } + } + } + else + { + date_color = mc.ForeColor; + } + + const int inflate = -1; + + if (date == mc.SelectionStart.Date && date == mc.SelectionEnd.Date) + { + // see if the date is in the start of selection + date_color = mc.BackColor; + // draw the left hand of the back ground + Rectangle selection_rect = Rectangle.Inflate(rectangle, inflate, inflate); + dc.FillPie(ResPool.GetSolidBrush(mc.TitleBackColor), selection_rect, 0, 360); + } + else if (date == mc.SelectionStart.Date) + { + // see if the date is in the start of selection + date_color = mc.BackColor; + // draw the left hand of the back ground + Rectangle selection_rect = Rectangle.Inflate(rectangle, inflate, inflate); + dc.FillPie(ResPool.GetSolidBrush(mc.TitleBackColor), selection_rect, 90, 180); + // fill the other side as a straight rect + if (date < mc.SelectionEnd.Date) + { + // use rectangle instead of rectangle to go all the way to edge of rect + selection_rect.X = (int)Math.Floor((double)(rectangle.X + rectangle.Width / 2)); + selection_rect.Width = Math.Max(rectangle.Right - selection_rect.X, 0); + dc.FillRectangle(ResPool.GetSolidBrush(mc.TitleBackColor), selection_rect); + } + } + else if (date == mc.SelectionEnd.Date) + { + // see if it is the end of selection + date_color = mc.BackColor; + // draw the left hand of the back ground + Rectangle selection_rect = Rectangle.Inflate(rectangle, inflate, inflate); + dc.FillPie(ResPool.GetSolidBrush(mc.TitleBackColor), selection_rect, 270, 180); + // fill the other side as a straight rect + if (date > mc.SelectionStart.Date) + { + selection_rect.X = rectangle.X; + selection_rect.Width = rectangle.Width - (rectangle.Width / 2); + dc.FillRectangle(ResPool.GetSolidBrush(mc.TitleBackColor), selection_rect); + } + } + else if (date > mc.SelectionStart.Date && date < mc.SelectionEnd.Date) + { + // now see if it's in the middle + date_color = mc.BackColor; + // draw the left hand of the back ground + Rectangle selection_rect = Rectangle.Inflate(rectangle, 0, inflate); + dc.FillRectangle(ResPool.GetSolidBrush(mc.TitleBackColor), selection_rect); + } + + // establish if it's a bolded font + Font font = mc.IsBoldedDate(date) ? mc.bold_font : mc.Font; + + // just draw the date now + dc.DrawString(date.Day.ToString(), font, ResPool.GetSolidBrush(date_color), rectangle, mc.centered_format); + + // today circle if needed + if (mc.ShowTodayCircle && date == DateTime.Now.Date) + { + DrawTodayCircle(dc, interior); + } + + // draw the selection grid + if (mc.is_date_clicked && mc.clicked_date == date) + { + Pen pen = ResPool.GetDashPen(Color.Black, DashStyle.Dot); + dc.DrawRectangle(pen, interior); + } + } + + private void DrawTodayCircle(Graphics dc, Rectangle rectangle) + { + Color circle_color = Color.FromArgb(248, 0, 0); + // draw the left hand of the circle + Rectangle lhs_circle_rect = new Rectangle(rectangle.X + 1, rectangle.Y + 4, Math.Max(rectangle.Width - 2, 0), Math.Max(rectangle.Height - 5, 0)); + Rectangle rhs_circle_rect = new Rectangle(rectangle.X + 1, rectangle.Y + 1, Math.Max(rectangle.Width - 2, 0), Math.Max(rectangle.Height - 2, 0)); + Point[] curve_points = new Point[3]; + curve_points[0] = new Point(lhs_circle_rect.X, rhs_circle_rect.Y + rhs_circle_rect.Height / 12); + curve_points[1] = new Point(lhs_circle_rect.X + lhs_circle_rect.Width / 9, rhs_circle_rect.Y); + curve_points[2] = new Point(lhs_circle_rect.X + lhs_circle_rect.Width / 2 + 1, rhs_circle_rect.Y); + + Pen pen = ResPool.GetSizedPen(circle_color, 2); + dc.DrawArc(pen, lhs_circle_rect, 90, 180); + dc.DrawArc(pen, rhs_circle_rect, 270, 180); + dc.DrawCurve(pen, curve_points); + dc.DrawLine(ResPool.GetPen(circle_color), curve_points[2], new Point(curve_points[2].X, lhs_circle_rect.Y)); + } + + #endregion // MonthCalendar + + #region Panel + public override Size PanelDefaultSize + { + get + { + return new Size(200, 100); + } + } + #endregion // Panel + + #region PictureBox + public override void DrawPictureBox(Graphics dc, Rectangle clip, PictureBox pb) + { + Rectangle client = pb.ClientRectangle; + + client = new Rectangle(client.Left + pb.Padding.Left, client.Top + pb.Padding.Top, client.Width - pb.Padding.Horizontal, client.Height - pb.Padding.Vertical); + + // FIXME - instead of drawing the whole picturebox every time + // intersect the clip rectangle with the drawn picture and only draw what's needed, + // Also, we only need a background fill where no image goes + if (pb.Image != null) + { + switch (pb.SizeMode) + { + case PictureBoxSizeMode.StretchImage: + dc.DrawImage(pb.Image, client.Left, client.Top, client.Width, client.Height); + break; + + case PictureBoxSizeMode.CenterImage: + dc.DrawImage(pb.Image, (client.Width / 2) - (pb.Image.Width / 2), (client.Height / 2) - (pb.Image.Height / 2)); + break; + + case PictureBoxSizeMode.Zoom: + Size image_size; + + if (((float)pb.Image.Width / (float)pb.Image.Height) >= ((float)client.Width / (float)client.Height)) + image_size = new Size(client.Width, (pb.Image.Height * client.Width) / pb.Image.Width); + else + image_size = new Size((pb.Image.Width * client.Height) / pb.Image.Height, client.Height); + + dc.DrawImage(pb.Image, (client.Width / 2) - (image_size.Width / 2), (client.Height / 2) - (image_size.Height / 2), image_size.Width, image_size.Height); + break; + + default: + // Normal, AutoSize + dc.DrawImage(pb.Image, client.Left, client.Top, pb.Image.Width, pb.Image.Height); + break; + } + + return; + } + } + + public override Size PictureBoxDefaultSize + { + get + { + return new Size(100, 50); + } + } + #endregion // PictureBox + + /* + #region PrintPreviewControl + public override int PrintPreviewControlPadding { + get { return 8; } + } + + public override Size PrintPreviewControlGetPageSize (PrintPreviewControl preview) + { + int page_width, page_height; + int padding = PrintPreviewControlPadding; + PreviewPageInfo[] pis = preview.page_infos; + + if (preview.AutoZoom) { + int height_available = preview.ClientRectangle.Height - (preview.Rows) * padding - 2 * padding; + int width_available = preview.ClientRectangle.Width - (preview.Columns - 1) * padding - 2 * padding; + + float image_ratio = (float)pis[0].Image.Width / pis[0].Image.Height; + + /* try to lay things out using the width to determine the size + page_width = width_available / preview.Columns; + page_height = (int)(page_width / image_ratio); + + /* does the height fit? + if (page_height * (preview.Rows + 1) > height_available) { + /* no, lay things out via the height + page_height = height_available / (preview.Rows + 1); + page_width = (int)(page_height * image_ratio); + } + } + else { + page_width = (int)(pis[0].Image.Width * preview.Zoom); + page_height = (int)(pis[0].Image.Height * preview.Zoom); + } + + return new Size (page_width, page_height); + } + + public override void PrintPreviewWidgetPaint (PaintEventArgs pe, PrintPreviewControl preview, Size page_size) + { + int padding = 8; + PreviewPageInfo[] pis = preview.page_infos; + if (pis == null) + return; + + int page_x, page_y; + + int width = page_size.Width * preview.Columns + padding * (preview.Columns - 1) + 2 * padding; + int height = page_size.Height * (preview.Rows + 1) + padding * preview.Rows + 2 * padding; + + Rectangle viewport = preview.ViewPort; + + pe.Graphics.Clip = new Region (viewport); + + /* center things if we can + int off_x = viewport.Width / 2 - width / 2; + if (off_x < 0) off_x = 0; + int off_y = viewport.Height / 2 - height / 2; + if (off_y < 0) off_y = 0; + + page_y = off_y + padding - preview.vbar_value; + + if (preview.StartPage > 0) { + int p = preview.StartPage - 1; + for (int py = 0; py < preview.Rows + 1; py ++) { + page_x = off_x + padding - preview.hbar_value; + for (int px = 0; px < preview.Columns; px ++) { + if (p >= pis.Length) + continue; + Image image = preview.image_cache[p]; + if (image == null) + image = pis[p].Image; + Rectangle dest = new Rectangle (new Point (page_x, page_y), page_size); + + pe.Graphics.DrawImage (image, dest, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel); + + page_x += padding + page_size.Width; + p++; + } + page_y += padding + page_size.Height; + } + } + } + #endregion // PrintPreviewControl*/ + + #region ProgressBar + public override void DrawProgressBar(Graphics dc, Rectangle clip_rect, ProgressBar ctrl) + { + Rectangle client_area = ctrl.client_area; + + /* Draw border */ + CPDrawBorder3D(dc, ctrl.ClientRectangle, Border3DStyle.SunkenOuter, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom & ~Border3DSide.Middle, ColorControl); + + /* Draw Blocks */ + int draw_mode = 0; + int max_blocks = int.MaxValue; + int start_pixel = client_area.X; + draw_mode = (int)ctrl.Style; + + switch (draw_mode) + { + case 1: + { // Continuous + int pixels_to_draw; + pixels_to_draw = (int)(client_area.Width * ((double)(ctrl.Value - ctrl.Minimum) / (double)(Math.Max(ctrl.Maximum - ctrl.Minimum, 1)))); + dc.FillRectangle(new SolidBrush(Application.CurrentSkin.ProgressBar_BackgroundColor), new Rectangle(client_area.X, client_area.Y, pixels_to_draw, client_area.Height)); + break; + } + case 2: // Marquee + if (XplatUI.ThemesEnabled) + { + int ms_diff = (int)(DateTime.Now - ctrl.start).TotalMilliseconds; + double percent_done = (double)ms_diff / ProgressBarMarqueeSpeedScaling + % (double)ctrl.MarqueeAnimationSpeed / (double)ctrl.MarqueeAnimationSpeed; + max_blocks = 5; + start_pixel = client_area.X + (int)(client_area.Width * percent_done); + } + + goto case 0; + case 0: + default: // Blocks + Rectangle block_rect; + int space_betweenblocks = ProgressBarChunkSpacing; + int block_width; + int increment; + int barpos_pixels; + int block_count = 0; + + block_width = ProgressBarGetChunkSize(client_area.Height); + block_width = Math.Max(block_width, 0); // block_width is used to break out the loop below, it must be >= 0! + barpos_pixels = (int)(((double)(ctrl.Value - ctrl.Minimum) * client_area.Width) / (Math.Max(ctrl.Maximum - ctrl.Minimum, 1))); + increment = block_width + space_betweenblocks; + + block_rect = new Rectangle(start_pixel, client_area.Y, block_width, client_area.Height); + while (true) + { + if (max_blocks != int.MaxValue) + { + if (block_count >= max_blocks) + break; + if (block_rect.X > client_area.Width) + block_rect.X -= client_area.Width; + } + else + { + if ((block_rect.X - client_area.X) >= barpos_pixels) + break; + } + + if (clip_rect.IntersectsWith(block_rect) == true) + { + dc.FillRectangle(new SolidBrush(Application.CurrentSkin.ProgressBar_BlockColor), block_rect); + } + + block_rect.X += increment; + block_count++; + } + break; + + } + } + + public const int ProgressBarChunkSpacing = 2; + + public static int ProgressBarGetChunkSize() + { + return ProgressBarGetChunkSize(ProgressBarDefaultHeight); + } + + static int ProgressBarGetChunkSize(int progressBarClientAreaHeight) + { + int size = (progressBarClientAreaHeight * 2) / 3; + return size; + } + + const int ProgressBarDefaultHeight = 23; + + public override Size ProgressBarDefaultSize + { + get + { + return new Size(100, ProgressBarDefaultHeight); + } + } + + public const double ProgressBarMarqueeSpeedScaling = 15; + + #endregion // ProgressBar + + #region RadioButton + public override void DrawRadioButton(Graphics dc, Rectangle clip_rectangle, RadioButton radio_button) + { + StringFormat text_format; + Rectangle client_rectangle; + Rectangle text_rectangle; + Rectangle radiobutton_rectangle; + int radiobutton_size = 13; + int radiobutton_space = 4; + + client_rectangle = radio_button.ClientRectangle; + text_rectangle = client_rectangle; + radiobutton_rectangle = new Rectangle(text_rectangle.X, text_rectangle.Y, radiobutton_size, radiobutton_size); + + text_format = new StringFormat(); + text_format.Alignment = StringAlignment.Near; + text_format.LineAlignment = StringAlignment.Center; + text_format.HotkeyPrefix = HotkeyPrefix.Show; + + /* Calculate the position of text and checkbox rectangle */ + if (radio_button.appearance != Appearance.Button) + { + switch (radio_button.radiobutton_alignment) + { + case ContentAlignment.BottomCenter: + { + radiobutton_rectangle.X = (client_rectangle.Right - client_rectangle.Left) / 2 - radiobutton_size / 2; + radiobutton_rectangle.Y = client_rectangle.Bottom - radiobutton_size; + text_rectangle.X = client_rectangle.X; + text_rectangle.Width = client_rectangle.Width; + text_rectangle.Height = client_rectangle.Height - radiobutton_size - radiobutton_space; + break; + } + + case ContentAlignment.BottomLeft: + { + radiobutton_rectangle.X = client_rectangle.Left; + radiobutton_rectangle.Y = client_rectangle.Bottom - radiobutton_size; + text_rectangle.X = client_rectangle.X + radiobutton_size + radiobutton_space; + text_rectangle.Width = client_rectangle.Width - radiobutton_size - radiobutton_space; + break; + } + + case ContentAlignment.BottomRight: + { + radiobutton_rectangle.X = client_rectangle.Right - radiobutton_size; + radiobutton_rectangle.Y = client_rectangle.Bottom - radiobutton_size; + text_rectangle.X = client_rectangle.X; + text_rectangle.Width = client_rectangle.Width - radiobutton_size - radiobutton_space; + break; + } + + case ContentAlignment.MiddleCenter: + { + radiobutton_rectangle.X = (client_rectangle.Right - client_rectangle.Left) / 2 - radiobutton_size / 2; + radiobutton_rectangle.Y = (client_rectangle.Bottom - client_rectangle.Top) / 2 - radiobutton_size / 2; + text_rectangle.X = client_rectangle.X; + text_rectangle.Width = client_rectangle.Width; + break; + } + + default: + case ContentAlignment.MiddleLeft: + { + radiobutton_rectangle.X = client_rectangle.Left; + radiobutton_rectangle.Y = (client_rectangle.Bottom - client_rectangle.Top) / 2 - radiobutton_size / 2; + text_rectangle.X = client_rectangle.X + radiobutton_size + radiobutton_space; + text_rectangle.Width = client_rectangle.Width - radiobutton_size - radiobutton_space; + break; + } + + case ContentAlignment.MiddleRight: + { + radiobutton_rectangle.X = client_rectangle.Right - radiobutton_size; + radiobutton_rectangle.Y = (client_rectangle.Bottom - client_rectangle.Top) / 2 - radiobutton_size / 2; + text_rectangle.X = client_rectangle.X; + text_rectangle.Width = client_rectangle.Width - radiobutton_size - radiobutton_space; + break; + } + + case ContentAlignment.TopCenter: + { + radiobutton_rectangle.X = (client_rectangle.Right - client_rectangle.Left) / 2 - radiobutton_size / 2; + radiobutton_rectangle.Y = client_rectangle.Top; + text_rectangle.X = client_rectangle.X; + text_rectangle.Y = radiobutton_size + radiobutton_space; + text_rectangle.Width = client_rectangle.Width; + text_rectangle.Height = client_rectangle.Height - radiobutton_size - radiobutton_space; + break; + } + + case ContentAlignment.TopLeft: + { + radiobutton_rectangle.X = client_rectangle.Left; + radiobutton_rectangle.Y = client_rectangle.Top; + text_rectangle.X = client_rectangle.X + radiobutton_size + radiobutton_space; + text_rectangle.Width = client_rectangle.Width - radiobutton_size - radiobutton_space; + break; + } + + case ContentAlignment.TopRight: + { + radiobutton_rectangle.X = client_rectangle.Right - radiobutton_size; + radiobutton_rectangle.Y = client_rectangle.Top; + text_rectangle.X = client_rectangle.X; + text_rectangle.Width = client_rectangle.Width - radiobutton_size - radiobutton_space; + break; + } + } + } + else + { + text_rectangle.X = client_rectangle.X; + text_rectangle.Width = client_rectangle.Width; + } + + /* Set the horizontal alignment of our text */ + switch (radio_button.text_alignment) + { + case ContentAlignment.BottomLeft: + case ContentAlignment.MiddleLeft: + case ContentAlignment.TopLeft: + { + text_format.Alignment = StringAlignment.Near; + break; + } + + case ContentAlignment.BottomCenter: + case ContentAlignment.MiddleCenter: + case ContentAlignment.TopCenter: + { + text_format.Alignment = StringAlignment.Center; + break; + } + + case ContentAlignment.BottomRight: + case ContentAlignment.MiddleRight: + case ContentAlignment.TopRight: + { + text_format.Alignment = StringAlignment.Far; + break; + } + } + + /* Set the vertical alignment of our text */ + switch (radio_button.text_alignment) + { + case ContentAlignment.TopLeft: + case ContentAlignment.TopCenter: + case ContentAlignment.TopRight: + { + text_format.LineAlignment = StringAlignment.Near; + break; + } + + case ContentAlignment.BottomLeft: + case ContentAlignment.BottomCenter: + case ContentAlignment.BottomRight: + { + text_format.LineAlignment = StringAlignment.Far; + break; + } + + case ContentAlignment.MiddleLeft: + case ContentAlignment.MiddleCenter: + case ContentAlignment.MiddleRight: + { + text_format.LineAlignment = StringAlignment.Center; + break; + } + } + + ButtonState state = ButtonState.Normal; + if (radio_button.FlatStyle == FlatStyle.Flat) + { + state |= ButtonState.Flat; + } + + if (radio_button.Checked) + { + state |= ButtonState.Checked; + } + + if (!radio_button.Enabled) + { + state |= ButtonState.Inactive; + } + + // Start drawing + RadioButton_DrawButton(radio_button, dc, state, radiobutton_rectangle); + + if ((radio_button.image != null) || (radio_button.image_list != null)) + ButtonBase_DrawImage(radio_button, dc); + + RadioButton_DrawText(radio_button, text_rectangle, dc, text_format); + + if (radio_button.Focused && radio_button.Enabled && radio_button.appearance != Appearance.Button && radio_button.Text != String.Empty && radio_button.ShowFocusCues) + { + SizeF text_size = dc.MeasureString(radio_button.Text, radio_button.Font); + + Rectangle focus_rect = Rectangle.Empty; + focus_rect.X = text_rectangle.X; + focus_rect.Y = (int)((text_rectangle.Height - text_size.Height) / 2); + focus_rect.Size = text_size.ToSize(); + + RadioButton_DrawFocus(radio_button, dc, focus_rect); + } + + text_format.Dispose(); + } + + protected virtual void RadioButton_DrawButton(RadioButton radio_button, Graphics dc, ButtonState state, Rectangle radiobutton_rectangle) + { + dc.FillRectangle(GetControlBackBrush(radio_button.BackColor), radio_button.ClientRectangle); + + if (radio_button.appearance == Appearance.Button) + { + ButtonBase_DrawButton(radio_button, dc); + + if ((radio_button.Focused) && radio_button.Enabled) + ButtonBase_DrawFocus(radio_button, dc); + } + else + { + // establish if we are rendering a flat style of some sort + if (radio_button.FlatStyle == FlatStyle.Flat || radio_button.FlatStyle == FlatStyle.Popup) + { + DrawFlatStyleRadioButton(dc, radiobutton_rectangle, radio_button); + } + else + { + CPDrawRadioButton(dc, radiobutton_rectangle, state); + } + } + } + + protected virtual void RadioButton_DrawText(RadioButton radio_button, Rectangle text_rectangle, Graphics dc, StringFormat text_format) + { + DrawCheckBox_and_RadioButtonText(radio_button, text_rectangle, dc, + text_format, radio_button.Appearance, radio_button.Checked); + } + + protected virtual void RadioButton_DrawFocus(RadioButton radio_button, Graphics dc, Rectangle text_rectangle) + { + DrawInnerFocusRectangle(dc, text_rectangle, radio_button.BackColor); + } + + + // renders a radio button with the Flat and Popup FlatStyle + protected virtual void DrawFlatStyleRadioButton(Graphics graphics, Rectangle rectangle, RadioButton radio_button) + { + int lineWidth; + + if (radio_button.Enabled) + { + + // draw the outer flatstyle arcs + if (radio_button.FlatStyle == FlatStyle.Flat) + { + graphics.DrawArc(SystemPens.ControlDarkDark, rectangle, 0, 359); + + // fill in the area depending on whether or not the mouse is hovering + if ((radio_button.is_entered || radio_button.Capture) && !radio_button.is_pressed) + { + graphics.FillPie(SystemBrushes.ControlLight, rectangle.X + 1, rectangle.Y + 1, rectangle.Width - 2, rectangle.Height - 2, 0, 359); + } + else + { + graphics.FillPie(SystemBrushes.ControlLightLight, rectangle.X + 1, rectangle.Y + 1, rectangle.Width - 2, rectangle.Height - 2, 0, 359); + } + } + else + { + // must be a popup radio button + // fill the control + graphics.FillPie(SystemBrushes.ControlLightLight, rectangle, 0, 359); + + if (radio_button.is_entered || radio_button.Capture) + { + // draw the popup 3d button knob + graphics.DrawArc(SystemPens.ControlLight, rectangle.X + 1, rectangle.Y + 1, rectangle.Width - 2, rectangle.Height - 2, 0, 359); + + graphics.DrawArc(SystemPens.ControlDark, rectangle, 135, 180); + graphics.DrawArc(SystemPens.ControlLightLight, rectangle, 315, 180); + + } + else + { + // just draw lighter flatstyle outer circle + graphics.DrawArc(SystemPens.ControlDark, rectangle, 0, 359); + } + } + } + else + { + // disabled + // fill control background color regardless of actual backcolor + graphics.FillPie(SystemBrushes.Control, rectangle.X + 1, rectangle.Y + 1, rectangle.Width - 2, rectangle.Height - 2, 0, 359); + // draw the ark as control dark + graphics.DrawArc(SystemPens.ControlDark, rectangle, 0, 359); + } + + // draw the check + if (radio_button.Checked) + { + lineWidth = Math.Max(1, Math.Min(rectangle.Width, rectangle.Height) / 3); + + Pen dot_pen = SystemPens.ControlDarkDark; + Brush dot_brush = SystemBrushes.ControlDarkDark; + + if (!radio_button.Enabled || ((radio_button.FlatStyle == FlatStyle.Popup) && radio_button.is_pressed)) + { + dot_pen = SystemPens.ControlDark; + dot_brush = SystemBrushes.ControlDark; + } + + if (rectangle.Height > 13) + { + graphics.FillPie(dot_brush, rectangle.X + lineWidth, rectangle.Y + lineWidth, rectangle.Width - lineWidth * 2, rectangle.Height - lineWidth * 2, 0, 359); + } + else + { + int x_half_pos = (rectangle.Width / 2) + rectangle.X; + int y_half_pos = (rectangle.Height / 2) + rectangle.Y; + + graphics.DrawLine(dot_pen, x_half_pos - 1, y_half_pos, x_half_pos + 2, y_half_pos); + graphics.DrawLine(dot_pen, x_half_pos - 1, y_half_pos + 1, x_half_pos + 2, y_half_pos + 1); + + graphics.DrawLine(dot_pen, x_half_pos, y_half_pos - 1, x_half_pos, y_half_pos + 2); + graphics.DrawLine(dot_pen, x_half_pos + 1, y_half_pos - 1, x_half_pos + 1, y_half_pos + 2); + } + } + } + + public override Size RadioButtonDefaultSize + { + get + { + return new Size(104, 24); + } + } + + public override void DrawRadioButton(Graphics g, RadioButton rb, Rectangle glyphArea, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle) + { + // Draw Button Background + if (rb.FlatStyle == FlatStyle.Flat || rb.FlatStyle == FlatStyle.Popup) + { + glyphArea.Height -= 2; + glyphArea.Width -= 2; + } + + DrawRadioButtonGlyph(g, rb, glyphArea); + + // If we have an image, draw it + if (imageBounds.Size != Size.Empty) + DrawRadioButtonImage(g, rb, imageBounds); + + if (rb.Focused && rb.Enabled && rb.ShowFocusCues && textBounds.Size != Size.Empty) + DrawRadioButtonFocus(g, rb, textBounds); + + // If we have text, draw it + if (textBounds != Rectangle.Empty) + DrawRadioButtonText(g, rb, textBounds); + } + + public virtual void DrawRadioButtonGlyph(Graphics g, RadioButton rb, Rectangle glyphArea) + { + if (rb.Pressed) + MemphisThemeElements.CurrentTheme.RadioButtonPainter.PaintRadioButton(g, glyphArea, rb.BackColor, rb.ForeColor, ElementState.Pressed, rb.FlatStyle, rb.Checked); + else if (rb.InternalSelected) + MemphisThemeElements.CurrentTheme.RadioButtonPainter.PaintRadioButton(g, glyphArea, rb.BackColor, rb.ForeColor, ElementState.Normal, rb.FlatStyle, rb.Checked); + else if (rb.Entered) + MemphisThemeElements.CurrentTheme.RadioButtonPainter.PaintRadioButton(g, glyphArea, rb.BackColor, rb.ForeColor, ElementState.Hot, rb.FlatStyle, rb.Checked); + else if (!rb.Enabled) + MemphisThemeElements.CurrentTheme.RadioButtonPainter.PaintRadioButton(g, glyphArea, rb.BackColor, rb.ForeColor, ElementState.Disabled, rb.FlatStyle, rb.Checked); + else + MemphisThemeElements.CurrentTheme.RadioButtonPainter.PaintRadioButton(g, glyphArea, rb.BackColor, rb.ForeColor, ElementState.Normal, rb.FlatStyle, rb.Checked); + } + + public virtual void DrawRadioButtonFocus(Graphics g, RadioButton rb, Rectangle focusArea) + { + WidgetPaint.DrawFocusRectangle(g, focusArea); + } + + public virtual void DrawRadioButtonImage(Graphics g, RadioButton rb, Rectangle imageBounds) + { + if (rb.Enabled) + g.DrawImage(rb.Image, imageBounds); + else + CPDrawImageDisabled(g, rb.Image, imageBounds.Left, imageBounds.Top, ColorControl); + } + + public virtual void DrawRadioButtonText(Graphics g, RadioButton rb, Rectangle textBounds) + { + if (rb.Enabled) + TextRenderer.DrawTextInternal(g, rb.Text, rb.Font, textBounds, rb.ForeColor, rb.TextFormatFlags, rb.UseCompatibleTextRendering); + else + DrawStringDisabled20(g, rb.Text, rb.Font, textBounds, rb.BackColor, rb.TextFormatFlags, rb.UseCompatibleTextRendering); + } + + public override Size CalculateRadioButtonAutoSize(RadioButton rb) + { + Size ret_size = Size.Empty; + Size text_size = TextRenderer.MeasureTextInternal(rb.Text, rb.Font, rb.UseCompatibleTextRendering); + Size image_size = rb.Image == null ? Size.Empty : rb.Image.Size; + + // Pad the text size + if (rb.Text.Length != 0) + { + text_size.Height += 4; + text_size.Width += 4; + } + + switch (rb.TextImageRelation) + { + case TextImageRelation.Overlay: + ret_size.Height = Math.Max(rb.Text.Length == 0 ? 0 : text_size.Height, image_size.Height); + ret_size.Width = Math.Max(text_size.Width, image_size.Width); + break; + case TextImageRelation.ImageAboveText: + case TextImageRelation.TextAboveImage: + ret_size.Height = text_size.Height + image_size.Height; + ret_size.Width = Math.Max(text_size.Width, image_size.Width); + break; + case TextImageRelation.ImageBeforeText: + case TextImageRelation.TextBeforeImage: + ret_size.Height = Math.Max(text_size.Height, image_size.Height); + ret_size.Width = text_size.Width + image_size.Width; + break; + } + + // Pad the result + ret_size.Height += (rb.Padding.Vertical); + ret_size.Width += (rb.Padding.Horizontal) + 15; + + // There seems to be a minimum height + if (ret_size.Height == rb.Padding.Vertical) + ret_size.Height += 14; + + return ret_size; + } + + public override void CalculateRadioButtonTextAndImageLayout(ButtonBase b, Point offset, out Rectangle glyphArea, out Rectangle textRectangle, out Rectangle imageRectangle) + { + CalculateCheckBoxTextAndImageLayout(b, offset, out glyphArea, out textRectangle, out imageRectangle); + } + #endregion // RadioButton + + #region ScrollBar + public override void DrawScrollBar(Graphics dc, Rectangle clip, ScrollBar bar) + { + int scrollbutton_width = bar.scrollbutton_width; + int scrollbutton_height = bar.scrollbutton_height; + Rectangle first_arrow_area; + Rectangle second_arrow_area; + Rectangle thumb_pos; + + thumb_pos = bar.ThumbPos; + + if (bar.vert) + { + first_arrow_area = new Rectangle(0, 0, bar.Width, scrollbutton_height); + bar.FirstArrowArea = first_arrow_area; + + second_arrow_area = new Rectangle(0, bar.ClientRectangle.Height - scrollbutton_height, bar.Width, scrollbutton_height); + bar.SecondArrowArea = second_arrow_area; + + thumb_pos.Width = bar.Width; + bar.ThumbPos = thumb_pos; + + Brush VerticalBrush; + /* Background, upper track */ + if (bar.thumb_moving == ScrollBar.ThumbMoving.Backwards) + VerticalBrush = ResPool.GetHatchBrush(HatchStyle.Percent50, Color.FromArgb(255, 63, 63, 63), Color.Black); + else + VerticalBrush = ResPool.GetHatchBrush(HatchStyle.Percent50, ColorScrollBar, Color.White); + Rectangle UpperTrack = new Rectangle(0, 0, bar.ClientRectangle.Width, bar.ThumbPos.Bottom); + if (clip.IntersectsWith(UpperTrack)) + dc.FillRectangle(VerticalBrush, UpperTrack); + + /* Background, lower track */ + if (bar.thumb_moving == ScrollBar.ThumbMoving.Forward) + VerticalBrush = ResPool.GetHatchBrush(HatchStyle.Percent50, Color.FromArgb(255, 63, 63, 63), Color.Black); + else + VerticalBrush = ResPool.GetHatchBrush(HatchStyle.Percent50, ColorScrollBar, Color.White); + Rectangle LowerTrack = new Rectangle(0, bar.ThumbPos.Bottom, bar.ClientRectangle.Width, bar.ClientRectangle.Height - bar.ThumbPos.Bottom); + if (clip.IntersectsWith(LowerTrack)) + dc.FillRectangle(VerticalBrush, LowerTrack); + + /* Buttons */ + if (clip.IntersectsWith(first_arrow_area)) + CPDrawScrollButton(dc, first_arrow_area, ScrollButton.Up, bar.firstbutton_state); + if (clip.IntersectsWith(second_arrow_area)) + CPDrawScrollButton(dc, second_arrow_area, ScrollButton.Down, bar.secondbutton_state); + } + else + { + first_arrow_area = new Rectangle(0, 0, scrollbutton_width, bar.Height); + bar.FirstArrowArea = first_arrow_area; + + second_arrow_area = new Rectangle(bar.ClientRectangle.Width - scrollbutton_width, 0, scrollbutton_width, bar.Height); + bar.SecondArrowArea = second_arrow_area; + + thumb_pos.Height = bar.Height; + bar.ThumbPos = thumb_pos; + + Brush HorizontalBrush; + //Background, left track + if (bar.thumb_moving == ScrollBar.ThumbMoving.Backwards) + HorizontalBrush = ResPool.GetHatchBrush(HatchStyle.Percent50, Color.FromArgb(255, 63, 63, 63), Color.Black); + else + HorizontalBrush = ResPool.GetHatchBrush(HatchStyle.Percent50, ColorScrollBar, Color.White); + Rectangle LeftTrack = new Rectangle(0, 0, bar.ThumbPos.Right, bar.ClientRectangle.Height); + if (clip.IntersectsWith(LeftTrack)) + dc.FillRectangle(HorizontalBrush, LeftTrack); + + //Background, right track + if (bar.thumb_moving == ScrollBar.ThumbMoving.Forward) + HorizontalBrush = ResPool.GetHatchBrush(HatchStyle.Percent50, Color.FromArgb(255, 63, 63, 63), Color.Black); + else + HorizontalBrush = ResPool.GetHatchBrush(HatchStyle.Percent50, ColorScrollBar, Color.White); + Rectangle RightTrack = new Rectangle(bar.ThumbPos.Right, 0, bar.ClientRectangle.Width - bar.ThumbPos.Right, bar.ClientRectangle.Height); + if (clip.IntersectsWith(RightTrack)) + dc.FillRectangle(HorizontalBrush, RightTrack); + + /* Buttons */ + if (clip.IntersectsWith(first_arrow_area)) + CPDrawScrollButton(dc, first_arrow_area, ScrollButton.Left, bar.firstbutton_state); + if (clip.IntersectsWith(second_arrow_area)) + CPDrawScrollButton(dc, second_arrow_area, ScrollButton.Right, bar.secondbutton_state); + } + + /* Thumb */ + ScrollBar_DrawThumb(bar, thumb_pos, clip, dc); + } + + protected virtual void ScrollBar_DrawThumb(ScrollBar bar, Rectangle thumb_pos, Rectangle clip, Graphics dc) + { + if (bar.Enabled && thumb_pos.Width > 0 && thumb_pos.Height > 0 && clip.IntersectsWith(thumb_pos)) + DrawScrollButtonPrimitive(dc, thumb_pos, ButtonState.Normal); + } + + public override int ScrollBarButtonSize + { + get { return 16; } + } + + public override bool ScrollBarHasHotElementStyles + { + get + { + return false; + } + } + + public override bool ScrollBarHasPressedThumbStyle + { + get + { + return false; + } + } + + public override bool ScrollBarHasHoverArrowButtonStyle + { + get + { + return false; + } + } + #endregion // ScrollBar + + #region StatusBar + public override void DrawStatusBar(Graphics real_dc, Rectangle clip, StatusBar sb) + { + Rectangle area = sb.ClientRectangle; + int horz_border = 2; + int vert_border = 2; + + Image backbuffer = new Bitmap(sb.ClientSize.Width, sb.ClientSize.Height, real_dc); + Graphics dc = Graphics.FromImage(backbuffer); + + DrawStatusBarBackground(dc, clip, sb); + + if (!sb.ShowPanels && sb.Text != String.Empty) + { + string text = sb.Text; + StringFormat string_format = new StringFormat(); + string_format.Trimming = StringTrimming.Character; + string_format.FormatFlags = StringFormatFlags.NoWrap; + + if (text.Length > 127) + text = text.Substring(0, 127); + + if (text[0] == '\t') + { + string_format.Alignment = StringAlignment.Center; + text = text.Substring(1); + if (text[0] == '\t') + { + string_format.Alignment = StringAlignment.Far; + text = text.Substring(1); + } + } + + dc.DrawString(text, sb.Font, ResPool.GetSolidBrush(sb.ForeColor), + new Rectangle(area.X + 2, area.Y + 2, area.Width - 4, area.Height - 4), string_format); + string_format.Dispose(); + } + else if (sb.ShowPanels) + { + Brush br_forecolor = GetControlForeBrush(sb.ForeColor); + int prev_x = area.X + horz_border; + int y = area.Y + vert_border; + for (int i = 0; i < sb.Panels.Count; i++) + { + Rectangle pr = new Rectangle(prev_x, y, + sb.Panels[i].Width, area.Height); + prev_x += pr.Width + StatusBarHorzGapWidth; + if (pr.IntersectsWith(clip)) + DrawStatusBarPanel(dc, pr, i, br_forecolor, sb.Panels[i]); + } + } + + if (sb.SizingGrip) + DrawStatusBarSizingGrip(dc, clip, sb, area); + + real_dc.DrawImage(backbuffer, 0, 0); + dc.Dispose(); + backbuffer.Dispose(); + + } + + protected virtual void DrawStatusBarBackground(Graphics dc, Rectangle clip, StatusBar sb) + { + bool is_color_control = sb.BackColor.ToArgb() == ColorControl.ToArgb(); + + Brush brush = is_color_control ? SystemBrushes.Control : ResPool.GetSolidBrush(sb.BackColor); + dc.FillRectangle(brush, clip); + } + + protected virtual void DrawStatusBarSizingGrip(Graphics dc, Rectangle clip, StatusBar sb, Rectangle area) + { + area = new Rectangle(area.Right - 16 - 2, area.Bottom - 12 - 1, 16, 16); + CPDrawSizeGrip(dc, ColorControl, area); + } + + protected virtual void DrawStatusBarPanel(Graphics dc, Rectangle area, int index, + Brush br_forecolor, StatusBarPanel panel) + { + int border_size = 3; // this is actually const, even if the border style is none + int icon_width = 16; + + area.Height -= border_size; + + DrawStatusBarPanelBackground(dc, area, panel); + + if (panel.Style == StatusBarPanelStyle.OwnerDraw) + { + StatusBarDrawItemEventArgs e = new StatusBarDrawItemEventArgs( + dc, panel.Parent.Font, area, index, DrawItemState.Default, + panel, panel.Parent.ForeColor, panel.Parent.BackColor); + panel.Parent.OnDrawItemInternal(e); + return; + } + + string text = panel.Text; + StringFormat string_format = new StringFormat(); + string_format.Trimming = StringTrimming.Character; + string_format.FormatFlags = StringFormatFlags.NoWrap; + + + if (text != null && text.Length > 0 && text[0] == '\t') + { + string_format.Alignment = StringAlignment.Center; + text = text.Substring(1); + if (text[0] == '\t') + { + string_format.Alignment = StringAlignment.Far; + text = text.Substring(1); + } + } + + Rectangle string_rect = Rectangle.Empty; + int x; + int len; + int icon_x = 0; + int y = (area.Height / 2 - (int)panel.Parent.Font.Size / 2) - 1; + + switch (panel.Alignment) + { + case HorizontalAlignment.Right: + len = (int)dc.MeasureString(text, panel.Parent.Font).Width; + x = area.Right - len - 4; + string_rect = new Rectangle(x, y, + area.Right - x - border_size, + area.Bottom - y - border_size); + if (panel.Icon != null) + { + icon_x = x - icon_width - 2; + } + break; + case HorizontalAlignment.Center: + len = (int)dc.MeasureString(text, panel.Parent.Font).Width; + x = area.Left + ((panel.Width - len) / 2); + + string_rect = new Rectangle(x, y, + area.Right - x - border_size, + area.Bottom - y - border_size); + + if (panel.Icon != null) + { + icon_x = x - icon_width - 2; + } + break; + + + default: + int left = area.Left + border_size; ; + if (panel.Icon != null) + { + icon_x = area.Left + 2; + left = icon_x + icon_width + 2; + } + + x = left; + string_rect = new Rectangle(x, y, + area.Right - x - border_size, + area.Bottom - y - border_size); + break; + } + + RectangleF clip_bounds = dc.ClipBounds; + dc.SetClip(area); + dc.DrawString(text, panel.Parent.Font, br_forecolor, string_rect, string_format); + dc.SetClip(clip_bounds); + + if (panel.Icon != null) + { + dc.DrawIcon(panel.Icon, new Rectangle(icon_x, y, icon_width, icon_width)); + } + } + + protected virtual void DrawStatusBarPanelBackground(Graphics dc, Rectangle area, StatusBarPanel panel) + { + if (panel.BorderStyle != StatusBarPanelBorderStyle.None) + { + Border3DStyle border_style = Border3DStyle.SunkenOuter; + if (panel.BorderStyle == StatusBarPanelBorderStyle.Raised) + border_style = Border3DStyle.RaisedInner; + + CPDrawBorder3D(dc, area, border_style, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom, panel.Parent.BackColor); + } + } + + public override int StatusBarSizeGripWidth + { + get { return 15; } + } + + public override int StatusBarHorzGapWidth + { + get { return 3; } + } + + public override Size StatusBarDefaultSize + { + get + { + return new Size(100, 22); + } + } + #endregion // StatusBar + + #region TabControl + + #region TabControl settings + + public override Size TabControlDefaultItemSize + { + get { return MemphisThemeElements.CurrentTheme.TabWidgetPainter.DefaultItemSize; } + } + + public override Point TabControlDefaultPadding + { + get { return MemphisThemeElements.CurrentTheme.TabWidgetPainter.DefaultPadding; } + } + + public override int TabControlMinimumTabWidth + { + get { return MemphisThemeElements.CurrentTheme.TabWidgetPainter.MinimumTabWidth; } + } + + public override Rectangle TabWidgetselectedDelta + { + get { return MemphisThemeElements.CurrentTheme.TabWidgetPainter.SelectedTabDelta; } + } + + public override int TabWidgetselectedSpacing + { + get { return MemphisThemeElements.CurrentTheme.TabWidgetPainter.SelectedSpacing; } + } + + public override int TabPanelOffsetX + { + get { return MemphisThemeElements.CurrentTheme.TabWidgetPainter.TabPanelOffset.X; } + } + + public override int TabPanelOffsetY + { + get { return MemphisThemeElements.CurrentTheme.TabWidgetPainter.TabPanelOffset.Y; } + } + + public override int TabControlColSpacing + { + get { return MemphisThemeElements.CurrentTheme.TabWidgetPainter.ColSpacing; } + } + + public override Point TabControlImagePadding + { + get { return MemphisThemeElements.CurrentTheme.TabWidgetPainter.ImagePadding; } + } + + public override int TabWidgetscrollerWidth + { + get { return MemphisThemeElements.CurrentTheme.TabWidgetPainter.ScrollerWidth; } + } + + + public override Size TabControlGetSpacing(TabWidget tab) + { + try + { + return MemphisThemeElements.CurrentTheme.TabWidgetPainter.RowSpacing(tab); + } + catch + { + throw new Exception("Invalid Appearance value: " + tab.Appearance); + } + } + #endregion + + public override void DrawTabControl(Graphics dc, Rectangle area, TabWidget tab) + { + MemphisThemeElements.CurrentTheme.TabWidgetPainter.Draw(dc, area, tab); + } + + public override Rectangle TabControlGetDisplayRectangle(TabWidget tab) + { + return MemphisThemeElements.CurrentTheme.TabWidgetPainter.GetDisplayRectangle(tab); + } + + public override Rectangle TabControlGetPanelRect(TabWidget tab) + { + return MemphisThemeElements.CurrentTheme.TabWidgetPainter.GetTabPanelRect(tab); + } + + #endregion + + #region TextBox + public override void TextBoxBaseFillBackground(TextBoxBase textBoxBase, Graphics g, Rectangle clippingArea) + { + if (textBoxBase.backcolor_set || (textBoxBase.Enabled && !textBoxBase.read_only)) + { + g.FillRectangle(ResPool.GetSolidBrush(textBoxBase.BackColor), clippingArea); + } + else + { + g.FillRectangle(ResPool.GetSolidBrush(ColorControl), clippingArea); + } + } + + public override bool TextBoxBaseHandleWmNcPaint(TextBoxBase textBoxBase, ref Message m) + { + return false; + } + + public override bool TextBoxBaseShouldPaintBackground(TextBoxBase textBoxBase) + { + return true; + } + #endregion + + + #region ToolTip + public override void DrawToolTip(Graphics dc, Rectangle clip_rectangle, ToolTip.ToolTipWindow control) + { + ToolTipDrawBackground(dc, clip_rectangle, control); + + TextFormatFlags flags = TextFormatFlags.HidePrefix; + + Color foreground = control.ForeColor; + if (control.title.Length > 0) + { + Font bold_font = new Font(control.Font, control.Font.Style | FontStyle.Bold); + TextRenderer.DrawTextInternal(dc, control.title, bold_font, control.title_rect, + foreground, flags, false); + bold_font.Dispose(); + } + + if (control.icon != null) + dc.DrawIcon(control.icon, control.icon_rect); + + TextRenderer.DrawTextInternal(dc, control.Text, control.Font, control.text_rect, foreground, flags, false); + } + + protected virtual void ToolTipDrawBackground(Graphics dc, Rectangle clip_rectangle, ToolTip.ToolTipWindow control) + { + Brush back_brush = ResPool.GetSolidBrush(control.BackColor); + dc.FillRectangle(back_brush, control.ClientRectangle); + dc.DrawRectangle(SystemPens.WindowFrame, 0, 0, control.Width - 1, control.Height - 1); + } + + public override Size ToolTipSize(ToolTip.ToolTipWindow tt, string text) + { + Size size = TextRenderer.MeasureTextInternal(text, tt.Font, false); + size.Width += 4; + size.Height += 3; + Rectangle text_rect = new Rectangle(Point.Empty, size); + text_rect.Inflate(-2, -1); + tt.text_rect = text_rect; + tt.icon_rect = tt.title_rect = Rectangle.Empty; + + Size title_size = Size.Empty; + if (tt.title.Length > 0) + { + Font bold_font = new Font(tt.Font, tt.Font.Style | FontStyle.Bold); + title_size = TextRenderer.MeasureTextInternal(tt.title, bold_font, false); + bold_font.Dispose(); + } + + Size icon_size = Size.Empty; + if (tt.icon != null) + icon_size = new Size(size.Height, size.Height); + + if (icon_size != Size.Empty || title_size != Size.Empty) + { + int padding = 8; + int top_area_width = 0; + int top_area_height = icon_size.Height > title_size.Height ? icon_size.Height : title_size.Height; + Size text_size = size; + Point location = new Point(padding, padding); + + if (icon_size != Size.Empty) + { + tt.icon_rect = new Rectangle(location, icon_size); + top_area_width = icon_size.Width + padding; + } + + if (title_size != Size.Empty) + { + Rectangle title_rect = new Rectangle(location, new Size(title_size.Width, top_area_height)); + if (icon_size != Size.Empty) + title_rect.X += icon_size.Width + padding; + + tt.title_rect = title_rect; + top_area_width += title_size.Width; + } + + tt.text_rect = new Rectangle(new Point(location.X, location.Y + top_area_height + padding), + text_size); + + size.Height += padding + top_area_height; + if (top_area_width > size.Width) + size.Width = top_area_width; + + // margins + size.Width += padding * 2; + size.Height += padding * 2; + } + + return size; + } + + public override bool ToolTipTransparentBackground + { + get + { + return false; + } + } + #endregion // ToolTip + + #region BalloonWindow + NotifyIcon.BalloonWindow balloon_window; + + public override void ShowBalloonWindow(IntPtr handle, int timeout, string title, string text, ToolTipIcon icon) + { + Widget control = Widget.FromHandle(handle); + + if (control == null) + return; + + if (balloon_window != null) + { + balloon_window.Close(); + balloon_window.Dispose(); + } + + balloon_window = new NotifyIcon.BalloonWindow(handle); + balloon_window.Title = title; + balloon_window.Text = text; + balloon_window.Icon = icon; + balloon_window.Timeout = timeout; + balloon_window.Show(); + } + + public override void HideBalloonWindow(IntPtr handle) + { + if (balloon_window == null || balloon_window.OwnerHandle != handle) + return; + + balloon_window.Close(); + balloon_window.Dispose(); + balloon_window = null; + } + + private const int balloon_iconsize = 16; + private const int balloon_bordersize = 8; + + public override void DrawBalloonWindow(Graphics dc, Rectangle clip, NotifyIcon.BalloonWindow control) + { + Brush solidbrush = ResPool.GetSolidBrush(this.ColorInfoText); + Rectangle rect = control.ClientRectangle; + int iconsize = (control.Icon == ToolTipIcon.None) ? 0 : balloon_iconsize; + + // Rectangle borders and background. + dc.FillRectangle(ResPool.GetSolidBrush(ColorInfo), rect); + dc.DrawRectangle(ResPool.GetPen(ColorWindowFrame), 0, 0, rect.Width - 1, rect.Height - 1); + + // Icon + Image image; + switch (control.Icon) + { + case ToolTipIcon.Info: + { + image = ThemeEngine.Current.Images(UIIcon.MessageBoxInfo, balloon_iconsize); + break; + } + + case ToolTipIcon.Warning: + { + image = ThemeEngine.Current.Images(UIIcon.MessageBoxError, balloon_iconsize); + break; + } + + case ToolTipIcon.Error: + { + image = ThemeEngine.Current.Images(UIIcon.MessageBoxWarning, balloon_iconsize); + break; + } + + default: + { + image = null; + break; + } + } + + if (control.Icon != ToolTipIcon.None) + dc.DrawImage(image, new Rectangle(balloon_bordersize, balloon_bordersize, iconsize, iconsize)); + + // Title + Rectangle titlerect = new Rectangle(rect.X + balloon_bordersize + iconsize + (iconsize > 0 ? balloon_bordersize : 0), + rect.Y + balloon_bordersize, + rect.Width - ((3 * balloon_bordersize) + iconsize), + rect.Height - (2 * balloon_bordersize)); + + Font titlefont = new Font(control.Font.FontFamily, control.Font.Size, control.Font.Style | FontStyle.Bold, control.Font.Unit); + dc.DrawString(control.Title, titlefont, solidbrush, titlerect, control.Format); + + // Text + Rectangle textrect = new Rectangle(rect.X + balloon_bordersize, + rect.Y + balloon_bordersize, + rect.Width - (2 * balloon_bordersize), + rect.Height - (2 * balloon_bordersize)); + + StringFormat textformat = control.Format; + textformat.LineAlignment = StringAlignment.Far; + dc.DrawString(control.Text, control.Font, solidbrush, textrect, textformat); + } + + public override Rectangle BalloonWindowRect(NotifyIcon.BalloonWindow control) + { + Rectangle deskrect = Screen.GetWorkingArea(control); + SizeF maxsize = new SizeF(250, 200); + + SizeF titlesize = TextRenderer.MeasureString(control.Title, control.Font, maxsize, control.Format); + SizeF textsize = TextRenderer.MeasureString(control.Text, control.Font, maxsize, control.Format); + + if (titlesize.Height < balloon_iconsize) + titlesize.Height = balloon_iconsize; + + Rectangle rect = new Rectangle(); + rect.Height = (int)(titlesize.Height + textsize.Height + (3 * balloon_bordersize)); + rect.Width = (int)((titlesize.Width > textsize.Width) ? titlesize.Width : textsize.Width) + (2 * balloon_bordersize); + rect.X = deskrect.Width - rect.Width - 2; + rect.Y = deskrect.Height - rect.Height - 2; + + return rect; + } + #endregion // BalloonWindow + + #region TrackBar + public override int TrackBarValueFromMousePosition(int x, int y, TrackBar tb) + { + int result = tb.Value; + int value_pos = tb.Value; + float pixels_betweenticks; + Rectangle thumb_pos = Rectangle.Empty, thumb_area = Rectangle.Empty; + Point channel_startpoint = Point.Empty, na_point = Point.Empty; + + GetTrackBarDrawingInfo(tb, out pixels_betweenticks, out thumb_area, out thumb_pos, out channel_startpoint, out na_point, out na_point); + + /* Convert thumb position from mouse position to value*/ + if (tb.Orientation == Orientation.Vertical) + { + value_pos = (int)Math.Round(((thumb_area.Bottom - y - (float)thumb_pos.Height / 2) / (float)pixels_betweenticks), 0); + + if (value_pos + tb.Minimum > tb.Maximum) + value_pos = tb.Maximum - tb.Minimum; + else if (value_pos + tb.Minimum < tb.Minimum) + value_pos = 0; + + result = value_pos + tb.Minimum; + } + else + { + value_pos = (int)Math.Round(((x - channel_startpoint.X - (float)thumb_pos.Width / 2) / (float)pixels_betweenticks), 0); + + if (value_pos + tb.Minimum > tb.Maximum) + value_pos = tb.Maximum - tb.Minimum; + else if (value_pos + tb.Minimum < tb.Minimum) + value_pos = 0; + + result = value_pos + tb.Minimum; + } + + return result; + } + + private void GetTrackBarDrawingInfo(TrackBar tb, out float pixels_betweenticks, out Rectangle thumb_area, out Rectangle thumb_pos, out Point channel_startpoint, out Point bottomtick_startpoint, out Point toptick_startpoint) + { + thumb_area = Rectangle.Empty; + thumb_pos = Rectangle.Empty; + + if (tb.Orientation == Orientation.Vertical) + { + toptick_startpoint = new Point(); + bottomtick_startpoint = new Point(); + channel_startpoint = new Point(); + float pixel_len; + const int space_from_right = 8; + const int space_from_left = 8; + const int space_from_bottom = 11; + Rectangle area = tb.ClientRectangle; + + switch (tb.TickStyle) + { + case TickStyle.BottomRight: + case TickStyle.None: + channel_startpoint.Y = 8; + channel_startpoint.X = 9; + bottomtick_startpoint.Y = 13; + bottomtick_startpoint.X = 24; + break; + case TickStyle.TopLeft: + channel_startpoint.Y = 8; + channel_startpoint.X = 19; + toptick_startpoint.Y = 13; + toptick_startpoint.X = 8; + break; + case TickStyle.Both: + channel_startpoint.Y = 8; + channel_startpoint.X = 18; + bottomtick_startpoint.Y = 13; + bottomtick_startpoint.X = 32; + toptick_startpoint.Y = 13; + toptick_startpoint.X = 8; + break; + default: + break; + } + + thumb_area.X = area.X + channel_startpoint.X; + thumb_area.Y = area.Y + channel_startpoint.Y; + thumb_area.Height = area.Height - space_from_right - space_from_left; + thumb_area.Width = TrackBarVerticalTrackWidth; + + pixel_len = thumb_area.Height - 11; + if (tb.Maximum == tb.Minimum) + { + pixels_betweenticks = 0; + } + else + { + pixels_betweenticks = pixel_len / (tb.Maximum - tb.Minimum); + } + + thumb_pos.Y = thumb_area.Bottom - space_from_bottom - (int)(pixels_betweenticks * (float)(tb.Value - tb.Minimum)); + } + else + { + toptick_startpoint = new Point(); + bottomtick_startpoint = new Point(); + channel_startpoint = new Point(); + float pixel_len; + const int space_from_right = 8; + const int space_from_left = 8; + Rectangle area = tb.ClientRectangle; + + switch (tb.TickStyle) + { + case TickStyle.BottomRight: + case TickStyle.None: + channel_startpoint.X = 8; + channel_startpoint.Y = 9; + bottomtick_startpoint.X = 13; + bottomtick_startpoint.Y = 24; + break; + case TickStyle.TopLeft: + channel_startpoint.X = 8; + channel_startpoint.Y = 19; + toptick_startpoint.X = 13; + toptick_startpoint.Y = 8; + break; + case TickStyle.Both: + channel_startpoint.X = 8; + channel_startpoint.Y = 18; + bottomtick_startpoint.X = 13; + bottomtick_startpoint.Y = 32; + toptick_startpoint.X = 13; + toptick_startpoint.Y = 8; + break; + default: + break; + } + + thumb_area.X = area.X + channel_startpoint.X; + thumb_area.Y = area.Y + channel_startpoint.Y; + thumb_area.Width = area.Width - space_from_right - space_from_left; + thumb_area.Height = TrackBarHorizontalTrackHeight; + + pixel_len = thumb_area.Width - 11; + if (tb.Maximum == tb.Minimum) + { + pixels_betweenticks = 0; + } + else + { + pixels_betweenticks = pixel_len / (tb.Maximum - tb.Minimum); + } + + thumb_pos.X = channel_startpoint.X + (int)(pixels_betweenticks * (float)(tb.Value - tb.Minimum)); + } + + thumb_pos.Size = TrackBarGetThumbSize(tb); + } + + protected virtual Size TrackBarGetThumbSize(TrackBar trackBar) + { + return TrackBarGetThumbSize(); + } + + public static Size TrackBarGetThumbSize() + { + /* Draw thumb fixed 10x22 size */ + return new Size(10, 22); + } + + public const int TrackBarVerticalTrackWidth = 4; + + public const int TrackBarHorizontalTrackHeight = 4; + + #region Ticks + protected interface ITrackBarTickPainter + { + void Paint(float x1, float y1, float x2, float y2); + } + + class TrackBarTickPainter : ITrackBarTickPainter + { + readonly Graphics g; + readonly Pen pen; + public TrackBarTickPainter(Graphics g, Pen pen) + { + this.g = g; + this.pen = pen; + } + public void Paint(float x1, float y1, float x2, float y2) + { + g.DrawLine(pen, x1, y1, x2, y2); + } + } + protected virtual ITrackBarTickPainter GetTrackBarTickPainter(Graphics g) + { + return new TrackBarTickPainter(g, ResPool.GetPen(pen_ticks_color)); + } + #endregion + + #region DrawTrackBar_Vertical + private void DrawTrackBar_Vertical(Graphics dc, Rectangle clip_rectangle, TrackBar tb, + ref Rectangle thumb_pos, ref Rectangle thumb_area, Brush br_thumb, + float ticks, int value_pos, bool mouse_value) + { + + Point toptick_startpoint = new Point(); + Point bottomtick_startpoint = new Point(); + Point channel_startpoint = new Point(); + float pixel_len; + float pixels_betweenticks; + Rectangle area = tb.ClientRectangle; + + GetTrackBarDrawingInfo(tb, out pixels_betweenticks, out thumb_area, out thumb_pos, out channel_startpoint, out bottomtick_startpoint, out toptick_startpoint); + + #region Track + TrackBarDrawVerticalTrack(dc, thumb_area, channel_startpoint, clip_rectangle); + #endregion + + #region Thumb + switch (tb.TickStyle) + { + case TickStyle.BottomRight: + case TickStyle.None: + thumb_pos.X = channel_startpoint.X - 8; + TrackBarDrawVerticalThumbRight(dc, thumb_pos, br_thumb, clip_rectangle, tb); + break; + case TickStyle.TopLeft: + thumb_pos.X = channel_startpoint.X - 10; + TrackBarDrawVerticalThumbLeft(dc, thumb_pos, br_thumb, clip_rectangle, tb); + break; + default: + thumb_pos.X = area.X + 10; + TrackBarDrawVerticalThumb(dc, thumb_pos, br_thumb, clip_rectangle, tb); + break; + } + #endregion + + pixel_len = thumb_area.Height - 11; + pixels_betweenticks = pixel_len / ticks; + + thumb_area.X = thumb_pos.X; + thumb_area.Y = channel_startpoint.Y; + thumb_area.Width = thumb_pos.Height; + + #region Ticks + if (pixels_betweenticks <= 0) + return; + if (tb.TickStyle == TickStyle.None) + return; + Region outside = new Region(area); + outside.Exclude(thumb_area); + + if (outside.IsVisible(clip_rectangle)) + { + ITrackBarTickPainter tick_painter = TrackBarGetVerticalTickPainter(dc); + + if ((tb.TickStyle & TickStyle.BottomRight) == TickStyle.BottomRight) + { + float x = area.X + bottomtick_startpoint.X; + for (float inc = 0; inc < pixel_len + 1; inc += pixels_betweenticks) + { + float y = area.Y + bottomtick_startpoint.Y + inc; + tick_painter.Paint( + x, y, + x + (inc == 0 || inc + pixels_betweenticks >= pixel_len + 1 ? 3 : 2), y); + } + } + + if ((tb.TickStyle & TickStyle.TopLeft) == TickStyle.TopLeft) + { + float x = area.X + toptick_startpoint.X; + for (float inc = 0; inc < (pixel_len + 1); inc += pixels_betweenticks) + { + float y = area.Y + toptick_startpoint.Y + inc; + tick_painter.Paint( + x - (inc == 0 || inc + pixels_betweenticks >= pixel_len + 1 ? 3 : 2), y, + x, y); + } + } + } + + outside.Dispose(); + #endregion + } + + #region Track + protected virtual void TrackBarDrawVerticalTrack(Graphics dc, Rectangle thumb_area, Point channel_startpoint, Rectangle clippingArea) + { + dc.FillRectangle(SystemBrushes.ControlDark, channel_startpoint.X, channel_startpoint.Y, + 1, thumb_area.Height); + + dc.FillRectangle(SystemBrushes.ControlDarkDark, channel_startpoint.X + 1, channel_startpoint.Y, + 1, thumb_area.Height); + + dc.FillRectangle(SystemBrushes.ControlLight, channel_startpoint.X + 3, channel_startpoint.Y, + 1, thumb_area.Height); + } + #endregion + + #region Thumb + protected virtual void TrackBarDrawVerticalThumbRight(Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + Pen pen = SystemPens.ControlLightLight; + dc.DrawLine(pen, thumb_pos.X, thumb_pos.Y, thumb_pos.X, thumb_pos.Y + 10); + dc.DrawLine(pen, thumb_pos.X, thumb_pos.Y, thumb_pos.X + 16, thumb_pos.Y); + dc.DrawLine(pen, thumb_pos.X + 16, thumb_pos.Y, thumb_pos.X + 16 + 4, thumb_pos.Y + 4); + + pen = SystemPens.ControlDark; + dc.DrawLine(pen, thumb_pos.X + 1, thumb_pos.Y + 9, thumb_pos.X + 15, thumb_pos.Y + 9); + dc.DrawLine(pen, thumb_pos.X + 16, thumb_pos.Y + 9, thumb_pos.X + 16 + 4, thumb_pos.Y + 9 - 4); + + pen = SystemPens.ControlDarkDark; + dc.DrawLine(pen, thumb_pos.X, thumb_pos.Y + 10, thumb_pos.X + 16, thumb_pos.Y + 10); + dc.DrawLine(pen, thumb_pos.X + 16, thumb_pos.Y + 10, thumb_pos.X + 16 + 5, thumb_pos.Y + 10 - 5); + + dc.FillRectangle(br_thumb, thumb_pos.X + 1, thumb_pos.Y + 1, 16, 8); + dc.FillRectangle(br_thumb, thumb_pos.X + 17, thumb_pos.Y + 2, 1, 6); + dc.FillRectangle(br_thumb, thumb_pos.X + 18, thumb_pos.Y + 3, 1, 4); + dc.FillRectangle(br_thumb, thumb_pos.X + 19, thumb_pos.Y + 4, 1, 2); + } + + protected virtual void TrackBarDrawVerticalThumbLeft(Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + Pen pen = SystemPens.ControlLightLight; + dc.DrawLine(pen, thumb_pos.X + 4, thumb_pos.Y, thumb_pos.X + 4 + 16, thumb_pos.Y); + dc.DrawLine(pen, thumb_pos.X + 4, thumb_pos.Y, thumb_pos.X, thumb_pos.Y + 4); + + pen = SystemPens.ControlDark; + dc.DrawLine(pen, thumb_pos.X + 4, thumb_pos.Y + 9, thumb_pos.X + 4 + 16, thumb_pos.Y + 9); + dc.DrawLine(pen, thumb_pos.X + 4, thumb_pos.Y + 9, thumb_pos.X, thumb_pos.Y + 5); + dc.DrawLine(pen, thumb_pos.X + 19, thumb_pos.Y + 9, thumb_pos.X + 19, thumb_pos.Y + 1); + + pen = SystemPens.ControlDarkDark; + dc.DrawLine(pen, thumb_pos.X + 4, thumb_pos.Y + 10, thumb_pos.X + 4 + 16, thumb_pos.Y + 10); + dc.DrawLine(pen, thumb_pos.X + 4, thumb_pos.Y + 10, thumb_pos.X - 1, thumb_pos.Y + 5); + dc.DrawLine(pen, thumb_pos.X + 20, thumb_pos.Y, thumb_pos.X + 20, thumb_pos.Y + 10); + + dc.FillRectangle(br_thumb, thumb_pos.X + 4, thumb_pos.Y + 1, 15, 8); + dc.FillRectangle(br_thumb, thumb_pos.X + 3, thumb_pos.Y + 2, 1, 6); + dc.FillRectangle(br_thumb, thumb_pos.X + 2, thumb_pos.Y + 3, 1, 4); + dc.FillRectangle(br_thumb, thumb_pos.X + 1, thumb_pos.Y + 4, 1, 2); + } + + protected virtual void TrackBarDrawVerticalThumb(Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + Pen pen = SystemPens.ControlLightLight; + dc.DrawLine(pen, thumb_pos.X, thumb_pos.Y, thumb_pos.X, thumb_pos.Y + 9); + dc.DrawLine(pen, thumb_pos.X, thumb_pos.Y, thumb_pos.X + 19, thumb_pos.Y); + + pen = SystemPens.ControlDark; + dc.DrawLine(pen, thumb_pos.X + 1, thumb_pos.Y + 9, thumb_pos.X + 19, thumb_pos.Y + 9); + dc.DrawLine(pen, thumb_pos.X + 10, thumb_pos.Y + 1, thumb_pos.X + 19, thumb_pos.Y + 8); + + pen = SystemPens.ControlDarkDark; + dc.DrawLine(pen, thumb_pos.X, thumb_pos.Y + 10, thumb_pos.X + 20, thumb_pos.Y + 10); + dc.DrawLine(pen, thumb_pos.X + 20, thumb_pos.Y, thumb_pos.X + 20, thumb_pos.Y + 9); + + dc.FillRectangle(br_thumb, thumb_pos.X + 1, thumb_pos.Y + 1, 18, 8); + } + #endregion + + #region Ticks + protected virtual ITrackBarTickPainter TrackBarGetVerticalTickPainter(Graphics g) + { + return GetTrackBarTickPainter(g); + } + #endregion + #endregion + + #region DrawTrackBar_Horizontal + /* + Horizontal trackbar + + Does not matter the size of the control, Win32 always draws: + - Ticks starting from pixel 13, 8 + - Channel starting at pos 8, 19 and ends at Width - 8 + - Autosize makes always the control 45 pixels high + - Ticks are draw at (channel.Witdh - 10) / (Maximum - Minimum) + + */ + private void DrawTrackBar_Horizontal(Graphics dc, Rectangle clip_rectangle, TrackBar tb, + ref Rectangle thumb_pos, ref Rectangle thumb_area, Brush br_thumb, + float ticks, int value_pos, bool mouse_value) + { + Point toptick_startpoint = new Point(); + Point bottomtick_startpoint = new Point(); + Point channel_startpoint = new Point(); + float pixel_len; + float pixels_betweenticks; + Rectangle area = tb.ClientRectangle; + + GetTrackBarDrawingInfo(tb, out pixels_betweenticks, out thumb_area, out thumb_pos, out channel_startpoint, out bottomtick_startpoint, out toptick_startpoint); + + #region Track + TrackBarDrawHorizontalTrack(dc, thumb_area, channel_startpoint, clip_rectangle); + #endregion + + #region Thumb + switch (tb.TickStyle) + { + case TickStyle.BottomRight: + case TickStyle.None: + thumb_pos.Y = channel_startpoint.Y - 8; + TrackBarDrawHorizontalThumbBottom(dc, thumb_pos, br_thumb, clip_rectangle, tb); + break; + case TickStyle.TopLeft: + thumb_pos.Y = channel_startpoint.Y - 10; + TrackBarDrawHorizontalThumbTop(dc, thumb_pos, br_thumb, clip_rectangle, tb); + break; + default: + thumb_pos.Y = area.Y + 10; + TrackBarDrawHorizontalThumb(dc, thumb_pos, br_thumb, clip_rectangle, tb); + break; + } + #endregion + + pixel_len = thumb_area.Width - 11; + pixels_betweenticks = pixel_len / ticks; + + thumb_area.Y = thumb_pos.Y; + thumb_area.X = channel_startpoint.X; + thumb_area.Height = thumb_pos.Height; + #region Ticks + if (pixels_betweenticks <= 0) + return; + if (tb.TickStyle == TickStyle.None) + return; + Region outside = new Region(area); + outside.Exclude(thumb_area); + + if (outside.IsVisible(clip_rectangle)) + { + ITrackBarTickPainter tick_painter = TrackBarGetHorizontalTickPainter(dc); + + if ((tb.TickStyle & TickStyle.BottomRight) == TickStyle.BottomRight) + { + float y = area.Y + bottomtick_startpoint.Y; + for (float inc = 0; inc < pixel_len + 1; inc += pixels_betweenticks) + { + float x = area.X + bottomtick_startpoint.X + inc; + tick_painter.Paint( + x, y, + x, y + (inc == 0 || inc + pixels_betweenticks >= pixel_len + 1 ? 3 : 2)); + } + } + + if ((tb.TickStyle & TickStyle.TopLeft) == TickStyle.TopLeft) + { + float y = area.Y + toptick_startpoint.Y; + for (float inc = 0; inc < pixel_len + 1; inc += pixels_betweenticks) + { + float x = area.X + toptick_startpoint.X + inc; + tick_painter.Paint( + x, y - (inc == 0 || (inc + pixels_betweenticks) >= pixel_len + 1 ? 3 : 2), + x, y); + } + } + } + + outside.Dispose(); + #endregion + } + + #region Track + protected virtual void TrackBarDrawHorizontalTrack(Graphics dc, Rectangle thumb_area, Point channel_startpoint, Rectangle clippingArea) + { + dc.FillRectangle(SystemBrushes.ControlDark, channel_startpoint.X, channel_startpoint.Y, + thumb_area.Width, 1); + + dc.FillRectangle(SystemBrushes.ControlDarkDark, channel_startpoint.X, channel_startpoint.Y + 1, + thumb_area.Width, 1); + + dc.FillRectangle(SystemBrushes.ControlLight, channel_startpoint.X, channel_startpoint.Y + 3, + thumb_area.Width, 1); + } + #endregion + + #region Thumb + protected virtual void TrackBarDrawHorizontalThumbBottom(Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + Pen pen = SystemPens.ControlLightLight; + dc.DrawLine(pen, thumb_pos.X, thumb_pos.Y, thumb_pos.X + 10, thumb_pos.Y); + dc.DrawLine(pen, thumb_pos.X, thumb_pos.Y, thumb_pos.X, thumb_pos.Y + 16); + dc.DrawLine(pen, thumb_pos.X, thumb_pos.Y + 16, thumb_pos.X + 4, thumb_pos.Y + 16 + 4); + + pen = SystemPens.ControlDark; + dc.DrawLine(pen, thumb_pos.X + 9, thumb_pos.Y + 1, thumb_pos.X + 9, thumb_pos.Y + 15); + dc.DrawLine(pen, thumb_pos.X + 9, thumb_pos.Y + 16, thumb_pos.X + 9 - 4, thumb_pos.Y + 16 + 4); + + pen = SystemPens.ControlDarkDark; + dc.DrawLine(pen, thumb_pos.X + 10, thumb_pos.Y, thumb_pos.X + 10, thumb_pos.Y + 16); + dc.DrawLine(pen, thumb_pos.X + 10, thumb_pos.Y + 16, thumb_pos.X + 10 - 5, thumb_pos.Y + 16 + 5); + + dc.FillRectangle(br_thumb, thumb_pos.X + 1, thumb_pos.Y + 1, 8, 16); + dc.FillRectangle(br_thumb, thumb_pos.X + 2, thumb_pos.Y + 17, 6, 1); + dc.FillRectangle(br_thumb, thumb_pos.X + 3, thumb_pos.Y + 18, 4, 1); + dc.FillRectangle(br_thumb, thumb_pos.X + 4, thumb_pos.Y + 19, 2, 1); + } + + protected virtual void TrackBarDrawHorizontalThumbTop(Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + Pen pen = SystemPens.ControlLightLight; + dc.DrawLine(pen, thumb_pos.X, thumb_pos.Y + 4, thumb_pos.X, thumb_pos.Y + 4 + 16); + dc.DrawLine(pen, thumb_pos.X, thumb_pos.Y + 4, thumb_pos.X + 4, thumb_pos.Y); + + pen = SystemPens.ControlDark; + dc.DrawLine(pen, thumb_pos.X + 9, thumb_pos.Y + 4, thumb_pos.X + 9, thumb_pos.Y + 4 + 16); + dc.DrawLine(pen, thumb_pos.X + 9, thumb_pos.Y + 4, thumb_pos.X + 5, thumb_pos.Y); + dc.DrawLine(pen, thumb_pos.X + 9, thumb_pos.Y + 19, thumb_pos.X + 1, thumb_pos.Y + 19); + + pen = SystemPens.ControlDarkDark; + dc.DrawLine(pen, thumb_pos.X + 10, thumb_pos.Y + 4, thumb_pos.X + 10, thumb_pos.Y + 4 + 16); + dc.DrawLine(pen, thumb_pos.X + 10, thumb_pos.Y + 4, thumb_pos.X + 5, thumb_pos.Y - 1); + dc.DrawLine(pen, thumb_pos.X, thumb_pos.Y + 20, thumb_pos.X + 10, thumb_pos.Y + 20); + + dc.FillRectangle(br_thumb, thumb_pos.X + 1, thumb_pos.Y + 4, 8, 15); + dc.FillRectangle(br_thumb, thumb_pos.X + 2, thumb_pos.Y + 3, 6, 1); + dc.FillRectangle(br_thumb, thumb_pos.X + 3, thumb_pos.Y + 2, 4, 1); + dc.FillRectangle(br_thumb, thumb_pos.X + 4, thumb_pos.Y + 1, 2, 1); + } + + protected virtual void TrackBarDrawHorizontalThumb(Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + Pen pen = SystemPens.ControlLightLight; + dc.DrawLine(pen, thumb_pos.X, thumb_pos.Y, thumb_pos.X + 9, thumb_pos.Y); + dc.DrawLine(pen, thumb_pos.X, thumb_pos.Y, thumb_pos.X, thumb_pos.Y + 19); + + pen = SystemPens.ControlDark; + dc.DrawLine(pen, thumb_pos.X + 9, thumb_pos.Y + 1, thumb_pos.X + 9, thumb_pos.Y + 19); + dc.DrawLine(pen, thumb_pos.X + 1, thumb_pos.Y + 10, thumb_pos.X + 8, thumb_pos.Y + 19); + + pen = SystemPens.ControlDarkDark; + dc.DrawLine(pen, thumb_pos.X + 10, thumb_pos.Y, thumb_pos.X + 10, thumb_pos.Y + 20); + dc.DrawLine(pen, thumb_pos.X, thumb_pos.Y + 20, thumb_pos.X + 9, thumb_pos.Y + 20); + + dc.FillRectangle(br_thumb, thumb_pos.X + 1, thumb_pos.Y + 1, 8, 18); + } + #endregion + + #region Ticks + protected virtual ITrackBarTickPainter TrackBarGetHorizontalTickPainter(Graphics g) + { + return GetTrackBarTickPainter(g); + } + #endregion + #endregion + + public override void DrawTrackBar(Graphics dc, Rectangle clip_rectangle, TrackBar tb) + { + Brush br_thumb; + int value_pos; + bool mouse_value; + float ticks = (tb.Maximum - tb.Minimum) / tb.tickFrequency; /* N of ticks draw*/ + Rectangle area; + Rectangle thumb_pos = tb.ThumbPos; + Rectangle thumb_area = tb.ThumbArea; + + if (tb.thumb_pressed) + { + value_pos = tb.thumb_mouseclick; + mouse_value = true; + } + else + { + value_pos = tb.Value - tb.Minimum; + mouse_value = false; + } + + area = tb.ClientRectangle; + + if (!tb.Enabled) + { + br_thumb = (Brush)ResPool.GetHatchBrush(HatchStyle.Percent50, ColorControlLightLight, ColorControlLight); + } + else if (tb.thumb_pressed == true) + { + br_thumb = (Brush)ResPool.GetHatchBrush(HatchStyle.Percent50, ColorControlLight, ColorControl); + } + else + { + br_thumb = SystemBrushes.Control; + } + + + /* Widget Background */ + if (tb.BackColor.ToArgb() == DefaultControlBackColor.ToArgb()) + { + dc.FillRectangle(SystemBrushes.Control, clip_rectangle); + } + else + { + dc.FillRectangle(ResPool.GetSolidBrush(tb.BackColor), clip_rectangle); + } + + if (tb.Focused) + { + CPDrawFocusRectangle(dc, area, tb.ForeColor, tb.BackColor); + } + + if (tb.Orientation == Orientation.Vertical) + { + DrawTrackBar_Vertical(dc, clip_rectangle, tb, ref thumb_pos, ref thumb_area, + br_thumb, ticks, value_pos, mouse_value); + + } + else + { + DrawTrackBar_Horizontal(dc, clip_rectangle, tb, ref thumb_pos, ref thumb_area, + br_thumb, ticks, value_pos, mouse_value); + } + + tb.ThumbPos = thumb_pos; + tb.ThumbArea = thumb_area; + } + + public override Size TrackBarDefaultSize + { + get + { + return new Size(104, 42); + } + } + + public override bool TrackBarHasHotThumbStyle + { + get + { + return false; + } + } + #endregion // TrackBar + + #region UpDownBase + public override void UpDownBaseDrawButton(Graphics g, Rectangle bounds, bool top, VisualStyles.PushButtonState state) + { + WidgetPaint.DrawScrollButton(g, bounds, top ? ScrollButton.Up : ScrollButton.Down, state == VisualStyles.PushButtonState.Pressed ? ButtonState.Pushed : ButtonState.Normal); + } + + public override bool UpDownBaseHasHotButtonStyle + { + get + { + return false; + } + } + #endregion + + #region VScrollBar + public override Size VScrollBarDefaultSize + { + get + { + return new Size(this.ScrollBarButtonSize, 80); + } + } + #endregion // VScrollBar + + #region TreeView + public override Size TreeViewDefaultSize + { + get + { + return new Size(121, 97); + } + } + + public override void TreeViewDrawNodePlusMinus(TreeView treeView, TreeNode node, Graphics dc, int x, int middle) + { + int height = treeView.ActualItemHeight - 2; + dc.FillRectangle(ResPool.GetSolidBrush(treeView.BackColor), (x + 4) - (height / 2), node.GetY() + 1, height, height); + + dc.DrawRectangle(SystemPens.ControlDarkDark, x, middle - 4, 8, 8); + + if (node.IsExpanded) + { + dc.DrawLine(SystemPens.ControlDarkDark, x + 2, middle, x + 6, middle); + } + else + { + dc.DrawLine(SystemPens.ControlDarkDark, x + 2, middle, x + 6, middle); + dc.DrawLine(SystemPens.ControlDarkDark, x + 4, middle - 2, x + 4, middle + 2); + } + } + #endregion + + #region Managed window + public override int ManagedWindowTitleBarHeight(InternalWindowManager wm) + { + if (wm.IsToolWindow && !wm.IsMinimized) + return SystemInformation.ToolWindowCaptionHeight; + if (wm.Form.FormBorderStyle == FormBorderStyle.None) + return 0; + return SystemInformation.CaptionHeight; + } + + public override int ManagedWindowBorderWidth(InternalWindowManager wm) + { + if ((wm.IsToolWindow && wm.form.FormBorderStyle == FormBorderStyle.FixedToolWindow) || + wm.IsMinimized) + return 3; + else + return 4; + } + + public override int ManagedWindowIconWidth(InternalWindowManager wm) + { + return ManagedWindowTitleBarHeight(wm) - 5; + } + + public override void ManagedWindowSetButtonLocations(InternalWindowManager wm) + { + TitleButtons buttons = wm.TitleButtons; + Form form = wm.form; + + buttons.HelpButton.Visible = form.HelpButton; + + foreach (TitleButton button in buttons) + { + button.Visible = false; + } + + switch (form.FormBorderStyle) + { + case FormBorderStyle.None: + if (form.WindowState != FormWindowState.Normal) + goto case FormBorderStyle.Sizable; + break; + case FormBorderStyle.FixedToolWindow: + case FormBorderStyle.SizableToolWindow: + buttons.CloseButton.Visible = true; + if (form.WindowState != FormWindowState.Normal) + goto case FormBorderStyle.Sizable; + break; + case FormBorderStyle.FixedSingle: + case FormBorderStyle.Fixed3D: + case FormBorderStyle.FixedDialog: + case FormBorderStyle.Sizable: + switch (form.WindowState) + { + case FormWindowState.Normal: + buttons.MinimizeButton.Visible = true; + buttons.MaximizeButton.Visible = true; + buttons.RestoreButton.Visible = false; + break; + case FormWindowState.Maximized: + buttons.MinimizeButton.Visible = true; + buttons.MaximizeButton.Visible = false; + buttons.RestoreButton.Visible = true; + break; + case FormWindowState.Minimized: + buttons.MinimizeButton.Visible = false; + buttons.MaximizeButton.Visible = true; + buttons.RestoreButton.Visible = true; + break; + } + buttons.CloseButton.Visible = true; + break; + } + + // Respect MinimizeBox/MaximizeBox + if (form.MinimizeBox == false && form.MaximizeBox == false) + { + buttons.MinimizeButton.Visible = false; + buttons.MaximizeButton.Visible = false; + } + else if (form.MinimizeBox == false) + buttons.MinimizeButton.State = ButtonState.Inactive; + else if (form.MaximizeBox == false) + buttons.MaximizeButton.State = ButtonState.Inactive; + + int bw = ManagedWindowBorderWidth(wm); + Size btsize = ManagedWindowButtonSize(wm); + int btw = btsize.Width; + int bth = btsize.Height; + int top = bw + 2; + int left = form.Width - bw - btw - ManagedWindowSpacingAfterLastTitleButton; + + if ((!wm.IsToolWindow || wm.IsMinimized) && wm.HasBorders) + { + buttons.CloseButton.Rectangle = new Rectangle(left, top, btw, bth); + left -= 2 + btw; + + if (buttons.MaximizeButton.Visible) + { + buttons.MaximizeButton.Rectangle = new Rectangle(left, top, btw, bth); + left -= 2 + btw; + } + if (buttons.RestoreButton.Visible) + { + buttons.RestoreButton.Rectangle = new Rectangle(left, top, btw, bth); + left -= 2 + btw; + } + + buttons.MinimizeButton.Rectangle = new Rectangle(left, top, btw, bth); + left -= 2 + btw; + } + else if (wm.IsToolWindow) + { + buttons.CloseButton.Rectangle = new Rectangle(left, top, btw, bth); + left -= 2 + btw; + } + } + + protected virtual Rectangle ManagedWindowDrawTitleBarAndBorders(Graphics dc, Rectangle clip, InternalWindowManager wm) + { + Form form = wm.Form; + int tbheight = ManagedWindowTitleBarHeight(wm); + int bdwidth = ManagedWindowBorderWidth(wm); + Color titlebar_color = Color.FromArgb(255, 10, 36, 106); + Color titlebar_color2 = Color.FromArgb(255, 166, 202, 240); + Color color = ThemeEngine.Current.ColorControlDark; + Color color2 = Color.FromArgb(255, 192, 192, 192); + + Pen pen = ResPool.GetPen(ColorControl); + Rectangle borders = new Rectangle(0, 0, form.Width, form.Height); + WidgetPaint.DrawBorder3D(dc, borders, Border3DStyle.Raised); + // The 3d border is only 2 pixels wide, so we draw the innermost pixels ourselves + borders = new Rectangle(2, 2, form.Width - 5, form.Height - 5); + for (int i = 2; i < bdwidth; i++) + { + dc.DrawRectangle(pen, borders); + borders.Inflate(-1, -1); + } + + + bool draw_titlebar_enabled = false; + if (wm.Form.Parent != null && wm.Form.Parent is Form) + { + draw_titlebar_enabled = false; + } + else if (wm.IsActive && !wm.IsMaximized) + { + draw_titlebar_enabled = true; + } + if (draw_titlebar_enabled) + { + color = titlebar_color; + color2 = titlebar_color2; + } + + Rectangle tb = new Rectangle(bdwidth, bdwidth, form.Width - (bdwidth * 2), tbheight - 1); + + // HACK: For now always draw the titlebar until we get updates better + if (tb.Width > 0 && tb.Height > 0) + { + using (System.Drawing.Drawing2D.LinearGradientBrush gradient = new LinearGradientBrush(tb, color, color2, LinearGradientMode.Horizontal)) + { + dc.FillRectangle(gradient, tb); + } + } + + if (!wm.IsMinimized) + // Draw the line just beneath the title bar + dc.DrawLine(ResPool.GetPen(SystemColors.Control), bdwidth, + tbheight + bdwidth - 1, form.Width - bdwidth - 1, + tbheight + bdwidth - 1); + return tb; + } + + public override void DrawManagedWindowDecorations(Graphics dc, Rectangle clip, InternalWindowManager wm) + { +#if debug + Console.WriteLine (DateTime.Now.ToLongTimeString () + " DrawManagedWindowDecorations"); + dc.FillRectangle (Brushes.Black, clip); +#endif + Rectangle tb = ManagedWindowDrawTitleBarAndBorders(dc, clip, wm); + + Form form = wm.Form; + if (wm.ShowIcon) + { + Rectangle icon = ManagedWindowGetTitleBarIconArea(wm); + if (icon.IntersectsWith(clip)) + dc.DrawIcon(form.Icon, icon); + const int SpacingBetweenIconAndCaption = 2; + tb.Width -= icon.Right + SpacingBetweenIconAndCaption - tb.X; + tb.X = icon.Right + SpacingBetweenIconAndCaption; + } + + foreach (TitleButton button in wm.TitleButtons.AllButtons) + { + tb.Width -= Math.Max(0, tb.Right - DrawTitleButton(dc, button, clip, form)); + } + const int SpacingBetweenCaptionAndLeftMostButton = 3; + tb.Width -= SpacingBetweenCaptionAndLeftMostButton; + + string window_caption = form.Text; + window_caption = window_caption.Replace(Environment.NewLine, string.Empty); + + if (window_caption != null && window_caption != string.Empty) + { + StringFormat format = new StringFormat(); + format.FormatFlags = StringFormatFlags.NoWrap; + format.Trimming = StringTrimming.EllipsisCharacter; + format.LineAlignment = StringAlignment.Center; + + if (tb.IntersectsWith(clip)) + dc.DrawString(window_caption, WindowBorderFont, + ThemeEngine.Current.ResPool.GetSolidBrush(Color.White), + tb, format); + } + } + + public override Size ManagedWindowButtonSize(InternalWindowManager wm) + { + int height = ManagedWindowTitleBarHeight(wm); + if (!wm.IsMaximized && !wm.IsMinimized) + { + if (wm.IsToolWindow) + return new Size(SystemInformation.ToolWindowCaptionButtonSize.Width - 2, + height - 5); + if (wm.Form.FormBorderStyle == FormBorderStyle.None) + return Size.Empty; + } + else + height = SystemInformation.CaptionHeight; + + return new Size(SystemInformation.CaptionButtonSize.Width - 2, + height - 5); + } + + private int DrawTitleButton(Graphics dc, TitleButton button, Rectangle clip, Form form) + { + if (!button.Visible) + { + return int.MaxValue; + } + + if (button.Rectangle.IntersectsWith(clip)) + { + ManagedWindowDrawTitleButton(dc, button, clip, form); + } + return button.Rectangle.Left; + } + + protected virtual void ManagedWindowDrawTitleButton(Graphics dc, TitleButton button, Rectangle clip, Form form) + { + dc.FillRectangle(SystemBrushes.Control, button.Rectangle); + + WidgetPaint.DrawCaptionButton(dc, button.Rectangle, + button.Caption, button.State); + } + + public override Rectangle ManagedWindowGetTitleBarIconArea(InternalWindowManager wm) + { + int bw = ManagedWindowBorderWidth(wm); + return new Rectangle(bw + 3, bw + 2, wm.IconWidth, wm.IconWidth); + } + + public override Size ManagedWindowGetMenuButtonSize(InternalWindowManager wm) + { + Size result = SystemInformation.MenuButtonSize; + result.Width -= 2; + result.Height -= 4; + return result; + } + + public override bool ManagedWindowTitleButtonHasHotElementStyle(TitleButton button, Form form) + { + return false; + } + + public override void ManagedWindowDrawMenuButton(Graphics dc, TitleButton button, Rectangle clip, InternalWindowManager wm) + { + dc.FillRectangle(SystemBrushes.Control, button.Rectangle); + WidgetPaint.DrawCaptionButton(dc, button.Rectangle, + button.Caption, button.State); + } + + public override void ManagedWindowOnSizeInitializedOrChanged(Form form) + { + } + #endregion + + #region WidgetPaint + public override void CPDrawBorder(Graphics graphics, Rectangle bounds, Color leftColor, int leftWidth, + ButtonBorderStyle leftStyle, Color topColor, int topWidth, ButtonBorderStyle topStyle, + Color rightColor, int rightWidth, ButtonBorderStyle rightStyle, Color bottomColor, + int bottomWidth, ButtonBorderStyle bottomStyle) + { + DrawBorderInternal(graphics, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom - 1, leftWidth, leftColor, leftStyle, Border3DSide.Left); + DrawBorderInternal(graphics, bounds.Left, bounds.Top, bounds.Right - 1, bounds.Top, topWidth, topColor, topStyle, Border3DSide.Top); + DrawBorderInternal(graphics, bounds.Right - 1, bounds.Top, bounds.Right - 1, bounds.Bottom - 1, rightWidth, rightColor, rightStyle, Border3DSide.Right); + DrawBorderInternal(graphics, bounds.Left, bounds.Bottom - 1, bounds.Right - 1, bounds.Bottom - 1, bottomWidth, bottomColor, bottomStyle, Border3DSide.Bottom); + } + + public override void CPDrawBorder(Graphics graphics, RectangleF bounds, Color leftColor, int leftWidth, + ButtonBorderStyle leftStyle, Color topColor, int topWidth, ButtonBorderStyle topStyle, + Color rightColor, int rightWidth, ButtonBorderStyle rightStyle, Color bottomColor, + int bottomWidth, ButtonBorderStyle bottomStyle) + { + DrawBorderInternal(graphics, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom - 1, leftWidth, leftColor, leftStyle, Border3DSide.Left); + DrawBorderInternal(graphics, bounds.Left, bounds.Top, bounds.Right - 1, bounds.Top, topWidth, topColor, topStyle, Border3DSide.Top); + DrawBorderInternal(graphics, bounds.Right - 1, bounds.Top, bounds.Right - 1, bounds.Bottom - 1, rightWidth, rightColor, rightStyle, Border3DSide.Right); + DrawBorderInternal(graphics, bounds.Left, bounds.Bottom - 1, bounds.Right - 1, bounds.Bottom - 1, bottomWidth, bottomColor, bottomStyle, Border3DSide.Bottom); + } + + public override void CPDrawBorder3D(Graphics graphics, Rectangle rectangle, Border3DStyle style, Border3DSide sides) + { + CPDrawBorder3D(graphics, rectangle, style, sides, ColorControl); + } + + public override void CPDrawBorder3D(Graphics graphics, Rectangle rectangle, Border3DStyle style, Border3DSide sides, Color control_color) + { + var skin = Application.CurrentSkin; + Pen penTopLeft; + Pen penTopLeftInner; + Pen penBottomRight; + Pen penBottomRightInner; + Rectangle rect = new Rectangle(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); + bool is_ColorControl = control_color.ToArgb() == ColorControl.ToArgb() ? true : false; + + if ((style & Border3DStyle.Adjust) != 0) + { + rect.Y -= 2; + rect.X -= 2; + rect.Width += 4; + rect.Height += 4; + } + + penTopLeft = penTopLeftInner = penBottomRight = penBottomRightInner = is_ColorControl ? SystemPens.Control : ResPool.GetPen(control_color); + + CPColor cpcolor = CPColor.Empty; + + if (!is_ColorControl) + cpcolor = ResPool.GetCPColor(control_color); + + switch (style) + { + case Border3DStyle.Raised: + penTopLeftInner = new Pen(skin.Border3DTopLeftInner); + penBottomRight = new Pen(skin.Border3DBottomRight); + penBottomRightInner = new Pen(skin.Border3DBottomRightInner); + break; + case Border3DStyle.Sunken: + penTopLeft = new Pen(skin.Border3DBottomRightInner); + penTopLeftInner = new Pen(skin.Border3DBottomRight); + penBottomRight = new Pen(skin.Border3DTopLeftInner); + break; + case Border3DStyle.Etched: + penTopLeft = new Pen(skin.Border3DBottomRightInner); + penTopLeftInner = new Pen(skin.Border3DTopLeftInner); + break; + case Border3DStyle.RaisedOuter: + penBottomRight = new Pen(skin.Border3DBottomRight); + break; + case Border3DStyle.SunkenOuter: + penTopLeft = new Pen(skin.Border3DBottomRightInner); + penBottomRight = new Pen(skin.Border3DTopLeftInner); + break; + case Border3DStyle.RaisedInner: + penTopLeft = new Pen(skin.Border3DTopLeftInner); + penBottomRight = new Pen(skin.Border3DBottomRightInner); + break; + case Border3DStyle.SunkenInner: + penTopLeft = new Pen(skin.Border3DBottomRight); + break; + case Border3DStyle.Flat: + penTopLeft = penBottomRight = new Pen(skin.DefaultForeColor); + break; + case Border3DStyle.Bump: + penTopLeftInner = penBottomRight = new Pen(skin.Border3DBottomRight); + break; + default: + break; + } + + bool inner = ((style != Border3DStyle.RaisedOuter) && (style != Border3DStyle.SunkenOuter)); + + if ((sides & Border3DSide.Middle) != 0) + { + Brush brush = is_ColorControl ? SystemBrushes.Control : ResPool.GetSolidBrush(control_color); + graphics.FillRectangle(brush, rect); + } + + if ((sides & Border3DSide.Left) != 0) + { + graphics.DrawLine(penTopLeft, rect.Left, rect.Bottom - 2, rect.Left, rect.Top); + if ((rect.Width > 2) && inner) + graphics.DrawLine(penTopLeftInner, rect.Left + 1, rect.Bottom - 2, rect.Left + 1, rect.Top); + } + + if ((sides & Border3DSide.Top) != 0) + { + graphics.DrawLine(penTopLeft, rect.Left, rect.Top, rect.Right - 2, rect.Top); + if ((rect.Height > 2) && inner) + graphics.DrawLine(penTopLeftInner, rect.Left + 1, rect.Top + 1, rect.Right - 3, rect.Top + 1); + } + + if ((sides & Border3DSide.Right) != 0) + { + graphics.DrawLine(penBottomRight, rect.Right - 1, rect.Top, rect.Right - 1, rect.Bottom - 1); + if ((rect.Width > 3) && inner) + graphics.DrawLine(penBottomRightInner, rect.Right - 2, rect.Top + 1, rect.Right - 2, rect.Bottom - 2); + } + + if ((sides & Border3DSide.Bottom) != 0) + { + graphics.DrawLine(penBottomRight, rect.Left, rect.Bottom - 1, rect.Right - 1, rect.Bottom - 1); + if ((rect.Height > 3) && inner) + graphics.DrawLine(penBottomRightInner, rect.Left + 1, rect.Bottom - 2, rect.Right - 2, rect.Bottom - 2); + } + } + + public override void CPDrawButton(Graphics dc, Rectangle rectangle, ButtonState state) + { + CPDrawButtonInternal(dc, rectangle, state, SystemPens.ControlDarkDark, SystemPens.ControlDark, SystemPens.ControlLight); + } + + private void CPDrawButtonInternal(Graphics dc, Rectangle rectangle, ButtonState state, Pen DarkPen, Pen NormalPen, Pen LightPen) + { + // sadly enough, the rectangle gets always filled with a hatchbrush + dc.FillRectangle(ResPool.GetHatchBrush(HatchStyle.Percent50, + Color.FromArgb(Clamp(ColorControl.R + 3, 0, 255), + ColorControl.G, ColorControl.B), + ColorControl), + rectangle.X + 1, rectangle.Y + 1, rectangle.Width - 2, rectangle.Height - 2); + + if ((state & ButtonState.All) == ButtonState.All || ((state & ButtonState.Checked) == ButtonState.Checked && (state & ButtonState.Flat) == ButtonState.Flat)) + { + dc.FillRectangle(ResPool.GetHatchBrush(HatchStyle.Percent50, ColorControlLight, ColorControl), rectangle.X + 2, rectangle.Y + 2, rectangle.Width - 4, rectangle.Height - 4); + + dc.DrawRectangle(SystemPens.ControlDark, rectangle.X, rectangle.Y, rectangle.Width - 1, rectangle.Height - 1); + } + else + if ((state & ButtonState.Flat) == ButtonState.Flat) + { + dc.DrawRectangle(SystemPens.ControlDark, rectangle.X, rectangle.Y, rectangle.Width - 1, rectangle.Height - 1); + } + else + if ((state & ButtonState.Checked) == ButtonState.Checked) + { + dc.FillRectangle(ResPool.GetHatchBrush(HatchStyle.Percent50, ColorControlLight, ColorControl), rectangle.X + 2, rectangle.Y + 2, rectangle.Width - 4, rectangle.Height - 4); + + Pen pen = DarkPen; + dc.DrawLine(pen, rectangle.X, rectangle.Y, rectangle.X, rectangle.Bottom - 2); + dc.DrawLine(pen, rectangle.X + 1, rectangle.Y, rectangle.Right - 2, rectangle.Y); + + pen = NormalPen; + dc.DrawLine(pen, rectangle.X + 1, rectangle.Y + 1, rectangle.X + 1, rectangle.Bottom - 3); + dc.DrawLine(pen, rectangle.X + 2, rectangle.Y + 1, rectangle.Right - 3, rectangle.Y + 1); + + pen = LightPen; + dc.DrawLine(pen, rectangle.X, rectangle.Bottom - 1, rectangle.Right - 2, rectangle.Bottom - 1); + dc.DrawLine(pen, rectangle.Right - 1, rectangle.Y, rectangle.Right - 1, rectangle.Bottom - 1); + } + else + if (((state & ButtonState.Pushed) == ButtonState.Pushed) && ((state & ButtonState.Normal) == ButtonState.Normal)) + { + Pen pen = DarkPen; + dc.DrawLine(pen, rectangle.X, rectangle.Y, rectangle.X, rectangle.Bottom - 2); + dc.DrawLine(pen, rectangle.X + 1, rectangle.Y, rectangle.Right - 2, rectangle.Y); + + pen = NormalPen; + dc.DrawLine(pen, rectangle.X + 1, rectangle.Y + 1, rectangle.X + 1, rectangle.Bottom - 3); + dc.DrawLine(pen, rectangle.X + 2, rectangle.Y + 1, rectangle.Right - 3, rectangle.Y + 1); + + pen = LightPen; + dc.DrawLine(pen, rectangle.X, rectangle.Bottom - 1, rectangle.Right - 2, rectangle.Bottom - 1); + dc.DrawLine(pen, rectangle.Right - 1, rectangle.Y, rectangle.Right - 1, rectangle.Bottom - 1); + } + else + if (((state & ButtonState.Inactive) == ButtonState.Inactive) || ((state & ButtonState.Normal) == ButtonState.Normal)) + { + Pen pen = LightPen; + dc.DrawLine(pen, rectangle.X, rectangle.Y, rectangle.Right - 2, rectangle.Y); + dc.DrawLine(pen, rectangle.X, rectangle.Y, rectangle.X, rectangle.Bottom - 2); + + pen = NormalPen; + dc.DrawLine(pen, rectangle.X + 1, rectangle.Bottom - 2, rectangle.Right - 2, rectangle.Bottom - 2); + dc.DrawLine(pen, rectangle.Right - 2, rectangle.Y + 1, rectangle.Right - 2, rectangle.Bottom - 3); + + pen = DarkPen; + dc.DrawLine(pen, rectangle.X, rectangle.Bottom - 1, rectangle.Right - 1, rectangle.Bottom - 1); + dc.DrawLine(pen, rectangle.Right - 1, rectangle.Y, rectangle.Right - 1, rectangle.Bottom - 2); + } + } + + + public override void CPDrawCaptionButton(Graphics graphics, Rectangle rectangle, CaptionButton button, ButtonState state) + { + Rectangle captionRect; + int lineWidth; + + CPDrawButtonInternal(graphics, rectangle, state, SystemPens.ControlDarkDark, SystemPens.ControlDark, SystemPens.ControlLightLight); + + if (rectangle.Width < rectangle.Height) + { + captionRect = new Rectangle(rectangle.X + 1, rectangle.Y + rectangle.Height / 2 - rectangle.Width / 2 + 1, rectangle.Width - 4, rectangle.Width - 4); + } + else + { + captionRect = new Rectangle(rectangle.X + rectangle.Width / 2 - rectangle.Height / 2 + 1, rectangle.Y + 1, rectangle.Height - 4, rectangle.Height - 4); + } + + if ((state & ButtonState.Pushed) != 0) + { + captionRect = new Rectangle(rectangle.X + 2, rectangle.Y + 2, rectangle.Width - 3, rectangle.Height - 3); + } + + /* Make sure we've got at least a line width of 1 */ + lineWidth = Math.Max(1, captionRect.Width / 7); + + switch (button) + { + case CaptionButton.Close: + { + Pen pen; + + if ((state & ButtonState.Inactive) != 0) + { + pen = ResPool.GetSizedPen(ColorControlLight, lineWidth); + DrawCaptionHelper(graphics, ColorControlLight, pen, lineWidth, 1, captionRect, button); + + pen = ResPool.GetSizedPen(ColorControlDark, lineWidth); + DrawCaptionHelper(graphics, ColorControlDark, pen, lineWidth, 0, captionRect, button); + return; + } + else + { + pen = ResPool.GetSizedPen(ColorControlText, lineWidth); + DrawCaptionHelper(graphics, ColorControlText, pen, lineWidth, 0, captionRect, button); + return; + } + } + + case CaptionButton.Help: + case CaptionButton.Maximize: + case CaptionButton.Minimize: + case CaptionButton.Restore: + { + if ((state & ButtonState.Inactive) != 0) + { + DrawCaptionHelper(graphics, ColorControlLight, SystemPens.ControlLightLight, lineWidth, 1, captionRect, button); + + DrawCaptionHelper(graphics, ColorControlDark, SystemPens.ControlDark, lineWidth, 0, captionRect, button); + return; + } + else + { + DrawCaptionHelper(graphics, ColorControlText, SystemPens.ControlText, lineWidth, 0, captionRect, button); + return; + } + } + } + } + + public override void CPDrawCheckBox(Graphics dc, Rectangle rectangle, ButtonState state) + { + CPDrawCheckBoxInternal(dc, rectangle, state, false /* mixed */); + } + + private void CPDrawCheckBoxInternal(Graphics dc, Rectangle rectangle, ButtonState state, bool mixed) + { + Pen check_pen = (mixed) ? Pens.Gray : Pens.Black; + + Rectangle cb_rect = new Rectangle(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); + + if ((state & ButtonState.All) == ButtonState.All) + { + cb_rect.Width -= 2; + cb_rect.Height -= 2; + + dc.FillRectangle(SystemBrushes.Control, cb_rect.X, cb_rect.Y, cb_rect.Width - 1, cb_rect.Height - 1); + dc.DrawRectangle(SystemPens.ControlDark, cb_rect.X, cb_rect.Y, cb_rect.Width - 1, cb_rect.Height - 1); + + check_pen = SystemPens.ControlDark; + } + else + if ((state & ButtonState.Flat) == ButtonState.Flat) + { + cb_rect.Width -= 2; + cb_rect.Height -= 2; + + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + dc.FillRectangle(SystemBrushes.ControlLight, cb_rect.X, cb_rect.Y, cb_rect.Width - 1, cb_rect.Height - 1); + else + dc.FillRectangle(Brushes.White, cb_rect.X, cb_rect.Y, cb_rect.Width - 1, cb_rect.Height - 1); + dc.DrawRectangle(SystemPens.ControlDark, cb_rect.X, cb_rect.Y, cb_rect.Width - 1, cb_rect.Height - 1); + } + else + { + cb_rect.Width -= 1; + cb_rect.Height -= 1; + + int check_box_visible_size = (cb_rect.Height > cb_rect.Width) ? cb_rect.Width : cb_rect.Height; + + int x_pos = Math.Max(0, cb_rect.X + (cb_rect.Width / 2) - check_box_visible_size / 2); + int y_pos = Math.Max(0, cb_rect.Y + (cb_rect.Height / 2) - check_box_visible_size / 2); + + Rectangle rect = new Rectangle(x_pos, y_pos, check_box_visible_size, check_box_visible_size); + + if (((state & ButtonState.Pushed) == ButtonState.Pushed) || ((state & ButtonState.Inactive) == ButtonState.Inactive)) + { + dc.FillRectangle(ResPool.GetHatchBrush(HatchStyle.Percent50, + Color.FromArgb(Clamp(ColorControl.R + 3, 0, 255), + ColorControl.G, ColorControl.B), + ColorControl), rect.X + 2, rect.Y + 2, rect.Width - 3, rect.Height - 3); + } + else + dc.FillRectangle(SystemBrushes.ControlLightLight, rect.X + 2, rect.Y + 2, rect.Width - 3, rect.Height - 3); + + Pen pen = SystemPens.ControlDark; + dc.DrawLine(pen, rect.X, rect.Y, rect.X, rect.Bottom - 1); + dc.DrawLine(pen, rect.X + 1, rect.Y, rect.Right - 1, rect.Y); + + pen = SystemPens.ControlDarkDark; + dc.DrawLine(pen, rect.X + 1, rect.Y + 1, rect.X + 1, rect.Bottom - 2); + dc.DrawLine(pen, rect.X + 2, rect.Y + 1, rect.Right - 2, rect.Y + 1); + + pen = SystemPens.ControlLightLight; + dc.DrawLine(pen, rect.Right, rect.Y, rect.Right, rect.Bottom); + dc.DrawLine(pen, rect.X, rect.Bottom, rect.Right, rect.Bottom); + + // oh boy, matching ms is like fighting against windmills + using (Pen h_pen = new Pen(ResPool.GetHatchBrush(HatchStyle.Percent50, + Color.FromArgb(Clamp(ColorControl.R + 3, 0, 255), + ColorControl.G, ColorControl.B), ColorControl))) + { + dc.DrawLine(h_pen, rect.X + 1, rect.Bottom - 1, rect.Right - 1, rect.Bottom - 1); + dc.DrawLine(h_pen, rect.Right - 1, rect.Y + 1, rect.Right - 1, rect.Bottom - 1); + } + + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + check_pen = SystemPens.ControlDark; + } + + if ((state & ButtonState.Checked) == ButtonState.Checked) + { + int check_size = (cb_rect.Height > cb_rect.Width) ? cb_rect.Width / 2 : cb_rect.Height / 2; + + if (check_size < 7) + { + int lineWidth = Math.Max(3, check_size / 3); + int Scale = Math.Max(1, check_size / 9); + + Rectangle rect = new Rectangle(cb_rect.X + (cb_rect.Width / 2) - (int)Math.Ceiling((float)check_size / 2) - 1, cb_rect.Y + (cb_rect.Height / 2) - (check_size / 2) - 1, + check_size, check_size); + + for (int i = 0; i < lineWidth; i++) + { + dc.DrawLine(check_pen, rect.Left + lineWidth / 2, rect.Top + lineWidth + i, rect.Left + lineWidth / 2 + 2 * Scale, rect.Top + lineWidth + 2 * Scale + i); + dc.DrawLine(check_pen, rect.Left + lineWidth / 2 + 2 * Scale, rect.Top + lineWidth + 2 * Scale + i, rect.Left + lineWidth / 2 + 6 * Scale, rect.Top + lineWidth - 2 * Scale + i); + } + } + else + { + int lineWidth = Math.Max(3, check_size / 3) + 1; + + int x_half = cb_rect.Width / 2; + int y_half = cb_rect.Height / 2; + + Rectangle rect = new Rectangle(cb_rect.X + x_half - (check_size / 2) - 1, cb_rect.Y + y_half - (check_size / 2), + check_size, check_size); + + int gradient_left = check_size / 3; + int gradient_right = check_size - gradient_left - 1; + + + for (int i = 0; i < lineWidth; i++) + { + dc.DrawLine(check_pen, rect.X, rect.Bottom - 1 - gradient_left - i, rect.X + gradient_left, rect.Bottom - 1 - i); + dc.DrawLine(check_pen, rect.X + gradient_left, rect.Bottom - 1 - i, rect.Right - 1, rect.Bottom - i - 1 - gradient_right); + } + } + } + } + + public override void CPDrawComboButton(Graphics graphics, Rectangle rectangle, ButtonState state) + { + Point[] arrow = new Point[3]; + Point P1; + Point P2; + Point P3; + int centerX; + int centerY; + int shiftX; + int shiftY; + Rectangle rect; + + if ((state & ButtonState.Checked) != 0) + { + graphics.FillRectangle(ResPool.GetHatchBrush(HatchStyle.Percent50, ColorControlLightLight, ColorControlLight), rectangle); + } + + if ((state & ButtonState.Flat) != 0) + { + WidgetPaint.DrawBorder(graphics, rectangle, ColorControlDark, ButtonBorderStyle.Solid); + } + else + { + if ((state & (ButtonState.Pushed | ButtonState.Checked)) != 0) + { + // this needs to render like a pushed button - jba + // CPDrawBorder3D(graphics, rectangle, Border3DStyle.Sunken, Border3DSide.Left | Border3DSide.Top | Border3DSide.Right | Border3DSide.Bottom, ColorControl); + Rectangle trace_rectangle = new Rectangle(rectangle.X, rectangle.Y, Math.Max(rectangle.Width - 1, 0), Math.Max(rectangle.Height - 1, 0)); + graphics.DrawRectangle(SystemPens.ControlDark, trace_rectangle); + } + else + { + CPDrawBorder3D(graphics, rectangle, Border3DStyle.Raised, Border3DSide.Left | Border3DSide.Top | Border3DSide.Right | Border3DSide.Bottom, ColorControl); + } + } + + rect = new Rectangle(rectangle.X + rectangle.Width / 4, rectangle.Y + rectangle.Height / 4, rectangle.Width / 2, rectangle.Height / 2); + centerX = rect.Left + rect.Width / 2; + centerY = rect.Top + rect.Height / 2; + shiftX = Math.Max(1, rect.Width / 8); + shiftY = Math.Max(1, rect.Height / 8); + + if ((state & ButtonState.Pushed) != 0) + { + shiftX++; + shiftY++; + } + + rect.Y -= shiftY; + centerY -= shiftY; + P1 = new Point(rect.Left, centerY); + P2 = new Point(rect.Right, centerY); + P3 = new Point(centerX, rect.Bottom); + + arrow[0] = P1; + arrow[1] = P2; + arrow[2] = P3; + + /* Draw the arrow */ + if ((state & ButtonState.Inactive) != 0) + { + /* Move away from the shadow */ + arrow[0].X += 1; arrow[0].Y += 1; + arrow[1].X += 1; arrow[1].Y += 1; + arrow[2].X += 1; arrow[2].Y += 1; + + graphics.FillPolygon(SystemBrushes.ControlLightLight, arrow, FillMode.Winding); + + arrow[0] = P1; + arrow[1] = P2; + arrow[2] = P3; + + graphics.FillPolygon(SystemBrushes.ControlDark, arrow, FillMode.Winding); + } + else + { + graphics.FillPolygon(SystemBrushes.ControlText, arrow, FillMode.Winding); + } + } + + public override void CPDrawContainerGrabHandle(Graphics graphics, Rectangle bounds) + { + Pen pen = Pens.Black; + Rectangle rect = new Rectangle(bounds.X, bounds.Y, bounds.Width - 1, bounds.Height - 1); // Dunno why, but MS does it that way, too + int X; + int Y; + + graphics.FillRectangle(SystemBrushes.ControlLightLight, rect); + graphics.DrawRectangle(pen, rect); + + X = rect.X + rect.Width / 2; + Y = rect.Y + rect.Height / 2; + + /* Draw the cross */ + graphics.DrawLine(pen, X, rect.Y + 2, X, rect.Bottom - 2); + graphics.DrawLine(pen, rect.X + 2, Y, rect.Right - 2, Y); + + /* Draw 'arrows' for vertical lines */ + graphics.DrawLine(pen, X - 1, rect.Y + 3, X + 1, rect.Y + 3); + graphics.DrawLine(pen, X - 1, rect.Bottom - 3, X + 1, rect.Bottom - 3); + + /* Draw 'arrows' for horizontal lines */ + graphics.DrawLine(pen, rect.X + 3, Y - 1, rect.X + 3, Y + 1); + graphics.DrawLine(pen, rect.Right - 3, Y - 1, rect.Right - 3, Y + 1); + } + + public virtual void DrawFlatStyleFocusRectangle(Graphics graphics, Rectangle rectangle, ButtonBase button, Color foreColor, Color backColor) + { + // make a rectange to trace around border of the button + Rectangle trace_rectangle = new Rectangle(rectangle.X, rectangle.Y, Math.Max(rectangle.Width - 1, 0), Math.Max(rectangle.Height - 1, 0)); + + Color outerColor = foreColor; + // adjust focus color according to the flatstyle + if (button.FlatStyle == FlatStyle.Popup && !button.is_pressed) + { + outerColor = (backColor.ToArgb() == ColorControl.ToArgb()) ? WidgetPaint.Dark(ColorControl) : ColorControlText; + } + + // draw the outer rectangle + graphics.DrawRectangle(ResPool.GetPen(outerColor), trace_rectangle); + + // draw the inner rectangle + if (button.FlatStyle == FlatStyle.Popup) + { + DrawInnerFocusRectangle(graphics, Rectangle.Inflate(rectangle, -4, -4), backColor); + } + else + { + // draw a flat inner rectangle + Pen pen = ResPool.GetPen(WidgetPaint.LightLight(backColor)); + graphics.DrawRectangle(pen, Rectangle.Inflate(trace_rectangle, -4, -4)); + } + } + + public virtual void DrawInnerFocusRectangle(Graphics graphics, Rectangle rectangle, Color backColor) + { + // make a rectange to trace around border of the button + Rectangle trace_rectangle = new Rectangle(rectangle.X, rectangle.Y, Math.Max(rectangle.Width - 1, 0), Math.Max(rectangle.Height - 1, 0)); + +#if NotUntilCairoIsFixed + Color colorBackInverted = Color.FromArgb (Math.Abs (backColor.R-255), Math.Abs (backColor.G-255), Math.Abs (backColor.B-255)); + DashStyle oldStyle; // used for caching old penstyle + Pen pen = ResPool.GetPen (colorBackInverted); + + oldStyle = pen.DashStyle; + pen.DashStyle = DashStyle.Dot; + + graphics.DrawRectangle (pen, trace_rectangle); + pen.DashStyle = oldStyle; +#else + CPDrawFocusRectangle(graphics, trace_rectangle, Color.Wheat, backColor); +#endif + } + + + public override void CPDrawFocusRectangle(Graphics graphics, Rectangle rectangle, Color foreColor, Color backColor) + { + Rectangle rect = rectangle; + Pen pen; + HatchBrush brush; + + if (backColor.GetBrightness() >= 0.5) + { + foreColor = Color.Transparent; + backColor = Color.Black; + + } + else + { + backColor = Color.FromArgb(Math.Abs(backColor.R - 255), Math.Abs(backColor.G - 255), Math.Abs(backColor.B - 255)); + foreColor = Color.Black; + } + + brush = ResPool.GetHatchBrush(HatchStyle.Percent50, backColor, foreColor); + pen = new Pen(brush, 1); + + rect.Width--; + rect.Height--; + + graphics.DrawRectangle(pen, rect); + pen.Dispose(); + } + + public override void CPDrawGrabHandle(Graphics graphics, Rectangle rectangle, bool primary, bool enabled) + { + Brush sb; + Pen pen; + + if (primary == true) + { + pen = Pens.Black; + if (enabled == true) + { + sb = Brushes.White; + } + else + { + sb = SystemBrushes.Control; + } + } + else + { + pen = Pens.White; + if (enabled == true) + { + sb = Brushes.Black; + } + else + { + sb = SystemBrushes.Control; + } + } + graphics.FillRectangle(sb, rectangle); + graphics.DrawRectangle(pen, rectangle); + } + + + public override void CPDrawGrid(Graphics graphics, Rectangle area, Size pixelsBetweenDots, Color backColor) + { + Color foreColor; + int h; + int b; + int s; + + WidgetPaint.Color2HBS(backColor, out h, out b, out s); + + if (b > 127) + { + foreColor = Color.Black; + } + else + { + foreColor = Color.White; + } + + // still not perfect. it seems that ms calculates the position of the first dot or line + + using (Pen pen = new Pen(foreColor)) + { + pen.DashPattern = new float[] { 1.0f, pixelsBetweenDots.Width - 1 }; + + for (int y = area.Top; y < area.Bottom; y += pixelsBetweenDots.Height) + graphics.DrawLine(pen, area.X, y, area.Right - 1, y); + } + } + + public override void CPDrawImageDisabled(Graphics graphics, Image image, int x, int y, Color background) + { + /* + Microsoft seems to ignore the background and simply make + the image grayscale. At least when having > 256 colors on + the display. + */ + + if (imagedisabled_attributes == null) + { + imagedisabled_attributes = new ImageAttributes(); + ColorMatrix colorMatrix = new ColorMatrix(new float[][] { + // This table would create a perfect grayscale image, based on luminance + // new float[]{0.3f,0.3f,0.3f,0,0}, + // new float[]{0.59f,0.59f,0.59f,0,0}, + // new float[]{0.11f,0.11f,0.11f,0,0}, + // new float[]{0,0,0,1,0,0}, + // new float[]{0,0,0,0,1,0}, + // new float[]{0,0,0,0,0,1} + + // This table generates a image that is grayscaled and then + // brightened up. Seems to match MS close enough. + new float[]{0.2f,0.2f,0.2f,0,0}, + new float[]{0.41f,0.41f,0.41f,0,0}, + new float[]{0.11f,0.11f,0.11f,0,0}, + new float[]{0.15f,0.15f,0.15f,1,0,0}, + new float[]{0.15f,0.15f,0.15f,0,1,0}, + new float[]{0.15f,0.15f,0.15f,0,0,1} + }); + + imagedisabled_attributes.SetColorMatrix(colorMatrix); + } + + graphics.DrawImage(image, new Rectangle(x, y, image.Width, image.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, imagedisabled_attributes); + + } + + + public override void CPDrawLockedFrame(Graphics graphics, Rectangle rectangle, bool primary) + { + Pen penBorder; + Pen penInside; + + if (primary) + { + penBorder = ResPool.GetSizedPen(Color.White, 2); + penInside = ResPool.GetPen(Color.Black); + } + else + { + penBorder = ResPool.GetSizedPen(Color.Black, 2); + penInside = ResPool.GetPen(Color.White); + } + penBorder.Alignment = PenAlignment.Inset; + penInside.Alignment = PenAlignment.Inset; + + graphics.DrawRectangle(penBorder, rectangle); + graphics.DrawRectangle(penInside, rectangle.X + 2, rectangle.Y + 2, rectangle.Width - 5, rectangle.Height - 5); + } + + + public override void CPDrawMenuGlyph(Graphics graphics, Rectangle rectangle, MenuGlyph glyph, Color color, Color backColor) + { + Rectangle rect; + int lineWidth; + + if (backColor != Color.Empty) + graphics.FillRectangle(ResPool.GetSolidBrush(backColor), rectangle); + + Brush brush = ResPool.GetSolidBrush(color); + + switch (glyph) + { + case MenuGlyph.Arrow: + { + float height = rectangle.Height * 0.7f; + float width = height / 2.0f; + + PointF ddCenter = new PointF(rectangle.X + ((rectangle.Width - width) / 2.0f), rectangle.Y + (rectangle.Height / 2.0f)); + + PointF[] vertices = new PointF[3]; + vertices[0].X = ddCenter.X; + vertices[0].Y = ddCenter.Y - (height / 2.0f); + vertices[1].X = ddCenter.X; + vertices[1].Y = ddCenter.Y + (height / 2.0f); + vertices[2].X = ddCenter.X + width + 0.1f; + vertices[2].Y = ddCenter.Y; + + graphics.FillPolygon(brush, vertices); + + return; + } + + case MenuGlyph.Bullet: + { + + lineWidth = Math.Max(2, rectangle.Width / 3); + rect = new Rectangle(rectangle.X + lineWidth, rectangle.Y + lineWidth, rectangle.Width - lineWidth * 2, rectangle.Height - lineWidth * 2); + + graphics.FillEllipse(brush, rect); + + return; + } + + case MenuGlyph.Checkmark: + { + + Pen pen = ResPool.GetPen(color); + lineWidth = Math.Max(2, rectangle.Width / 6); + rect = new Rectangle(rectangle.X + lineWidth, rectangle.Y + lineWidth, rectangle.Width - lineWidth * 2, rectangle.Height - lineWidth * 2); + + int Scale = Math.Max(1, rectangle.Width / 12); + int top = (rect.Y + lineWidth + ((rect.Height - ((2 * Scale) + lineWidth)) / 2)); + + for (int i = 0; i < lineWidth; i++) + { + graphics.DrawLine(pen, rect.Left + lineWidth / 2, top + i, rect.Left + lineWidth / 2 + 2 * Scale, top + 2 * Scale + i); + graphics.DrawLine(pen, rect.Left + lineWidth / 2 + 2 * Scale, top + 2 * Scale + i, rect.Left + lineWidth / 2 + 6 * Scale, top - 2 * Scale + i); + } + return; + } + } + + } + + public override void CPDrawMixedCheckBox(Graphics graphics, Rectangle rectangle, ButtonState state) + { + CPDrawCheckBoxInternal(graphics, rectangle, state, true /* mixed */); + } + + public override void CPDrawRadioButton(Graphics dc, Rectangle rectangle, ButtonState state) + { + CPColor cpcolor = ResPool.GetCPColor(ColorControl); + + Color dot_color = Color.Black; + + Color top_left_outer = Color.Black; + Color top_left_inner = Color.Black; + Color bottom_right_outer = Color.Black; + Color bottom_right_inner = Color.Black; + + int ellipse_diameter = (rectangle.Width > rectangle.Height) ? (int)(rectangle.Height * 0.9f) : (int)(rectangle.Width * 0.9f); + int radius = ellipse_diameter / 2; + + Rectangle rb_rect = new Rectangle(rectangle.X + (rectangle.Width / 2) - radius, rectangle.Y + (rectangle.Height / 2) - radius, ellipse_diameter, ellipse_diameter); + + Brush brush = null; + + if ((state & ButtonState.All) == ButtonState.All) + { + brush = ResPool.GetHatchBrush(HatchStyle.Percent50, Color.FromArgb(Clamp(ColorControl.R + 3, 0, 255), + ColorControl.G, ColorControl.B), ColorControl); + dot_color = cpcolor.Dark; + } + else + if ((state & ButtonState.Flat) == ButtonState.Flat) + { + if (((state & ButtonState.Inactive) == ButtonState.Inactive) || ((state & ButtonState.Pushed) == ButtonState.Pushed)) + brush = ResPool.GetHatchBrush(HatchStyle.Percent50, Color.FromArgb(Clamp(ColorControl.R + 3, 0, 255), ColorControl.G, ColorControl.B), ColorControl); + else + brush = SystemBrushes.ControlLightLight; + } + else + { + if (((state & ButtonState.Inactive) == ButtonState.Inactive) || ((state & ButtonState.Pushed) == ButtonState.Pushed)) + brush = ResPool.GetHatchBrush(HatchStyle.Percent50, Color.FromArgb(Clamp(ColorControl.R + 3, 0, 255), ColorControl.G, ColorControl.B), ColorControl); + else + brush = SystemBrushes.ControlLightLight; + + top_left_outer = cpcolor.Dark; + top_left_inner = cpcolor.DarkDark; + bottom_right_outer = cpcolor.Light; + bottom_right_inner = Color.Transparent; + + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + dot_color = cpcolor.Dark; + } + + dc.FillEllipse(brush, rb_rect.X + 1, rb_rect.Y + 1, ellipse_diameter - 1, ellipse_diameter - 1); + + int line_width = Math.Max(1, (int)(ellipse_diameter * 0.08f)); + + dc.DrawArc(ResPool.GetSizedPen(top_left_outer, line_width), rb_rect, 135.0f, 180.0f); + dc.DrawArc(ResPool.GetSizedPen(top_left_inner, line_width), Rectangle.Inflate(rb_rect, -line_width, -line_width), 135.0f, 180.0f); + dc.DrawArc(ResPool.GetSizedPen(bottom_right_outer, line_width), rb_rect, 315.0f, 180.0f); + + if (bottom_right_inner != Color.Transparent) + dc.DrawArc(ResPool.GetSizedPen(bottom_right_inner, line_width), Rectangle.Inflate(rb_rect, -line_width, -line_width), 315.0f, 180.0f); + else + using (Pen h_pen = new Pen(ResPool.GetHatchBrush(HatchStyle.Percent50, Color.FromArgb(Clamp(ColorControl.R + 3, 0, 255), ColorControl.G, ColorControl.B), ColorControl), line_width)) + { + dc.DrawArc(h_pen, Rectangle.Inflate(rb_rect, -line_width, -line_width), 315.0f, 180.0f); + } + + if ((state & ButtonState.Checked) == ButtonState.Checked) + { + int inflate = line_width * 4; + Rectangle tmp = Rectangle.Inflate(rb_rect, -inflate, -inflate); + if (rectangle.Height > 13) + { + tmp.X += 1; + tmp.Y += 1; + tmp.Height -= 1; + dc.FillEllipse(ResPool.GetSolidBrush(dot_color), tmp); + } + else + { + Pen pen = ResPool.GetPen(dot_color); + dc.DrawLine(pen, tmp.X, tmp.Y + (tmp.Height / 2), tmp.Right, tmp.Y + (tmp.Height / 2)); + dc.DrawLine(pen, tmp.X, tmp.Y + (tmp.Height / 2) + 1, tmp.Right, tmp.Y + (tmp.Height / 2) + 1); + + dc.DrawLine(pen, tmp.X + (tmp.Width / 2), tmp.Y, tmp.X + (tmp.Width / 2), tmp.Bottom); + dc.DrawLine(pen, tmp.X + (tmp.Width / 2) + 1, tmp.Y, tmp.X + (tmp.Width / 2) + 1, tmp.Bottom); + } + } + } + + public override void CPDrawReversibleFrame(Rectangle rectangle, Color backColor, FrameStyle style) + { + + } + + + public override void CPDrawReversibleLine(Point start, Point end, Color backColor) + { + + } + + + /* Scroll button: regular button + direction arrow */ + public override void CPDrawScrollButton(Graphics dc, Rectangle area, ScrollButton type, ButtonState state) + { + DrawScrollButtonPrimitive(dc, area, state); + + bool fill_rect = true; + int offset = 0; + + if ((state & ButtonState.Pushed) != 0) + offset = 1; + + // skip the border + Rectangle rect = new Rectangle(area.X + 2 + offset, area.Y + 2 + offset, area.Width - 4, area.Height - 4); + + Point[] arrow = new Point[3]; + for (int i = 0; i < 3; i++) + arrow[i] = new Point(); + + Pen pen = SystemPens.ControlText; + + if ((state & ButtonState.Inactive) != 0) + { + pen = SystemPens.ControlDark; + } + + switch (type) + { + default: + case ScrollButton.Down: + int x_middle = (int)Math.Round(rect.Width / 2.0f) - 1; + int y_middle = (int)Math.Round(rect.Height / 2.0f) - 1; + if (x_middle == 1) + x_middle = 2; + + int triangle_height; + + if (rect.Height < 8) + { + triangle_height = 2; + fill_rect = false; + } + else if (rect.Height == 11) + { + triangle_height = 3; + } + else + { + triangle_height = (int)Math.Round(rect.Height / 3.0f); + } + + arrow[0].X = rect.X + x_middle; + arrow[0].Y = rect.Y + y_middle + triangle_height / 2; + + arrow[1].X = arrow[0].X + triangle_height - 1; + arrow[1].Y = arrow[0].Y - triangle_height + 1; + arrow[2].X = arrow[0].X - triangle_height + 1; + arrow[2].Y = arrow[1].Y; + + dc.DrawPolygon(pen, arrow); + + if ((state & ButtonState.Inactive) != 0) + { + dc.DrawLine(SystemPens.ControlLightLight, arrow[1].X + 1, arrow[1].Y + 1, arrow[0].X + 1, arrow[0].Y + 1); + dc.DrawLine(SystemPens.ControlLightLight, arrow[1].X, arrow[1].Y + 1, arrow[0].X + 1, arrow[0].Y); + } + + if (fill_rect) + { + for (int i = 0; i < arrow[0].Y - arrow[1].Y; i++) + { + dc.DrawLine(pen, arrow[1].X, arrow[1].Y + i, arrow[2].X, arrow[1].Y + i); + arrow[1].X -= 1; + arrow[2].X += 1; + } + } + break; + + case ScrollButton.Up: + x_middle = (int)Math.Round(rect.Width / 2.0f) - 1; + y_middle = (int)Math.Round(rect.Height / 2.0f); + if (x_middle == 1) + x_middle = 2; + + if (y_middle == 1) + y_middle = 2; + + if (rect.Height < 8) + { + triangle_height = 2; + fill_rect = false; + } + else if (rect.Height == 11) + { + triangle_height = 3; + } + else + { + triangle_height = (int)Math.Round(rect.Height / 3.0f); + } + + arrow[0].X = rect.X + x_middle; + arrow[0].Y = rect.Y + y_middle - triangle_height / 2; + + arrow[1].X = arrow[0].X + triangle_height - 1; + arrow[1].Y = arrow[0].Y + triangle_height - 1; + arrow[2].X = arrow[0].X - triangle_height + 1; + arrow[2].Y = arrow[1].Y; + + dc.DrawPolygon(pen, arrow); + + if ((state & ButtonState.Inactive) != 0) + { + dc.DrawLine(SystemPens.ControlLightLight, arrow[1].X + 1, arrow[1].Y + 1, arrow[2].X + 1, arrow[1].Y + 1); + } + + if (fill_rect) + { + for (int i = 0; i < arrow[1].Y - arrow[0].Y; i++) + { + dc.DrawLine(pen, arrow[2].X, arrow[1].Y - i, arrow[1].X, arrow[1].Y - i); + arrow[1].X -= 1; + arrow[2].X += 1; + } + } + break; + + case ScrollButton.Left: + y_middle = (int)Math.Round(rect.Height / 2.0f) - 1; + if (y_middle == 1) + y_middle = 2; + + int triangle_width; + + if (rect.Width < 8) + { + triangle_width = 2; + fill_rect = false; + } + else if (rect.Width == 11) + { + triangle_width = 3; + } + else + { + triangle_width = (int)Math.Round(rect.Width / 3.0f); + } + + arrow[0].X = rect.Left + triangle_width - 1; + arrow[0].Y = rect.Y + y_middle; + + if (arrow[0].X - 1 == rect.X) + arrow[0].X += 1; + + arrow[1].X = arrow[0].X + triangle_width - 1; + arrow[1].Y = arrow[0].Y - triangle_width + 1; + arrow[2].X = arrow[1].X; + arrow[2].Y = arrow[0].Y + triangle_width - 1; + + dc.DrawPolygon(pen, arrow); + + if ((state & ButtonState.Inactive) != 0) + { + dc.DrawLine(SystemPens.ControlLightLight, arrow[1].X + 1, arrow[1].Y + 1, arrow[2].X + 1, arrow[2].Y + 1); + } + + if (fill_rect) + { + for (int i = 0; i < arrow[2].X - arrow[0].X; i++) + { + dc.DrawLine(pen, arrow[2].X - i, arrow[1].Y, arrow[2].X - i, arrow[2].Y); + arrow[1].Y += 1; + arrow[2].Y -= 1; + } + } + break; + + case ScrollButton.Right: + y_middle = (int)Math.Round(rect.Height / 2.0f) - 1; + if (y_middle == 1) + y_middle = 2; + + if (rect.Width < 8) + { + triangle_width = 2; + fill_rect = false; + } + else if (rect.Width == 11) + { + triangle_width = 3; + } + else + { + triangle_width = (int)Math.Round(rect.Width / 3.0f); + } + + arrow[0].X = rect.Right - triangle_width - 1; + arrow[0].Y = rect.Y + y_middle; + + if (arrow[0].X - 1 == rect.X) + arrow[0].X += 1; + + arrow[1].X = arrow[0].X - triangle_width + 1; + arrow[1].Y = arrow[0].Y - triangle_width + 1; + arrow[2].X = arrow[1].X; + arrow[2].Y = arrow[0].Y + triangle_width - 1; + + dc.DrawPolygon(pen, arrow); + + if ((state & ButtonState.Inactive) != 0) + { + dc.DrawLine(SystemPens.ControlLightLight, arrow[0].X + 1, arrow[0].Y + 1, arrow[2].X + 1, arrow[2].Y + 1); + dc.DrawLine(SystemPens.ControlLightLight, arrow[0].X, arrow[0].Y + 1, arrow[2].X + 1, arrow[2].Y); + } + + if (fill_rect) + { + for (int i = 0; i < arrow[0].X - arrow[1].X; i++) + { + dc.DrawLine(pen, arrow[2].X + i, arrow[1].Y, arrow[2].X + i, arrow[2].Y); + arrow[1].Y += 1; + arrow[2].Y -= 1; + } + } + break; + } + } + + public override void CPDrawSelectionFrame(Graphics graphics, bool active, Rectangle outsideRect, Rectangle insideRect, + Color backColor) + { + + } + + + public override void CPDrawSizeGrip(Graphics dc, Color backColor, Rectangle bounds) + { + Pen pen_dark = ResPool.GetPen(WidgetPaint.Dark(backColor)); + Pen pen_light_light = ResPool.GetPen(WidgetPaint.LightLight(backColor)); + + for (int i = 2; i < bounds.Width - 2; i += 4) + { + dc.DrawLine(pen_light_light, bounds.X + i, bounds.Bottom - 2, bounds.Right - 1, bounds.Y + i - 1); + dc.DrawLine(pen_dark, bounds.X + i + 1, bounds.Bottom - 2, bounds.Right - 1, bounds.Y + i); + dc.DrawLine(pen_dark, bounds.X + i + 2, bounds.Bottom - 2, bounds.Right - 1, bounds.Y + i + 1); + } + } + + private void DrawStringDisabled20(Graphics g, string s, Font font, Rectangle layoutRectangle, Color color, TextFormatFlags flags, bool useDrawString) + { + CPColor cpcolor = ResPool.GetCPColor(color); + + layoutRectangle.Offset(1, 1); + TextRenderer.DrawTextInternal(g, s, font, layoutRectangle, cpcolor.LightLight, flags, useDrawString); + + layoutRectangle.Offset(-1, -1); + TextRenderer.DrawTextInternal(g, s, font, layoutRectangle, cpcolor.Dark, flags, useDrawString); + } + + public override void CPDrawStringDisabled(Graphics dc, string s, Font font, Color color, RectangleF layoutRectangle, StringFormat format) + { + CPColor cpcolor = ResPool.GetCPColor(color); + + dc.DrawString(s, font, ResPool.GetSolidBrush(cpcolor.LightLight), + new RectangleF(layoutRectangle.X + 1, layoutRectangle.Y + 1, layoutRectangle.Width, layoutRectangle.Height), + format); + dc.DrawString(s, font, ResPool.GetSolidBrush(cpcolor.Dark), layoutRectangle, format); + } + + public override void CPDrawStringDisabled(IDeviceContext dc, string s, Font font, Color color, Rectangle layoutRectangle, TextFormatFlags format) + { + CPColor cpcolor = ResPool.GetCPColor(color); + + layoutRectangle.Offset(1, 1); + TextRenderer.DrawText(dc, s, font, layoutRectangle, cpcolor.LightLight, format); + + layoutRectangle.Offset(-1, -1); + TextRenderer.DrawText(dc, s, font, layoutRectangle, cpcolor.Dark, format); + } + + public override void CPDrawVisualStyleBorder(Graphics graphics, Rectangle bounds) + { + graphics.DrawRectangle(SystemPens.ControlDarkDark, bounds); + } + + private static void DrawBorderInternal(Graphics graphics, int startX, int startY, int endX, int endY, + int width, Color color, ButtonBorderStyle style, Border3DSide side) + { + DrawBorderInternal(graphics, (float)startX, (float)startY, (float)endX, (float)endY, + width, color, style, side); + } + + private static void DrawBorderInternal(Graphics graphics, float startX, float startY, float endX, float endY, + int width, Color color, ButtonBorderStyle style, Border3DSide side) + { + + Pen pen = null; + + switch (style) + { + case ButtonBorderStyle.Solid: + case ButtonBorderStyle.Inset: + case ButtonBorderStyle.Outset: + pen = ThemeEngine.Current.ResPool.GetDashPen(color, DashStyle.Solid); + break; + case ButtonBorderStyle.Dashed: + pen = ThemeEngine.Current.ResPool.GetDashPen(color, DashStyle.Dash); + break; + case ButtonBorderStyle.Dotted: + pen = ThemeEngine.Current.ResPool.GetDashPen(color, DashStyle.Dot); + break; + default: + case ButtonBorderStyle.None: + return; + } + + switch (style) + { + case ButtonBorderStyle.Outset: + { + Color colorGrade; + int hue, brightness, saturation; + int brightnessSteps; + int brightnessDownSteps; + + WidgetPaint.Color2HBS(color, out hue, out brightness, out saturation); + + brightnessDownSteps = brightness / width; + if (brightness > 127) + { + brightnessSteps = Math.Max(6, (160 - brightness) / width); + } + else + { + brightnessSteps = (127 - brightness) / width; + } + + for (int i = 0; i < width; i++) + { + switch (side) + { + case Border3DSide.Left: + { + colorGrade = WidgetPaint.HBS2Color(hue, Math.Min(255, brightness + brightnessSteps * (width - i)), saturation); + pen = ThemeEngine.Current.ResPool.GetPen(colorGrade); + graphics.DrawLine(pen, startX + i, startY + i, endX + i, endY - i); + break; + } + + case Border3DSide.Right: + { + colorGrade = WidgetPaint.HBS2Color(hue, Math.Max(0, brightness - brightnessDownSteps * (width - i)), saturation); + pen = ThemeEngine.Current.ResPool.GetPen(colorGrade); + graphics.DrawLine(pen, startX - i, startY + i, endX - i, endY - i); + break; + } + + case Border3DSide.Top: + { + colorGrade = WidgetPaint.HBS2Color(hue, Math.Min(255, brightness + brightnessSteps * (width - i)), saturation); + pen = ThemeEngine.Current.ResPool.GetPen(colorGrade); + graphics.DrawLine(pen, startX + i, startY + i, endX - i, endY + i); + break; + } + + case Border3DSide.Bottom: + { + colorGrade = WidgetPaint.HBS2Color(hue, Math.Max(0, brightness - brightnessDownSteps * (width - i)), saturation); + pen = ThemeEngine.Current.ResPool.GetPen(colorGrade); + graphics.DrawLine(pen, startX + i, startY - i, endX - i, endY - i); + break; + } + } + } + break; + } + + case ButtonBorderStyle.Inset: + { + Color colorGrade; + int hue, brightness, saturation; + int brightnessSteps; + int brightnessDownSteps; + + WidgetPaint.Color2HBS(color, out hue, out brightness, out saturation); + + brightnessDownSteps = brightness / width; + if (brightness > 127) + { + brightnessSteps = Math.Max(6, (160 - brightness) / width); + } + else + { + brightnessSteps = (127 - brightness) / width; + } + + for (int i = 0; i < width; i++) + { + switch (side) + { + case Border3DSide.Left: + { + colorGrade = WidgetPaint.HBS2Color(hue, Math.Max(0, brightness - brightnessDownSteps * (width - i)), saturation); + pen = ThemeEngine.Current.ResPool.GetPen(colorGrade); + graphics.DrawLine(pen, startX + i, startY + i, endX + i, endY - i); + break; + } + + case Border3DSide.Right: + { + colorGrade = WidgetPaint.HBS2Color(hue, Math.Min(255, brightness + brightnessSteps * (width - i)), saturation); + pen = ThemeEngine.Current.ResPool.GetPen(colorGrade); + graphics.DrawLine(pen, startX - i, startY + i, endX - i, endY - i); + break; + } + + case Border3DSide.Top: + { + colorGrade = WidgetPaint.HBS2Color(hue, Math.Max(0, brightness - brightnessDownSteps * (width - i)), saturation); + pen = ThemeEngine.Current.ResPool.GetPen(colorGrade); + graphics.DrawLine(pen, startX + i, startY + i, endX - i, endY + i); + break; + } + + case Border3DSide.Bottom: + { + colorGrade = WidgetPaint.HBS2Color(hue, Math.Min(255, brightness + brightnessSteps * (width - i)), saturation); + pen = ThemeEngine.Current.ResPool.GetPen(colorGrade); + graphics.DrawLine(pen, startX + i, startY - i, endX - i, endY - i); + break; + } + } + } + break; + } + + /* + I decided to have the for-loop duplicated for speed reasons; + that way we only have to switch once (as opposed to have the + for-loop around the switch) + */ + default: + { + switch (side) + { + case Border3DSide.Left: + { + for (int i = 0; i < width; i++) + { + graphics.DrawLine(pen, startX + i, startY + i, endX + i, endY - i); + } + break; + } + + case Border3DSide.Right: + { + for (int i = 0; i < width; i++) + { + graphics.DrawLine(pen, startX - i, startY + i, endX - i, endY - i); + } + break; + } + + case Border3DSide.Top: + { + for (int i = 0; i < width; i++) + { + graphics.DrawLine(pen, startX + i, startY + i, endX - i, endY + i); + } + break; + } + + case Border3DSide.Bottom: + { + for (int i = 0; i < width; i++) + { + graphics.DrawLine(pen, startX + i, startY - i, endX - i, endY - i); + } + break; + } + } + break; + } + } + } + + /* + This function actually draws the various caption elements. + This way we can scale them nicely, no matter what size, and they + still look like MS's scaled caption buttons. (as opposed to scaling a bitmap) + */ + + private void DrawCaptionHelper(Graphics graphics, Color color, Pen pen, int lineWidth, int shift, Rectangle captionRect, CaptionButton button) + { + switch (button) + { + case CaptionButton.Close: + { + if (lineWidth < 2) + { + graphics.DrawLine(pen, captionRect.Left + 2 * lineWidth + 1 + shift, captionRect.Top + 2 * lineWidth + shift, captionRect.Right - 2 * lineWidth + 1 + shift, captionRect.Bottom - 2 * lineWidth + shift); + graphics.DrawLine(pen, captionRect.Right - 2 * lineWidth + 1 + shift, captionRect.Top + 2 * lineWidth + shift, captionRect.Left + 2 * lineWidth + 1 + shift, captionRect.Bottom - 2 * lineWidth + shift); + } + + graphics.DrawLine(pen, captionRect.Left + 2 * lineWidth + shift, captionRect.Top + 2 * lineWidth + shift, captionRect.Right - 2 * lineWidth + shift, captionRect.Bottom - 2 * lineWidth + shift); + graphics.DrawLine(pen, captionRect.Right - 2 * lineWidth + shift, captionRect.Top + 2 * lineWidth + shift, captionRect.Left + 2 * lineWidth + shift, captionRect.Bottom - 2 * lineWidth + shift); + return; + } + + case CaptionButton.Help: + { + StringFormat sf = new StringFormat(); + Font font = new Font("Microsoft Sans Serif", captionRect.Height, FontStyle.Bold, GraphicsUnit.Pixel); + + sf.Alignment = StringAlignment.Center; + sf.LineAlignment = StringAlignment.Center; + + + graphics.DrawString("?", font, ResPool.GetSolidBrush(color), captionRect.X + captionRect.Width / 2 + shift, captionRect.Y + captionRect.Height / 2 + shift + lineWidth / 2, sf); + + sf.Dispose(); + font.Dispose(); + + return; + } + + case CaptionButton.Maximize: + { + /* Top 'caption bar' line */ + for (int i = 0; i < Math.Max(2, lineWidth); i++) + { + graphics.DrawLine(pen, captionRect.Left + lineWidth + shift, captionRect.Top + 2 * lineWidth + shift + i, captionRect.Right - lineWidth - lineWidth / 2 + shift, captionRect.Top + 2 * lineWidth + shift + i); + } + + /* Left side line */ + for (int i = 0; i < Math.Max(1, lineWidth / 2); i++) + { + graphics.DrawLine(pen, captionRect.Left + lineWidth + shift + i, captionRect.Top + 2 * lineWidth + shift, captionRect.Left + lineWidth + shift + i, captionRect.Bottom - lineWidth + shift); + } + + /* Right side line */ + for (int i = 0; i < Math.Max(1, lineWidth / 2); i++) + { + graphics.DrawLine(pen, captionRect.Right - lineWidth - lineWidth / 2 + shift + i, captionRect.Top + 2 * lineWidth + shift, captionRect.Right - lineWidth - lineWidth / 2 + shift + i, captionRect.Bottom - lineWidth + shift); + } + + /* Bottom line */ + for (int i = 0; i < Math.Max(1, lineWidth / 2); i++) + { + graphics.DrawLine(pen, captionRect.Left + lineWidth + shift, captionRect.Bottom - lineWidth + shift - i, captionRect.Right - lineWidth - lineWidth / 2 + shift, captionRect.Bottom - lineWidth + shift - i); + } + return; + } + + case CaptionButton.Minimize: + { + /* Bottom line */ + for (int i = 0; i < Math.Max(2, lineWidth); i++) + { + graphics.DrawLine(pen, captionRect.Left + lineWidth + shift, captionRect.Bottom - lineWidth + shift - i, captionRect.Right - 3 * lineWidth + shift, captionRect.Bottom - lineWidth + shift - i); + } + return; + } + + case CaptionButton.Restore: + { + /** First 'window' **/ + /* Top 'caption bar' line */ + for (int i = 0; i < Math.Max(2, lineWidth); i++) + { + graphics.DrawLine(pen, captionRect.Left + 3 * lineWidth + shift, captionRect.Top + 2 * lineWidth + shift - i, captionRect.Right - lineWidth - lineWidth / 2 + shift, captionRect.Top + 2 * lineWidth + shift - i); + } + + /* Left side line */ + for (int i = 0; i < Math.Max(1, lineWidth / 2); i++) + { + graphics.DrawLine(pen, captionRect.Left + 3 * lineWidth + shift + i, captionRect.Top + 2 * lineWidth + shift, captionRect.Left + 3 * lineWidth + shift + i, captionRect.Top + 4 * lineWidth + shift); + } + + /* Right side line */ + for (int i = 0; i < Math.Max(1, lineWidth / 2); i++) + { + graphics.DrawLine(pen, captionRect.Right - lineWidth - lineWidth / 2 + shift - i, captionRect.Top + 2 * lineWidth + shift, captionRect.Right - lineWidth - lineWidth / 2 + shift - i, captionRect.Top + 5 * lineWidth - lineWidth / 2 + shift); + } + + /* Bottom line */ + for (int i = 0; i < Math.Max(1, lineWidth / 2); i++) + { + graphics.DrawLine(pen, captionRect.Right - 3 * lineWidth - lineWidth / 2 + shift, captionRect.Top + 5 * lineWidth - lineWidth / 2 + shift + 1 + i, captionRect.Right - lineWidth - lineWidth / 2 + shift, captionRect.Top + 5 * lineWidth - lineWidth / 2 + shift + 1 + i); + } + + /** Second 'window' **/ + /* Top 'caption bar' line */ + for (int i = 0; i < Math.Max(2, lineWidth); i++) + { + graphics.DrawLine(pen, captionRect.Left + lineWidth + shift, captionRect.Top + 4 * lineWidth + shift + 1 - i, captionRect.Right - 3 * lineWidth - lineWidth / 2 + shift, captionRect.Top + 4 * lineWidth + shift + 1 - i); + } + + /* Left side line */ + for (int i = 0; i < Math.Max(1, lineWidth / 2); i++) + { + graphics.DrawLine(pen, captionRect.Left + lineWidth + shift + i, captionRect.Top + 4 * lineWidth + shift + 1, captionRect.Left + lineWidth + shift + i, captionRect.Bottom - lineWidth + shift); + } + + /* Right side line */ + for (int i = 0; i < Math.Max(1, lineWidth / 2); i++) + { + graphics.DrawLine(pen, captionRect.Right - 3 * lineWidth - lineWidth / 2 + shift - i, captionRect.Top + 4 * lineWidth + shift + 1, captionRect.Right - 3 * lineWidth - lineWidth / 2 + shift - i, captionRect.Bottom - lineWidth + shift); + } + + /* Bottom line */ + for (int i = 0; i < Math.Max(1, lineWidth / 2); i++) + { + graphics.DrawLine(pen, captionRect.Left + lineWidth + shift, captionRect.Bottom - lineWidth + shift - i, captionRect.Right - 3 * lineWidth - lineWidth / 2 + shift, captionRect.Bottom - lineWidth + shift - i); + } + + return; + } + + } + } + + /* Generic scroll button */ + public void DrawScrollButtonPrimitive(Graphics dc, Rectangle area, ButtonState state) + { + if ((state & ButtonState.Pushed) == ButtonState.Pushed) + { + dc.FillRectangle(SystemBrushes.Control, area.X + 1, + area.Y + 1, area.Width - 2, area.Height - 2); + + dc.DrawRectangle(SystemPens.ControlDark, area.X, + area.Y, area.Width, area.Height); + + return; + } + + Brush sb_control = SystemBrushes.Control; + Brush sb_lightlight = SystemBrushes.ControlLightLight; + Brush sb_dark = SystemBrushes.ControlDark; + Brush sb_darkdark = SystemBrushes.ControlDarkDark; + + dc.FillRectangle(sb_control, area.X, area.Y, area.Width, 1); + dc.FillRectangle(sb_control, area.X, area.Y, 1, area.Height); + + dc.FillRectangle(sb_lightlight, area.X + 1, area.Y + 1, area.Width - 1, 1); + dc.FillRectangle(sb_lightlight, area.X + 1, area.Y + 2, 1, + area.Height - 4); + + dc.FillRectangle(sb_dark, area.X + 1, area.Y + area.Height - 2, + area.Width - 2, 1); + + dc.FillRectangle(sb_darkdark, area.X, area.Y + area.Height - 1, + area.Width, 1); + + dc.FillRectangle(sb_dark, area.X + area.Width - 2, + area.Y + 1, 1, area.Height - 3); + + dc.FillRectangle(sb_darkdark, area.X + area.Width - 1, + area.Y, 1, area.Height - 1); + + dc.FillRectangle(sb_control, area.X + 2, + area.Y + 2, area.Width - 4, area.Height - 4); + + } + + public override void CPDrawBorderStyle(Graphics dc, Rectangle area, BorderStyle border_style) + { + switch (border_style) + { + case BorderStyle.Fixed3D: + dc.DrawLine(ResPool.GetPen(ColorControlDark), area.X, area.Y, area.X + area.Width, area.Y); + dc.DrawLine(ResPool.GetPen(ColorControlDark), area.X, area.Y, area.X, area.Y + area.Height); + dc.DrawLine(ResPool.GetPen(ColorControlLight), area.X, area.Y + area.Height - 1, area.X + area.Width, + area.Y + area.Height - 1); + dc.DrawLine(ResPool.GetPen(ColorControlLight), area.X + area.Width - 1, area.Y, area.X + area.Width - 1, + area.Y + area.Height); + + dc.DrawLine(ResPool.GetPen(ColorActiveBorder), area.X + 1, area.Bottom - 2, area.Right - 2, area.Bottom - 2); + dc.DrawLine(ResPool.GetPen(ColorActiveBorder), area.Right - 2, area.Top + 1, area.Right - 2, area.Bottom - 2); + dc.DrawLine(ResPool.GetPen(ColorControlDarkDark), area.X + 1, area.Top + 1, area.X + 1, area.Bottom - 3); + dc.DrawLine(ResPool.GetPen(ColorControlDarkDark), area.X + 1, area.Top + 1, area.Right - 3, area.Top + 1); + break; + case BorderStyle.FixedSingle: + dc.DrawRectangle(ResPool.GetPen(ColorWindowFrame), area.X, area.Y, area.Width - 1, area.Height - 1); + break; + case BorderStyle.None: + default: + break; + } + + } + #endregion // WidgetPaint + + + } //class +} diff --git a/source/ShiftUI/Theming/ThemeVisualStyles.cs b/source/ShiftUI/Theming/ThemeVisualStyles.cs new file mode 100644 index 0000000..d0bd4ea --- /dev/null +++ b/source/ShiftUI/Theming/ThemeVisualStyles.cs @@ -0,0 +1,2162 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2008 George Giolfan +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// George Giolfan, georgegiolfan@yahoo.com +// Ernesto Carrea, equistango@gmail.com + +using System.Drawing; +using System.Drawing.Drawing2D; +using ShiftUI.VisualStyles; +using System; + +namespace ShiftUI +{ + /// + /// VisualStyles theme. + /// + /// + /// This theme uses only the managed VisualStyles API. + /// To select it, set MONO_THEME to VisualStyles and call . + /// + class ThemeVisualStyles : ThemeWin32Classic + { + static bool render_client_areas; + static bool render_non_client_areas; + + public ThemeVisualStyles () + { + Update (); + } + + public override void ResetDefaults () + { + base.ResetDefaults (); + Update (); + } + + static void Update () + { + bool visual_styles_is_enabled_by_user = VisualStyleInformation.IsEnabledByUser; + render_client_areas = + visual_styles_is_enabled_by_user && + (Application.VisualStyleState == VisualStyleState.ClientAndNonClientAreasEnabled || + Application.VisualStyleState == VisualStyleState.ClientAreaEnabled); + render_non_client_areas = + visual_styles_is_enabled_by_user && + (Application.VisualStyleState == VisualStyleState.ClientAndNonClientAreasEnabled/* || + Application.VisualStyleState == VisualStyleState.NonClientAreaEnabled*/); + } + + public static bool RenderClientAreas { + get { return render_client_areas; } + } + + #region Widgets + #region ButtonBase + public override void DrawButtonBase (Graphics dc, Rectangle clip_area, ButtonBase button) + { + if (button.FlatStyle == FlatStyle.System) { + ButtonRenderer.DrawButton ( + dc, + new Rectangle (Point.Empty, button.Size), + button.Text, + button.Font, + button.TextFormatFlags, + null, + Rectangle.Empty, + ShouldPaintFocusRectagle (button), + GetPushButtonState (button) + ); + return; + } + base.DrawButtonBase (dc, clip_area, button); + } + static PushButtonState GetPushButtonState (ButtonBase button) + { + if (!button.Enabled) + return PushButtonState.Disabled; + if (button.Pressed) + return PushButtonState.Pressed; + if (button.Entered) + return PushButtonState.Hot; + if (button.IsDefault || button.Focused || button.paint_as_acceptbutton) + return PushButtonState.Default; + return PushButtonState.Normal; + } + #endregion + + #region Button 2.0 + public override void DrawButtonBackground (Graphics g, Button button, Rectangle clipArea) + { + if (!RenderClientAreas || + !button.UseVisualStyleBackColor) { + base.DrawButtonBackground (g, button, clipArea); + return; + } + ButtonRenderer.GetPushButtonRenderer (GetPushButtonState (button)).DrawBackground (g, new Rectangle (Point.Empty, button.Size)); + } + #endregion + + #region CheckBox + protected override void CheckBox_DrawCheckBox (Graphics dc, CheckBox checkbox, ButtonState state, Rectangle checkbox_rectangle) + { + if (checkbox.Appearance == Appearance.Normal && checkbox.FlatStyle == FlatStyle.System) { + CheckBoxRenderer.DrawCheckBox ( + dc, + new Point (checkbox_rectangle.Left, checkbox_rectangle.Top), + GetCheckBoxState (checkbox) + ); + return; + } + base.CheckBox_DrawCheckBox(dc, checkbox, state, checkbox_rectangle); + } + static CheckBoxState GetCheckBoxState (CheckBox checkBox) + { + switch (checkBox.CheckState) { + case CheckState.Checked: + if (!checkBox.Enabled) + return CheckBoxState.CheckedDisabled; + else if (checkBox.Pressed) + return CheckBoxState.CheckedPressed; + else if (checkBox.Entered) + return CheckBoxState.CheckedHot; + return CheckBoxState.CheckedNormal; + case CheckState.Indeterminate: + if (!checkBox.Enabled) + return CheckBoxState.MixedDisabled; + else if (checkBox.Pressed) + return CheckBoxState.MixedPressed; + else if (checkBox.Entered) + return CheckBoxState.MixedHot; + return CheckBoxState.MixedNormal; + default: + if (!checkBox.Enabled) + return CheckBoxState.UncheckedDisabled; + else if (checkBox.Pressed) + return CheckBoxState.UncheckedPressed; + else if (checkBox.Entered) + return CheckBoxState.UncheckedHot; + return CheckBoxState.UncheckedNormal; + } + } + #endregion + #region ComboBox + static VisualStyleElement ComboBoxGetVisualStyleElement (ComboBox comboBox, ButtonState state) + { + if (state == ButtonState.Inactive) + return VisualStyleElement.ComboBox.DropDownButton.Disabled; + if (state == ButtonState.Pushed) + return VisualStyleElement.ComboBox.DropDownButton.Pressed; + if (comboBox.DropDownButtonEntered) + return VisualStyleElement.ComboBox.DropDownButton.Hot; + return VisualStyleElement.ComboBox.DropDownButton.Normal; + } + public override void ComboBoxDrawNormalDropDownButton (ComboBox comboBox, Graphics g, Rectangle clippingArea, Rectangle area, ButtonState state) + { + if (!RenderClientAreas) { + base.ComboBoxDrawNormalDropDownButton (comboBox, g, clippingArea, area, state); + return; + } + VisualStyleElement element = ComboBoxGetVisualStyleElement (comboBox, state); + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.ComboBoxDrawNormalDropDownButton (comboBox, g, clippingArea, area, state); + return; + } + new VisualStyleRenderer (element).DrawBackground (g, area, clippingArea); + } + public override bool ComboBoxNormalDropDownButtonHasTransparentBackground (ComboBox comboBox, ButtonState state) + { + if (!RenderClientAreas) + return base.ComboBoxNormalDropDownButtonHasTransparentBackground (comboBox, state); + VisualStyleElement element = ComboBoxGetVisualStyleElement (comboBox, state); + if (!VisualStyleRenderer.IsElementDefined (element)) + return base.ComboBoxNormalDropDownButtonHasTransparentBackground (comboBox, state); + return new VisualStyleRenderer (element).IsBackgroundPartiallyTransparent (); + } + public override bool ComboBoxDropDownButtonHasHotElementStyle (ComboBox comboBox) + { + if (!RenderClientAreas) + return base.ComboBoxDropDownButtonHasHotElementStyle (comboBox); + switch (comboBox.FlatStyle) { + case FlatStyle.Flat: + case FlatStyle.Popup: + return base.ComboBoxDropDownButtonHasHotElementStyle (comboBox); + } + return true; + } + static bool ComboBoxShouldPaintBackground (ComboBox comboBox) + { + if (comboBox.DropDownStyle == ComboBoxStyle.Simple) + return false; + switch (comboBox.FlatStyle) { + case FlatStyle.Flat: + case FlatStyle.Popup: + return false; + } + return true; + } + public override void ComboBoxDrawBackground (ComboBox comboBox, Graphics g, Rectangle clippingArea, FlatStyle style) + { + if (!RenderClientAreas || !ComboBoxShouldPaintBackground (comboBox)) { + base.ComboBoxDrawBackground (comboBox, g, clippingArea, style); + return; + } + VisualStyleElement element; + if (!comboBox.Enabled) + element = VisualStyleElement.ComboBox.Border.Disabled; + else if (comboBox.Entered) + element = VisualStyleElement.ComboBox.Border.Hot; + else if (comboBox.Focused) + element = VisualStyleElement.ComboBox.Border.Focused; + else + element = VisualStyleElement.ComboBox.Border.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.ComboBoxDrawBackground (comboBox, g, clippingArea, style); + return; + } + new VisualStyleRenderer (element).DrawBackground (g, new Rectangle (Point.Empty, comboBox.Size), clippingArea); + } + public override bool CombBoxBackgroundHasHotElementStyle (ComboBox comboBox) + { + if (RenderClientAreas && + ComboBoxShouldPaintBackground (comboBox) && + comboBox.Enabled && + VisualStyleRenderer.IsElementDefined (VisualStyleElement.ComboBox.Border.Hot)) + return true; + return base.CombBoxBackgroundHasHotElementStyle (comboBox); + } + #endregion + #region WidgetPaint + #region DrawButton + public override void CPDrawButton (Graphics dc, Rectangle rectangle, ButtonState state) + { + if (!RenderClientAreas || + (state & ButtonState.Flat) == ButtonState.Flat || + (state & ButtonState.Checked) == ButtonState.Checked) { + base.CPDrawButton (dc, rectangle, state); + return; + } + VisualStyleElement element; + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + element = VisualStyleElement.Button.PushButton.Disabled; + else if ((state & ButtonState.Pushed) == ButtonState.Pushed) + element = VisualStyleElement.Button.PushButton.Pressed; + else + element = VisualStyleElement.Button.PushButton.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.CPDrawButton (dc, rectangle, state); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, rectangle); + } + #endregion + #region DrawCaptionButton + public override void CPDrawCaptionButton (Graphics graphics, Rectangle rectangle, CaptionButton button, ButtonState state) + { + if (!RenderClientAreas || + (state & ButtonState.Flat) == ButtonState.Flat || + (state & ButtonState.Checked) == ButtonState.Checked) { + base.CPDrawCaptionButton (graphics, rectangle, button, state); + return; + } + VisualStyleElement element = GetCaptionButtonVisualStyleElement (button, state); + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.CPDrawCaptionButton (graphics, rectangle, button, state); + return; + } + new VisualStyleRenderer (element).DrawBackground (graphics, rectangle); + } + static VisualStyleElement GetCaptionButtonVisualStyleElement (CaptionButton button, ButtonState state) + { + switch (button) { + case CaptionButton.Minimize: + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + return VisualStyleElement.Window.MinButton.Disabled; + else if ((state & ButtonState.Pushed) == ButtonState.Pushed) + return VisualStyleElement.Window.MinButton.Pressed; + else + return VisualStyleElement.Window.MinButton.Normal; + case CaptionButton.Maximize: + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + return VisualStyleElement.Window.MaxButton.Disabled; + else if ((state & ButtonState.Pushed) == ButtonState.Pushed) + return VisualStyleElement.Window.MaxButton.Pressed; + else + return VisualStyleElement.Window.MaxButton.Normal; + case CaptionButton.Close: + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + return VisualStyleElement.Window.CloseButton.Disabled; + else if ((state & ButtonState.Pushed) == ButtonState.Pushed) + return VisualStyleElement.Window.CloseButton.Pressed; + else + return VisualStyleElement.Window.CloseButton.Normal; + case CaptionButton.Restore: + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + return VisualStyleElement.Window.RestoreButton.Disabled; + else if ((state & ButtonState.Pushed) == ButtonState.Pushed) + return VisualStyleElement.Window.RestoreButton.Pressed; + else + return VisualStyleElement.Window.RestoreButton.Normal; + default: + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + return VisualStyleElement.Window.HelpButton.Disabled; + else if ((state & ButtonState.Pushed) == ButtonState.Pushed) + return VisualStyleElement.Window.HelpButton.Pressed; + else + return VisualStyleElement.Window.HelpButton.Normal; + } + } + #endregion + #region DrawCheckBox + public override void CPDrawCheckBox (Graphics dc, Rectangle rectangle, ButtonState state) + { + if (!RenderClientAreas || + (state & ButtonState.Flat) == ButtonState.Flat) { + base.CPDrawCheckBox (dc, rectangle, state); + return; + } + VisualStyleElement element; + if ((state & ButtonState.Checked) == ButtonState.Checked) + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + element = VisualStyleElement.Button.CheckBox.CheckedDisabled; + else if ((state & ButtonState.Pushed) == ButtonState.Pushed) + element = VisualStyleElement.Button.CheckBox.CheckedPressed; + else + element = VisualStyleElement.Button.CheckBox.CheckedNormal; + else + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + element = VisualStyleElement.Button.CheckBox.UncheckedDisabled; + else if ((state & ButtonState.Pushed) == ButtonState.Pushed) + element = VisualStyleElement.Button.CheckBox.UncheckedPressed; + else + element = VisualStyleElement.Button.CheckBox.UncheckedNormal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.CPDrawCheckBox (dc, rectangle, state); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, rectangle); + } + #endregion + #region DrawComboButton + public override void CPDrawComboButton (Graphics graphics, Rectangle rectangle, ButtonState state) + { + if (!RenderClientAreas || + (state & ButtonState.Flat) == ButtonState.Flat || + (state & ButtonState.Checked) == ButtonState.Checked) { + base.CPDrawComboButton (graphics, rectangle, state); + return; + } + VisualStyleElement element; + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + element = VisualStyleElement.ComboBox.DropDownButton.Disabled; + else if ((state & ButtonState.Pushed) == ButtonState.Pushed) + element = VisualStyleElement.ComboBox.DropDownButton.Pressed; + else + element = VisualStyleElement.ComboBox.DropDownButton.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.CPDrawComboButton (graphics, rectangle, state); + return; + } + new VisualStyleRenderer (element).DrawBackground (graphics, rectangle); + } + #endregion + #region DrawMixedCheckBox + public override void CPDrawMixedCheckBox (Graphics dc, Rectangle rectangle, ButtonState state) + { + if (!RenderClientAreas || + (state & ButtonState.Flat) == ButtonState.Flat) { + base.CPDrawMixedCheckBox (dc, rectangle, state); + return; + } + VisualStyleElement element; + if ((state & ButtonState.Checked) == ButtonState.Checked) + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + element = VisualStyleElement.Button.CheckBox.MixedDisabled; + else if ((state & ButtonState.Pushed) == ButtonState.Pushed) + element = VisualStyleElement.Button.CheckBox.MixedPressed; + else + element = VisualStyleElement.Button.CheckBox.MixedNormal; + else + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + element = VisualStyleElement.Button.CheckBox.UncheckedDisabled; + else if ((state & ButtonState.Pushed) == ButtonState.Pushed) + element = VisualStyleElement.Button.CheckBox.UncheckedPressed; + else + element = VisualStyleElement.Button.CheckBox.UncheckedNormal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.CPDrawMixedCheckBox (dc, rectangle, state); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, rectangle); + } + #endregion + #region DrawRadioButton + public override void CPDrawRadioButton (Graphics dc, Rectangle rectangle, ButtonState state) + { + if (!RenderClientAreas || + (state & ButtonState.Flat) == ButtonState.Flat) { + base.CPDrawRadioButton (dc, rectangle, state); + return; + } + VisualStyleElement element; + if ((state & ButtonState.Checked) == ButtonState.Checked) + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + element = VisualStyleElement.Button.RadioButton.CheckedDisabled; + else if ((state & ButtonState.Pushed) == ButtonState.Pushed) + element = VisualStyleElement.Button.RadioButton.CheckedPressed; + else + element = VisualStyleElement.Button.RadioButton.CheckedNormal; + else + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + element = VisualStyleElement.Button.RadioButton.UncheckedDisabled; + else if ((state & ButtonState.Pushed) == ButtonState.Pushed) + element = VisualStyleElement.Button.RadioButton.UncheckedPressed; + else + element = VisualStyleElement.Button.RadioButton.UncheckedNormal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.CPDrawRadioButton (dc, rectangle, state); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, rectangle); + } + #endregion + #region DrawScrollButton + public override void CPDrawScrollButton (Graphics dc, Rectangle area, ScrollButton type, ButtonState state) + { + if (!RenderClientAreas || + (state & ButtonState.Flat) == ButtonState.Flat || + (state & ButtonState.Checked) == ButtonState.Checked) { + base.CPDrawScrollButton (dc, area, type, state); + return; + } + VisualStyleElement element = GetScrollButtonVisualStyleElement (type, state); + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.CPDrawScrollButton (dc, area, type, state); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, area); + } + static VisualStyleElement GetScrollButtonVisualStyleElement (ScrollButton type, ButtonState state) + { + switch (type) { + case ScrollButton.Left: + if (IsDisabled (state)) + return VisualStyleElement.ScrollBar.ArrowButton.LeftDisabled; + else if (IsPressed (state)) + return VisualStyleElement.ScrollBar.ArrowButton.LeftPressed; + else + return VisualStyleElement.ScrollBar.ArrowButton.LeftNormal; + case ScrollButton.Right: + if (IsDisabled (state)) + return VisualStyleElement.ScrollBar.ArrowButton.RightDisabled; + else if (IsPressed (state)) + return VisualStyleElement.ScrollBar.ArrowButton.RightPressed; + else + return VisualStyleElement.ScrollBar.ArrowButton.RightNormal; + case ScrollButton.Up: + if (IsDisabled (state)) + return VisualStyleElement.ScrollBar.ArrowButton.UpDisabled; + else if (IsPressed (state)) + return VisualStyleElement.ScrollBar.ArrowButton.UpPressed; + else + return VisualStyleElement.ScrollBar.ArrowButton.UpNormal; + default: + if (IsDisabled (state)) + return VisualStyleElement.ScrollBar.ArrowButton.DownDisabled; + else if (IsPressed (state)) + return VisualStyleElement.ScrollBar.ArrowButton.DownPressed; + else + return VisualStyleElement.ScrollBar.ArrowButton.DownNormal; + } + } + static bool IsDisabled (ButtonState state) + { + return (state & ButtonState.Inactive) == ButtonState.Inactive; + } + static bool IsPressed (ButtonState state) + { + return (state & ButtonState.Pushed) == ButtonState.Pushed; + } + #endregion + #endregion + /* FIXME: I SAID NO. + #region DataGridView + #region DataGridViewHeaderCell + #region DataGridViewRowHeaderCell + public override bool DataGridViewRowHeaderCellDrawBackground (DataGridViewRowHeaderCell cell, Graphics g, Rectangle bounds) + { + if (!RenderClientAreas || + !cell.DataGridView.EnableHeadersVisualStyles) + return base.DataGridViewRowHeaderCellDrawBackground (cell, g, bounds); + VisualStyleElement element = DataGridViewRowHeaderCellGetVisualStyleElement (cell); + if (!VisualStyleRenderer.IsElementDefined (element)) + return base.DataGridViewRowHeaderCellDrawBackground (cell, g, bounds); + bounds.Width--; + Bitmap bitmap = new Bitmap (bounds.Height, bounds.Width); + Graphics bitmap_g = Graphics.FromImage (bitmap); + Rectangle bitmap_rectangle = new Rectangle (Point.Empty, bitmap.Size); + VisualStyleRenderer renderer = new VisualStyleRenderer (element); + if (!AreEqual (element, VisualStyleElement.Header.Item.Normal) && renderer.IsBackgroundPartiallyTransparent ()) + new VisualStyleRenderer (VisualStyleElement.Header.Item.Normal).DrawBackground (bitmap_g, bitmap_rectangle); + renderer.DrawBackground (bitmap_g, bitmap_rectangle); + bitmap_g.Dispose (); + g.Transform = new Matrix(0, 1, 1, 0, 0, 0); + g.DrawImage (bitmap, bounds.Y, bounds.X); + bitmap.Dispose (); + g.ResetTransform (); + return true; + } + public override bool DataGridViewRowHeaderCellDrawSelectionBackground (DataGridViewRowHeaderCell cell) + { + if (!RenderClientAreas || + !cell.DataGridView.EnableHeadersVisualStyles || !VisualStyleRenderer.IsElementDefined (DataGridViewRowHeaderCellGetVisualStyleElement (cell))) + return base.DataGridViewRowHeaderCellDrawSelectionBackground (cell); + return true; + } + public override bool DataGridViewRowHeaderCellDrawBorder (DataGridViewRowHeaderCell cell, Graphics g, Rectangle bounds) + { + if (!RenderClientAreas || + !cell.DataGridView.EnableHeadersVisualStyles || !VisualStyleRenderer.IsElementDefined (DataGridViewRowHeaderCellGetVisualStyleElement (cell))) + return base.DataGridViewRowHeaderCellDrawBorder (cell, g, bounds); + g.DrawLine (cell.GetBorderPen (), bounds.Right - 1, bounds.Top, bounds.Right - 1, bounds.Bottom - 1); + return true; + } + static VisualStyleElement DataGridViewRowHeaderCellGetVisualStyleElement (DataGridViewRowHeaderCell cell) + { + if (cell.DataGridView.PressedHeaderCell == cell) + return VisualStyleElement.Header.Item.Pressed; + if (cell.DataGridView.EnteredHeaderCell == cell) + return VisualStyleElement.Header.Item.Hot; + if (cell.OwningRow.SelectedInternal) + return VisualStyleElement.Header.Item.Pressed; + return VisualStyleElement.Header.Item.Normal; + } + #endregion + #region DataGridViewColumnHeaderCell + public override bool DataGridViewColumnHeaderCellDrawBackground (DataGridViewColumnHeaderCell cell, Graphics g, Rectangle bounds) + { + if (!RenderClientAreas || + !cell.DataGridView.EnableHeadersVisualStyles || cell is DataGridViewTopLeftHeaderCell) + return base.DataGridViewColumnHeaderCellDrawBackground (cell, g, bounds); + VisualStyleElement element = DataGridViewColumnHeaderCellGetVisualStyleElement (cell); + if (!VisualStyleRenderer.IsElementDefined (element)) + return base.DataGridViewColumnHeaderCellDrawBackground (cell, g, bounds); + bounds.Height--; + VisualStyleRenderer renderer = new VisualStyleRenderer (element); + if (!AreEqual (element, VisualStyleElement.Header.Item.Normal) && renderer.IsBackgroundPartiallyTransparent ()) + new VisualStyleRenderer (VisualStyleElement.Header.Item.Normal).DrawBackground (g, bounds); + renderer.DrawBackground (g, bounds); + return true; + } + public override bool DataGridViewColumnHeaderCellDrawBorder (DataGridViewColumnHeaderCell cell, Graphics g, Rectangle bounds) + { + if (!RenderClientAreas || + !cell.DataGridView.EnableHeadersVisualStyles || + cell is DataGridViewTopLeftHeaderCell || + !VisualStyleRenderer.IsElementDefined (VisualStyleElement.Header.Item.Normal)) + return base.DataGridViewColumnHeaderCellDrawBorder (cell, g, bounds); + g.DrawLine (cell.GetBorderPen (), bounds.Left, bounds.Bottom - 1, bounds.Right - 1, bounds.Bottom - 1); + return true; + } + static VisualStyleElement DataGridViewColumnHeaderCellGetVisualStyleElement (DataGridViewColumnHeaderCell cell) + { + if (cell.DataGridView.PressedHeaderCell == cell) + return VisualStyleElement.Header.Item.Pressed; + if (cell.DataGridView.EnteredHeaderCell == cell) + return VisualStyleElement.Header.Item.Hot; + return VisualStyleElement.Header.Item.Normal; + } + #endregion + public override bool DataGridViewHeaderCellHasPressedStyle (DataGridView dataGridView) + { + if (!RenderClientAreas || + !dataGridView.EnableHeadersVisualStyles || + !VisualStyleRenderer.IsElementDefined (VisualStyleElement.Header.Item.Pressed)) + return base.DataGridViewHeaderCellHasPressedStyle (dataGridView); + return true; + } + public override bool DataGridViewHeaderCellHasHotStyle (DataGridView dataGridView) + { + if (!RenderClientAreas || + !dataGridView.EnableHeadersVisualStyles || + !VisualStyleRenderer.IsElementDefined (VisualStyleElement.Header.Item.Hot)) + return base.DataGridViewHeaderCellHasHotStyle (dataGridView); + return true; + } + #endregion + #endregion*/ + + #region DateTimePicker + #region Border + protected override void DateTimePickerDrawBorder (DateTimePicker dateTimePicker, Graphics g, Rectangle clippingArea) + { + if (!RenderClientAreas) { + base.DateTimePickerDrawBorder (dateTimePicker, g, clippingArea); + return; + } + VisualStyleElement element; + if (!dateTimePicker.Enabled) + element = VisualStyleElement.DatePicker.DateBorder.Disabled; + else if (dateTimePicker.Entered) + element = VisualStyleElement.DatePicker.DateBorder.Hot; + else if (dateTimePicker.Focused) + element = VisualStyleElement.DatePicker.DateBorder.Focused; + else + element = VisualStyleElement.DatePicker.DateBorder.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.DateTimePickerDrawBorder (dateTimePicker, g, clippingArea); + return; + } + new VisualStyleRenderer (element).DrawBackground (g, new Rectangle (Point.Empty, dateTimePicker.Size), clippingArea); + } + public override bool DateTimePickerBorderHasHotElementStyle { + get { + if (RenderClientAreas && + VisualStyleRenderer.IsElementDefined (VisualStyleElement.DatePicker.DateBorder.Hot)) + return true; + return base.DateTimePickerBorderHasHotElementStyle; + } + } + #endregion + #region Drop down button + protected override void DateTimePickerDrawDropDownButton (DateTimePicker dateTimePicker, Graphics g, Rectangle clippingArea) + { + if (!RenderClientAreas) { + base.DateTimePickerDrawDropDownButton (dateTimePicker, g, clippingArea); + return; + } + VisualStyleElement element; + if (!dateTimePicker.Enabled) + element = VisualStyleElement.DatePicker.ShowCalendarButtonRight.Disabled; + else if (dateTimePicker.is_drop_down_visible) + element = VisualStyleElement.DatePicker.ShowCalendarButtonRight.Pressed; + else if (dateTimePicker.DropDownButtonEntered) + element = VisualStyleElement.DatePicker.ShowCalendarButtonRight.Hot; + else + element = VisualStyleElement.DatePicker.ShowCalendarButtonRight.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.DateTimePickerDrawDropDownButton (dateTimePicker, g, clippingArea); + return; + } + new VisualStyleRenderer (element).DrawBackground (g, dateTimePicker.drop_down_arrow_rect, clippingArea); + } + //TODO: Until somebody figures out how to obtain the proper width this will need to be updated when new Windows versions/themes are released. + const int DateTimePickerDropDownWidthOnWindowsVista = 34; + const int DateTimePickerDropDownHeightOnWindowsVista = 20; + public override Rectangle DateTimePickerGetDropDownButtonArea (DateTimePicker dateTimePicker) + { + if (!RenderClientAreas) + return base.DateTimePickerGetDropDownButtonArea (dateTimePicker); + VisualStyleElement element = VisualStyleElement.DatePicker.ShowCalendarButtonRight.Pressed; + if (!VisualStyleRenderer.IsElementDefined (element)) + return base.DateTimePickerGetDropDownButtonArea (dateTimePicker); + Size size = new Size (DateTimePickerDropDownWidthOnWindowsVista, DateTimePickerDropDownHeightOnWindowsVista); + return new Rectangle (dateTimePicker.Width - size.Width, 0, size.Width, size.Height); + } + public override Rectangle DateTimePickerGetDateArea (DateTimePicker dateTimePicker) + { + if (!RenderClientAreas || + dateTimePicker.ShowUpDown) + return base.DateTimePickerGetDateArea (dateTimePicker); + VisualStyleElement element = VisualStyleElement.DatePicker.DateBorder.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) + return base.DateTimePickerGetDateArea (dateTimePicker); + Graphics g = dateTimePicker.CreateGraphics (); + Rectangle result = new VisualStyleRenderer (element).GetBackgroundContentRectangle (g, dateTimePicker.ClientRectangle); + g.Dispose (); + result.Width -= DateTimePickerDropDownWidthOnWindowsVista; + return result; + } + public override bool DateTimePickerDropDownButtonHasHotElementStyle { + get { + if (RenderClientAreas && + VisualStyleRenderer.IsElementDefined (VisualStyleElement.DatePicker.ShowCalendarButtonRight.Hot)) + return true; + return base.DateTimePickerDropDownButtonHasHotElementStyle; + } + } + #endregion + #endregion + #region ListView + protected override void ListViewDrawColumnHeaderBackground (ListView listView, ColumnHeader columnHeader, Graphics g, Rectangle area, Rectangle clippingArea) + { + if (!RenderClientAreas) { + base.ListViewDrawColumnHeaderBackground (listView, columnHeader, g, area, clippingArea); + return; + } + VisualStyleElement element; + if (listView.HeaderStyle == ColumnHeaderStyle.Clickable) + if (columnHeader.Pressed) + element = VisualStyleElement.Header.Item.Pressed; + else if (columnHeader == listView.EnteredColumnHeader) + element = VisualStyleElement.Header.Item.Hot; + else + element = VisualStyleElement.Header.Item.Normal; + else + element = VisualStyleElement.Header.Item.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.ListViewDrawColumnHeaderBackground (listView, columnHeader, g, area, clippingArea); + return; + } + new VisualStyleRenderer (element).DrawBackground (g, area, clippingArea); + } + protected override void ListViewDrawUnusedHeaderBackground (ListView listView, Graphics g, Rectangle area, Rectangle clippingArea) + { + if (!RenderClientAreas) { + base.ListViewDrawUnusedHeaderBackground (listView, g, area, clippingArea); + return; + } + VisualStyleElement element = VisualStyleElement.Header.Item.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.ListViewDrawUnusedHeaderBackground (listView, g, area, clippingArea); + return; + } + new VisualStyleRenderer (element).DrawBackground (g, area, clippingArea); + } + public override bool ListViewHasHotHeaderStyle { + get { + if (!RenderClientAreas || + !VisualStyleRenderer.IsElementDefined (VisualStyleElement.Header.Item.Hot)) + return base.ListViewHasHotHeaderStyle; + return true; + } + } + public override int ListViewGetHeaderHeight (ListView listView, Font font) + { + if (!RenderClientAreas) + return base.ListViewGetHeaderHeight (listView, font); + VisualStyleElement element = VisualStyleElement.Header.Item.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) + return base.ListViewGetHeaderHeight (listView, font); + Widget control = null; + Graphics g; + if (listView == null) { + control = new Widget (); + g = control.CreateGraphics (); + } else + g = listView.CreateGraphics (); + int result = new VisualStyleRenderer (element).GetPartSize (g, ThemeSizeType.True).Height; + g.Dispose (); + if (listView == null) + control.Dispose (); + return result; + } + #endregion + #region GroupBox + public override void DrawGroupBox (Graphics dc, Rectangle area, GroupBox box) + { + GroupBoxRenderer.DrawGroupBox ( + dc, + new Rectangle (Point.Empty, box.Size), + box.Text, + box.Font, + box.ForeColor == GroupBox.DefaultForeColor ? Color.Empty : box.ForeColor, + box.Enabled ? GroupBoxState.Normal : GroupBoxState.Disabled); + } + #endregion + #region Managed window + Rectangle ManagedWindowGetTitleBarRectangle (InternalWindowManager wm) + { + return new Rectangle (0, 0, wm.Form.Width, ManagedWindowTitleBarHeight (wm) + ManagedWindowBorderWidth (wm) * (wm.IsMinimized ? 2 : 1)); + } + Region ManagedWindowGetWindowRegion (Form form) + { + if (form.WindowManager is MdiWindowManager && form.WindowManager.IsMaximized) + return null; + VisualStyleElement title_bar_element = ManagedWindowGetTitleBarVisualStyleElement (form.WindowManager); + if (!VisualStyleRenderer.IsElementDefined (title_bar_element)) + return null; + VisualStyleRenderer renderer = new VisualStyleRenderer (title_bar_element); + if (!renderer.IsBackgroundPartiallyTransparent ()) + return null; + IDeviceContext dc = GetMeasurementDeviceContext (); + Rectangle title_bar_rectangle = ManagedWindowGetTitleBarRectangle (form.WindowManager); + Region region = renderer.GetBackgroundRegion (dc, title_bar_rectangle); + ReleaseMeasurementDeviceContext (dc); + region.Union (new Rectangle (0, title_bar_rectangle.Bottom, form.Width, form.Height)); + return region; + } + public override void ManagedWindowOnSizeInitializedOrChanged (Form form) + { + base.ManagedWindowOnSizeInitializedOrChanged (form); + if (!render_non_client_areas) + return; + form.Region = ManagedWindowGetWindowRegion (form); + } + protected override Rectangle ManagedWindowDrawTitleBarAndBorders (Graphics dc, Rectangle clip, InternalWindowManager wm) + { + if (!render_non_client_areas) + return base.ManagedWindowDrawTitleBarAndBorders (dc, clip, wm); + VisualStyleElement title_bar_element = ManagedWindowGetTitleBarVisualStyleElement (wm); + VisualStyleElement left_border_element; + VisualStyleElement right_border_element; + VisualStyleElement bottom_border_element; + ManagedWindowGetBorderVisualStyleElements (wm, out left_border_element, out right_border_element, out bottom_border_element); + if (!VisualStyleRenderer.IsElementDefined (title_bar_element) || + (!wm.IsMinimized && ( + !VisualStyleRenderer.IsElementDefined (left_border_element) || + !VisualStyleRenderer.IsElementDefined (right_border_element) || + !VisualStyleRenderer.IsElementDefined (bottom_border_element)))) + return base.ManagedWindowDrawTitleBarAndBorders (dc, clip, wm); + VisualStyleRenderer renderer = new VisualStyleRenderer (title_bar_element); + Rectangle title_bar_rectangle = ManagedWindowGetTitleBarRectangle (wm); + renderer.DrawBackground (dc, title_bar_rectangle, clip); + if (!wm.IsMinimized) { + int border_width = ManagedWindowBorderWidth (wm); + renderer.SetParameters (left_border_element); + renderer.DrawBackground (dc, new Rectangle ( + 0, + title_bar_rectangle.Bottom, + border_width, + wm.Form.Height - title_bar_rectangle.Bottom + ), clip); + renderer.SetParameters (right_border_element); + renderer.DrawBackground (dc, new Rectangle ( + wm.Form.Width - border_width, + title_bar_rectangle.Bottom, + border_width, + wm.Form.Height - title_bar_rectangle.Bottom + ), clip); + renderer.SetParameters (bottom_border_element); + renderer.DrawBackground (dc, new Rectangle ( + 0, + wm.Form.Height - border_width, + wm.Form.Width, + border_width + ), clip); + } + return title_bar_rectangle; + } + static FormWindowState ManagedWindowGetWindowState (InternalWindowManager wm) + { + return wm.GetWindowState (); + } + static bool ManagedWindowIsDisabled (InternalWindowManager wm) + { + return !wm.Form.Enabled; + } + static bool ManagedWindowIsActive (InternalWindowManager wm) + { + return wm.IsActive; + } + static VisualStyleElement ManagedWindowGetTitleBarVisualStyleElement (InternalWindowManager wm) + { + if (wm.IsToolWindow) + #region Small window + switch (ManagedWindowGetWindowState (wm)) { + case FormWindowState.Minimized: + if (ManagedWindowIsDisabled (wm)) + return VisualStyleElement.Window.SmallMinCaption.Disabled; + else if (ManagedWindowIsActive (wm)) + return VisualStyleElement.Window.SmallMinCaption.Active; + return VisualStyleElement.Window.SmallMinCaption.Inactive; + case FormWindowState.Maximized: + if (ManagedWindowIsDisabled (wm)) + return VisualStyleElement.Window.SmallMaxCaption.Disabled; + else if (ManagedWindowIsActive (wm)) + return VisualStyleElement.Window.SmallMaxCaption.Active; + return VisualStyleElement.Window.SmallMaxCaption.Inactive; + default: + if (ManagedWindowIsDisabled (wm)) + return VisualStyleElement.Window.SmallCaption.Disabled; + else if (ManagedWindowIsActive (wm)) + return VisualStyleElement.Window.SmallCaption.Active; + return VisualStyleElement.Window.SmallCaption.Inactive; + } + #endregion + else + #region Normal window + switch (ManagedWindowGetWindowState (wm)) { + case FormWindowState.Minimized: + if (ManagedWindowIsDisabled (wm)) + return VisualStyleElement.Window.MinCaption.Disabled; + else if (ManagedWindowIsActive (wm)) + return VisualStyleElement.Window.MinCaption.Active; + return VisualStyleElement.Window.MinCaption.Inactive; + case FormWindowState.Maximized: + if (ManagedWindowIsDisabled (wm)) + return VisualStyleElement.Window.MaxCaption.Disabled; + else if (ManagedWindowIsActive (wm)) + return VisualStyleElement.Window.MaxCaption.Active; + return VisualStyleElement.Window.MaxCaption.Inactive; + default: + if (ManagedWindowIsDisabled (wm)) + return VisualStyleElement.Window.Caption.Disabled; + else if (ManagedWindowIsActive (wm)) + return VisualStyleElement.Window.Caption.Active; + return VisualStyleElement.Window.Caption.Inactive; + } + #endregion + } + static void ManagedWindowGetBorderVisualStyleElements (InternalWindowManager wm, out VisualStyleElement left, out VisualStyleElement right, out VisualStyleElement bottom) + { + bool active = !ManagedWindowIsDisabled (wm) && ManagedWindowIsActive (wm); + if (wm.IsToolWindow) { + if (active) { + left = VisualStyleElement.Window.SmallFrameLeft.Active; + right = VisualStyleElement.Window.SmallFrameRight.Active; + bottom = VisualStyleElement.Window.SmallFrameBottom.Active; + } else { + left = VisualStyleElement.Window.SmallFrameLeft.Inactive; + right = VisualStyleElement.Window.SmallFrameRight.Inactive; + bottom = VisualStyleElement.Window.SmallFrameBottom.Inactive; + } + } else { + if (active) { + left = VisualStyleElement.Window.FrameLeft.Active; + right = VisualStyleElement.Window.FrameRight.Active; + bottom = VisualStyleElement.Window.FrameBottom.Active; + } else { + left = VisualStyleElement.Window.FrameLeft.Inactive; + right = VisualStyleElement.Window.FrameRight.Inactive; + bottom = VisualStyleElement.Window.FrameBottom.Inactive; + } + } + } + public override bool ManagedWindowTitleButtonHasHotElementStyle (TitleButton button, Form form) + { + if (render_non_client_areas && (button.State & ButtonState.Inactive) != ButtonState.Inactive) { + VisualStyleElement element; + if (ManagedWindowIsMaximizedMdiChild (form)) + switch (button.Caption) { + case CaptionButton.Close: + element = VisualStyleElement.Window.MdiCloseButton.Hot; + break; + case CaptionButton.Help: + element = VisualStyleElement.Window.MdiHelpButton.Hot; + break; + case CaptionButton.Minimize: + element = VisualStyleElement.Window.MdiMinButton.Hot; + break; + default: + element = VisualStyleElement.Window.MdiRestoreButton.Hot; + break; + } + else if (form.WindowManager.IsToolWindow) + element = VisualStyleElement.Window.SmallCloseButton.Hot; + else + switch (button.Caption) { + case CaptionButton.Close: + element = VisualStyleElement.Window.CloseButton.Hot; + break; + case CaptionButton.Help: + element = VisualStyleElement.Window.HelpButton.Hot; + break; + case CaptionButton.Maximize: + element = VisualStyleElement.Window.MaxButton.Hot; + break; + case CaptionButton.Minimize: + element = VisualStyleElement.Window.MinButton.Hot; + break; + default: + element = VisualStyleElement.Window.RestoreButton.Hot; + break; + } + if (VisualStyleRenderer.IsElementDefined (element)) + return true; + } + return base.ManagedWindowTitleButtonHasHotElementStyle (button, form); + } + static bool ManagedWindowIsMaximizedMdiChild (Form form) + { + return form.WindowManager is MdiWindowManager && + ManagedWindowGetWindowState (form.WindowManager) == FormWindowState.Maximized; + } + static bool ManagedWindowTitleButtonIsDisabled (TitleButton button, InternalWindowManager wm) + { + return (button.State & ButtonState.Inactive) == ButtonState.Inactive; + } + static bool ManagedWindowTitleButtonIsPressed (TitleButton button) + { + return (button.State & ButtonState.Pushed) == ButtonState.Pushed; + } + static VisualStyleElement ManagedWindowGetTitleButtonVisualStyleElement (TitleButton button, Form form) + { + if (form.WindowManager.IsToolWindow) { + if (ManagedWindowTitleButtonIsDisabled (button, form.WindowManager)) + return VisualStyleElement.Window.SmallCloseButton.Disabled; + if (ManagedWindowTitleButtonIsPressed (button)) + return VisualStyleElement.Window.SmallCloseButton.Pressed; + if (button.Entered) + return VisualStyleElement.Window.SmallCloseButton.Hot; + return VisualStyleElement.Window.SmallCloseButton.Normal; + } + switch (button.Caption) { + case CaptionButton.Close: + if (ManagedWindowTitleButtonIsDisabled (button, form.WindowManager)) + return VisualStyleElement.Window.CloseButton.Disabled; + if (ManagedWindowTitleButtonIsPressed (button)) + return VisualStyleElement.Window.CloseButton.Pressed; + if (button.Entered) + return VisualStyleElement.Window.CloseButton.Hot; + return VisualStyleElement.Window.CloseButton.Normal; + case CaptionButton.Help: + if (ManagedWindowTitleButtonIsDisabled (button, form.WindowManager)) + return VisualStyleElement.Window.HelpButton.Disabled; + if (ManagedWindowTitleButtonIsPressed (button)) + return VisualStyleElement.Window.HelpButton.Pressed; + if (button.Entered) + return VisualStyleElement.Window.HelpButton.Hot; + return VisualStyleElement.Window.HelpButton.Normal; + case CaptionButton.Maximize: + if (ManagedWindowTitleButtonIsDisabled (button, form.WindowManager)) + return VisualStyleElement.Window.MaxButton.Disabled; + if (ManagedWindowTitleButtonIsPressed (button)) + return VisualStyleElement.Window.MaxButton.Pressed; + if (button.Entered) + return VisualStyleElement.Window.MaxButton.Hot; + return VisualStyleElement.Window.MaxButton.Normal; + case CaptionButton.Minimize: + if (ManagedWindowTitleButtonIsDisabled (button, form.WindowManager)) + return VisualStyleElement.Window.MinButton.Disabled; + if (ManagedWindowTitleButtonIsPressed (button)) + return VisualStyleElement.Window.MinButton.Pressed; + if (button.Entered) + return VisualStyleElement.Window.MinButton.Hot; + return VisualStyleElement.Window.MinButton.Normal; + default: + if (ManagedWindowTitleButtonIsDisabled (button, form.WindowManager)) + return VisualStyleElement.Window.RestoreButton.Disabled; + if (ManagedWindowTitleButtonIsPressed (button)) + return VisualStyleElement.Window.RestoreButton.Pressed; + if (button.Entered) + return VisualStyleElement.Window.RestoreButton.Hot; + return VisualStyleElement.Window.RestoreButton.Normal; + } + } + protected override void ManagedWindowDrawTitleButton (Graphics dc, TitleButton button, Rectangle clip, Form form) + { + if (!render_non_client_areas) { + base.ManagedWindowDrawTitleButton (dc, button, clip, form); + return; + } + VisualStyleElement element = ManagedWindowGetTitleButtonVisualStyleElement (button, form); + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.ManagedWindowDrawTitleButton (dc, button, clip, form); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, button.Rectangle, clip); + } + public override Size ManagedWindowButtonSize (InternalWindowManager wm) + { + if (!render_non_client_areas) + return base.ManagedWindowButtonSize (wm); + VisualStyleElement element = wm.IsToolWindow && !wm.IsMinimized ? + VisualStyleElement.Window.SmallCloseButton.Normal : + VisualStyleElement.Window.CloseButton.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) + return base.ManagedWindowButtonSize (wm); + IDeviceContext dc = GetMeasurementDeviceContext (); + Size result = new VisualStyleRenderer (element).GetPartSize (dc, ThemeSizeType.True); + ReleaseMeasurementDeviceContext (dc); + return result; + } + public override void ManagedWindowDrawMenuButton (Graphics dc, TitleButton button, Rectangle clip, InternalWindowManager wm) + { + if (!render_non_client_areas) { + base.ManagedWindowDrawMenuButton (dc, button, clip, wm); + return; + } + VisualStyleElement element = ManagedWindowGetMenuButtonVisualStyleElement (button, wm); + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.ManagedWindowDrawMenuButton (dc, button, clip, wm); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, button.Rectangle, clip); + } + static VisualStyleElement ManagedWindowGetMenuButtonVisualStyleElement (TitleButton button, InternalWindowManager wm) + { + switch (button.Caption) { + case CaptionButton.Close: + if (ManagedWindowTitleButtonIsDisabled (button, wm)) + return VisualStyleElement.Window.MdiCloseButton.Disabled; + if (ManagedWindowTitleButtonIsPressed (button)) + return VisualStyleElement.Window.MdiCloseButton.Pressed; + if (button.Entered) + return VisualStyleElement.Window.MdiCloseButton.Hot; + return VisualStyleElement.Window.MdiCloseButton.Normal; + case CaptionButton.Help: + if (ManagedWindowTitleButtonIsDisabled (button, wm)) + return VisualStyleElement.Window.MdiHelpButton.Disabled; + if (ManagedWindowTitleButtonIsPressed (button)) + return VisualStyleElement.Window.MdiHelpButton.Pressed; + if (button.Entered) + return VisualStyleElement.Window.MdiHelpButton.Hot; + return VisualStyleElement.Window.MdiHelpButton.Normal; + case CaptionButton.Minimize: + if (ManagedWindowTitleButtonIsDisabled (button, wm)) + return VisualStyleElement.Window.MdiMinButton.Disabled; + if (ManagedWindowTitleButtonIsPressed (button)) + return VisualStyleElement.Window.MdiMinButton.Pressed; + if (button.Entered) + return VisualStyleElement.Window.MdiMinButton.Hot; + return VisualStyleElement.Window.MdiMinButton.Normal; + default: + if (ManagedWindowTitleButtonIsDisabled (button, wm)) + return VisualStyleElement.Window.MdiRestoreButton.Disabled; + if (ManagedWindowTitleButtonIsPressed (button)) + return VisualStyleElement.Window.MdiRestoreButton.Pressed; + if (button.Entered) + return VisualStyleElement.Window.MdiRestoreButton.Hot; + return VisualStyleElement.Window.MdiRestoreButton.Normal; + } + } + #endregion + #region ProgressBar + public override void DrawProgressBar (Graphics dc, Rectangle clip_rect, ProgressBar ctrl) + { + if (!RenderClientAreas || + !VisualStyleRenderer.IsElementDefined (VisualStyleElement.ProgressBar.Bar.Normal) || + !VisualStyleRenderer.IsElementDefined (VisualStyleElement.ProgressBar.Chunk.Normal)) { + base.DrawProgressBar (dc, clip_rect, ctrl); + return; + } + VisualStyleRenderer renderer = new VisualStyleRenderer (VisualStyleElement.ProgressBar.Bar.Normal); + renderer.DrawBackground (dc, ctrl.ClientRectangle, clip_rect); + Rectangle client_area = renderer.GetBackgroundContentRectangle (dc, new Rectangle (Point.Empty, ctrl.Size)); + renderer = new VisualStyleRenderer (VisualStyleElement.ProgressBar.Chunk.Normal); + /* Draw Blocks */ + int draw_mode = 0; + int max_blocks = int.MaxValue; + int start_pixel = client_area.X; + draw_mode = (int)ctrl.Style; + switch (draw_mode) { + case 1: // Continuous + client_area.Width = (int)(client_area.Width * ((double)(ctrl.Value - ctrl.Minimum) / (double)(Math.Max (ctrl.Maximum - ctrl.Minimum, 1)))); + renderer.DrawBackground (dc, client_area, clip_rect); + break; + case 2: // Marquee + int ms_diff = (int)(DateTime.Now - ctrl.start).TotalMilliseconds; + double percent_done = (double) ms_diff / ProgressBarMarqueeSpeedScaling + % (double)ctrl.MarqueeAnimationSpeed / (double)ctrl.MarqueeAnimationSpeed; + max_blocks = 5; + start_pixel = client_area.X + (int)(client_area.Width * percent_done); + goto default; + default: // Blocks + int block_width = renderer.GetInteger (IntegerProperty.ProgressChunkSize); + block_width = Math.Max (block_width, 0); // block_width is used to break out the loop below, it must be >= 0! + int first_pixel_outside_filled_area = (int)(((double)(ctrl.Value - ctrl.Minimum) * client_area.Width) / (Math.Max (ctrl.Maximum - ctrl.Minimum, 1))) + client_area.X; + int block_count = 0; + int increment = block_width + renderer.GetInteger (IntegerProperty.ProgressSpaceSize); + Rectangle block_rect = new Rectangle (start_pixel, client_area.Y, block_width, client_area.Height); + while (true) { + if (max_blocks != int.MaxValue) { + if (block_count == max_blocks) + break; + if (block_rect.Right >= client_area.Width) + block_rect.X -= client_area.Width; + } else { + if (block_rect.X >= first_pixel_outside_filled_area) + break; + if (block_rect.Right >= first_pixel_outside_filled_area) + if (first_pixel_outside_filled_area == client_area.Right) + block_rect.Width = first_pixel_outside_filled_area - block_rect.X; + else + break; + } + if (clip_rect.IntersectsWith (block_rect)) + renderer.DrawBackground (dc, block_rect, clip_rect); + block_rect.X += increment; + block_count++; + } + break; + } + } + #endregion + #region RadioButton + protected override void RadioButton_DrawButton (RadioButton radio_button, Graphics dc, ButtonState state, Rectangle radiobutton_rectangle) { + if (radio_button.Appearance == Appearance.Normal && radio_button.FlatStyle == FlatStyle.System) { + RadioButtonRenderer.DrawRadioButton ( + dc, + new Point (radiobutton_rectangle.Left, radiobutton_rectangle.Top), + GetRadioButtonState (radio_button) + ); + return; + } + base.RadioButton_DrawButton(radio_button, dc, state, radiobutton_rectangle); + } + static RadioButtonState GetRadioButtonState (RadioButton checkBox) + { + if (checkBox.Checked) { + if (!checkBox.Enabled) + return RadioButtonState.CheckedDisabled; + else if (checkBox.Pressed) + return RadioButtonState.CheckedPressed; + else if (checkBox.Entered) + return RadioButtonState.CheckedHot; + return RadioButtonState.CheckedNormal; + } else { + if (!checkBox.Enabled) + return RadioButtonState.UncheckedDisabled; + else if (checkBox.Pressed) + return RadioButtonState.UncheckedPressed; + else if (checkBox.Entered) + return RadioButtonState.UncheckedHot; + return RadioButtonState.UncheckedNormal; + } + } + #endregion + #region ScrollBar + public override void DrawScrollBar (Graphics dc, Rectangle clip, ScrollBar bar) + { + if (!RenderClientAreas || + !ScrollBarAreElementsDefined) { + base.DrawScrollBar (dc, clip, bar); + return; + } + VisualStyleElement element; + VisualStyleRenderer renderer; + int scroll_button_width = bar.scrollbutton_width; + int scroll_button_height = bar.scrollbutton_height; + if (bar.vert) { + bar.FirstArrowArea = new Rectangle (0, 0, bar.Width, scroll_button_height); + bar.SecondArrowArea = new Rectangle ( + 0, + bar.ClientRectangle.Height - scroll_button_height, + bar.Width, + scroll_button_height); + Rectangle thumb_pos = bar.ThumbPos; + thumb_pos.Width = bar.Width; + bar.ThumbPos = thumb_pos; + #region Background, upper track + if (bar.thumb_moving == ScrollBar.ThumbMoving.Backwards) + element = VisualStyleElement.ScrollBar.LowerTrackVertical.Pressed; + else + element = bar.Enabled ? + VisualStyleElement.ScrollBar.LowerTrackVertical.Normal : + VisualStyleElement.ScrollBar.LowerTrackVertical.Disabled; + renderer = new VisualStyleRenderer (element); + Rectangle upper_track_rect = new Rectangle ( + 0, + 0, + bar.ClientRectangle.Width, + bar.ThumbPos.Top); + if (clip.IntersectsWith (upper_track_rect)) + renderer.DrawBackground (dc, upper_track_rect, clip); + #endregion + #region Background, lower track + if (bar.thumb_moving == ScrollBar.ThumbMoving.Forward) + element = VisualStyles.VisualStyleElement.ScrollBar.LowerTrackVertical.Pressed; + else + element = bar.Enabled ? + VisualStyleElement.ScrollBar.LowerTrackVertical.Normal : + VisualStyleElement.ScrollBar.LowerTrackVertical.Disabled; + renderer = new VisualStyleRenderer (element); + Rectangle lower_track_rect = new Rectangle ( + 0, + bar.ThumbPos.Bottom, + bar.ClientRectangle.Width, + bar.ClientRectangle.Height - bar.ThumbPos.Bottom); + if (clip.IntersectsWith (lower_track_rect)) + renderer.DrawBackground (dc, lower_track_rect, clip); + #endregion + #region Buttons + if (clip.IntersectsWith (bar.FirstArrowArea)) { + if (!bar.Enabled) + element = VisualStyleElement.ScrollBar.ArrowButton.UpDisabled; + else if (bar.firstbutton_state == ButtonState.Pushed) + element = VisualStyleElement.ScrollBar.ArrowButton.UpPressed; + else if (bar.FirstButtonEntered) + element = VisualStyleElement.ScrollBar.ArrowButton.UpHot; + else if (ScrollBarHasHoverArrowButtonStyleVisualStyles && bar.Entered) + element = VisualStyleElement.ScrollBar.ArrowButton.UpHover; + else + element = VisualStyleElement.ScrollBar.ArrowButton.UpNormal; + renderer = new VisualStyleRenderer (element); + renderer.DrawBackground (dc, bar.FirstArrowArea); + } + if (clip.IntersectsWith (bar.SecondArrowArea)) { + if (!bar.Enabled) + element = VisualStyleElement.ScrollBar.ArrowButton.DownDisabled; + else if (bar.secondbutton_state == ButtonState.Pushed) + element = VisualStyleElement.ScrollBar.ArrowButton.DownPressed; + else if (bar.SecondButtonEntered) + element = VisualStyleElement.ScrollBar.ArrowButton.DownHot; + else if (ScrollBarHasHoverArrowButtonStyleVisualStyles && bar.Entered) + element = VisualStyleElement.ScrollBar.ArrowButton.DownHover; + else + element = VisualStyleElement.ScrollBar.ArrowButton.DownNormal; + renderer = new VisualStyleRenderer (element); + renderer.DrawBackground (dc, bar.SecondArrowArea); + } + #endregion + #region Thumb and grip + if (!bar.Enabled) + element = VisualStyleElement.ScrollBar.LowerTrackVertical.Disabled; + else if (bar.ThumbPressed) + element = VisualStyleElement.ScrollBar.ThumbButtonVertical.Pressed; + else if (bar.ThumbEntered) + element = VisualStyleElement.ScrollBar.ThumbButtonVertical.Hot; + else + element = VisualStyleElement.ScrollBar.ThumbButtonVertical.Normal; + renderer = new VisualStyleRenderer (element); + renderer.DrawBackground (dc, bar.ThumbPos, clip); + + if (bar.Enabled && bar.ThumbPos.Height >= 20) { + element = VisualStyleElement.ScrollBar.GripperVertical.Normal; + if (VisualStyleRenderer.IsElementDefined (element)) { + renderer = new VisualStyleRenderer (element); + renderer.DrawBackground (dc, bar.ThumbPos, clip); + } + } + #endregion + } else { + bar.FirstArrowArea = new Rectangle (0, 0, scroll_button_width, bar.Height); + bar.SecondArrowArea = new Rectangle ( + bar.ClientRectangle.Width - scroll_button_width, + 0, + scroll_button_width, + bar.Height); + Rectangle thumb_pos = bar.ThumbPos; + thumb_pos.Height = bar.Height; + bar.ThumbPos = thumb_pos; + #region Background, left track + if (bar.thumb_moving == ScrollBar.ThumbMoving.Backwards) + element = VisualStyleElement.ScrollBar.LeftTrackHorizontal.Pressed; + else + element = bar.Enabled ? + VisualStyleElement.ScrollBar.LeftTrackHorizontal.Normal : + VisualStyleElement.ScrollBar.LeftTrackHorizontal.Disabled; + renderer = new VisualStyleRenderer (element); + Rectangle left_track_rect = new Rectangle ( + 0, + 0, + bar.ThumbPos.Left, + bar.ClientRectangle.Height); + if (clip.IntersectsWith (left_track_rect)) + renderer.DrawBackground (dc, left_track_rect, clip); + #endregion + #region Background, right track + if (bar.thumb_moving == ScrollBar.ThumbMoving.Forward) + element = VisualStyleElement.ScrollBar.RightTrackHorizontal.Pressed; + else + element = bar.Enabled ? + VisualStyleElement.ScrollBar.RightTrackHorizontal.Normal : + VisualStyleElement.ScrollBar.RightTrackHorizontal.Disabled; + renderer = new VisualStyleRenderer (element); + Rectangle right_track_rect = new Rectangle ( + bar.ThumbPos.Right, + 0, + bar.ClientRectangle.Width - bar.ThumbPos.Right, + bar.ClientRectangle.Height); + if (clip.IntersectsWith (right_track_rect)) + renderer.DrawBackground (dc, right_track_rect, clip); + #endregion + #region Buttons + if (clip.IntersectsWith (bar.FirstArrowArea)) { + if (!bar.Enabled) + element = VisualStyleElement.ScrollBar.ArrowButton.LeftDisabled; + else if (bar.firstbutton_state == ButtonState.Pushed) + element = VisualStyleElement.ScrollBar.ArrowButton.LeftPressed; + else if (bar.FirstButtonEntered) + element = VisualStyleElement.ScrollBar.ArrowButton.LeftHot; + else if (ScrollBarHasHoverArrowButtonStyleVisualStyles && bar.Entered) + element = VisualStyleElement.ScrollBar.ArrowButton.LeftHover; + else + element = VisualStyleElement.ScrollBar.ArrowButton.LeftNormal; + renderer = new VisualStyleRenderer (element); + renderer.DrawBackground (dc, bar.FirstArrowArea); + } + if (clip.IntersectsWith (bar.SecondArrowArea)) { + if (!bar.Enabled) + element = VisualStyleElement.ScrollBar.ArrowButton.RightDisabled; + else if (bar.secondbutton_state == ButtonState.Pushed) + element = VisualStyleElement.ScrollBar.ArrowButton.RightPressed; + else if (bar.SecondButtonEntered) + element = VisualStyleElement.ScrollBar.ArrowButton.RightHot; + else if (ScrollBarHasHoverArrowButtonStyleVisualStyles && bar.Entered) + element = VisualStyleElement.ScrollBar.ArrowButton.RightHover; + else + element = VisualStyleElement.ScrollBar.ArrowButton.RightNormal; + renderer = new VisualStyleRenderer (element); + renderer.DrawBackground (dc, bar.SecondArrowArea); + } + #endregion + #region Thumb and grip + if (!bar.Enabled) + element = VisualStyleElement.ScrollBar.RightTrackHorizontal.Disabled; + else if (bar.ThumbPressed) + element = VisualStyleElement.ScrollBar.ThumbButtonHorizontal.Pressed; + else if (bar.ThumbEntered) + element = VisualStyleElement.ScrollBar.ThumbButtonHorizontal.Hot; + else + element = VisualStyleElement.ScrollBar.ThumbButtonHorizontal.Normal; + renderer = new VisualStyleRenderer (element); + renderer.DrawBackground (dc, bar.ThumbPos, clip); + + if (bar.Enabled && bar.ThumbPos.Height >= 20) { + element = VisualStyleElement.ScrollBar.GripperHorizontal.Normal; + if (VisualStyleRenderer.IsElementDefined (element)) { + renderer = new VisualStyleRenderer (element); + renderer.DrawBackground (dc, bar.ThumbPos, clip); + } + } + #endregion + } + } + public override bool ScrollBarHasHotElementStyles { + get { + if (!RenderClientAreas) + return base.ScrollBarHasHotElementStyles; + return ScrollBarAreElementsDefined; + } + } + public override bool ScrollBarHasPressedThumbStyle { + get { + if (!RenderClientAreas) + return base.ScrollBarHasPressedThumbStyle; + return ScrollBarAreElementsDefined; + } + } + const int WindowsVistaMajorVersion = 6; + static bool ScrollBarHasHoverArrowButtonStyleVisualStyles = + Environment.OSVersion.Version.Major >= WindowsVistaMajorVersion; + public override bool ScrollBarHasHoverArrowButtonStyle { + get { + if (RenderClientAreas && + ScrollBarHasHoverArrowButtonStyleVisualStyles) + return ScrollBarAreElementsDefined; + return base.ScrollBarHasHoverArrowButtonStyle; + } + } + static bool ScrollBarAreElementsDefined { + get { + return + VisualStyleRenderer.IsElementDefined (VisualStyleElement.ScrollBar.ArrowButton.DownDisabled) && + VisualStyleRenderer.IsElementDefined (VisualStyleElement.ScrollBar.LeftTrackHorizontal.Disabled) && + VisualStyleRenderer.IsElementDefined (VisualStyleElement.ScrollBar.LowerTrackVertical.Disabled) && + VisualStyleRenderer.IsElementDefined (VisualStyleElement.ScrollBar.RightTrackHorizontal.Disabled) && + VisualStyleRenderer.IsElementDefined (VisualStyleElement.ScrollBar.ThumbButtonHorizontal.Disabled) && + VisualStyleRenderer.IsElementDefined (VisualStyleElement.ScrollBar.ThumbButtonVertical.Disabled) && + VisualStyleRenderer.IsElementDefined (VisualStyleElement.ScrollBar.UpperTrackVertical.Disabled); + } + } + #endregion + #region StatusBar + protected override void DrawStatusBarBackground(Graphics dc, Rectangle clip, StatusBar sb) { + if (!RenderClientAreas) { + base.DrawStatusBarBackground (dc, clip, sb); + return; + } + VisualStyleElement element = VisualStyleElement.Status.Bar.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.DrawStatusBarBackground (dc, clip, sb); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, sb.ClientRectangle, clip); + } + protected override void DrawStatusBarSizingGrip (Graphics dc, Rectangle clip, StatusBar sb, Rectangle area) + { + if (!RenderClientAreas) { + base.DrawStatusBarSizingGrip (dc, clip, sb, area); + return; + } + VisualStyleElement element = VisualStyleElement.Status.Gripper.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.DrawStatusBarSizingGrip (dc, clip, sb, area); + return; + } + VisualStyleRenderer renderer = new VisualStyleRenderer (element); + Rectangle sizing_grip_rectangle = new Rectangle (Point.Empty, renderer.GetPartSize (dc, ThemeSizeType.True)); + sizing_grip_rectangle.X = sb.Width - sizing_grip_rectangle.Width; + sizing_grip_rectangle.Y = sb.Height - sizing_grip_rectangle.Height; + renderer.DrawBackground (dc, sizing_grip_rectangle, clip); + } + protected override void DrawStatusBarPanelBackground (Graphics dc, Rectangle area, StatusBarPanel panel) + { + if (!RenderClientAreas) { + base.DrawStatusBarPanelBackground (dc, area, panel); + return; + } + VisualStyleElement element = VisualStyleElement.Status.Pane.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.DrawStatusBarPanelBackground (dc, area, panel); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, area); + } + #endregion + #region TextBoxBase + static bool TextBoxBaseShouldPaint (TextBoxBase textBoxBase) + { + return textBoxBase.BorderStyle == BorderStyle.Fixed3D; + } + static VisualStyleElement TextBoxBaseGetVisualStyleElement (TextBoxBase textBoxBase) + { + if (!textBoxBase.Enabled) + return VisualStyleElement.TextBox.TextEdit.Disabled; + if (textBoxBase.ReadOnly) + return VisualStyleElement.TextBox.TextEdit.ReadOnly; + if (textBoxBase.Entered) + return VisualStyleElement.TextBox.TextEdit.Hot; + if (textBoxBase.Focused) + return VisualStyleElement.TextBox.TextEdit.Focused; + return VisualStyleElement.TextBox.TextEdit.Normal; + } + public override void TextBoxBaseFillBackground (TextBoxBase textBoxBase, Graphics g, Rectangle clippingArea) + { + if (!RenderClientAreas || + !TextBoxBaseShouldPaint (textBoxBase)) { + base.TextBoxBaseFillBackground (textBoxBase, g, clippingArea); + return; + } + VisualStyleElement element = TextBoxBaseGetVisualStyleElement (textBoxBase); + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.TextBoxBaseFillBackground (textBoxBase, g, clippingArea); + return; + } + Rectangle bounds = new Rectangle(Point.Empty, textBoxBase.Size); + bounds.X -= (bounds.Width - textBoxBase.ClientSize.Width) / 2; + bounds.Y -= (bounds.Height - textBoxBase.ClientSize.Height) / 2; + new VisualStyleRenderer (element).DrawBackground (g, bounds, clippingArea); + } + public override bool TextBoxBaseHandleWmNcPaint (TextBoxBase textBoxBase, ref Message m) + { + if (!RenderClientAreas || + !TextBoxBaseShouldPaint (textBoxBase)) + return base.TextBoxBaseHandleWmNcPaint (textBoxBase, ref m); + VisualStyleElement element = TextBoxBaseGetVisualStyleElement (textBoxBase); + if (!VisualStyleRenderer.IsElementDefined (element)) + return base.TextBoxBaseHandleWmNcPaint (textBoxBase, ref m); + PaintEventArgs e = XplatUI.PaintEventStart (ref m, textBoxBase.Handle, false); + new VisualStyleRenderer (element).DrawBackgroundExcludingArea ( + e.Graphics, + new Rectangle (Point.Empty, textBoxBase.Size), + new Rectangle (new Point ((textBoxBase.Width - textBoxBase.ClientSize.Width) / 2, + (textBoxBase.Height - textBoxBase.ClientSize.Height) / 2), + textBoxBase.ClientSize)); + XplatUI.PaintEventEnd (ref m, textBoxBase.Handle, false); + return true; + } + public override bool TextBoxBaseShouldPaintBackground (TextBoxBase textBoxBase) + { + if (!RenderClientAreas || + !TextBoxBaseShouldPaint (textBoxBase)) + return base.TextBoxBaseShouldPaintBackground (textBoxBase); + VisualStyleElement element = TextBoxBaseGetVisualStyleElement (textBoxBase); + if (!VisualStyleRenderer.IsElementDefined (element)) + return base.TextBoxBaseShouldPaintBackground (textBoxBase); + return new VisualStyleRenderer (element).IsBackgroundPartiallyTransparent (); + } + #endregion + /* FIXME: I SAID NO. + #region ToolBar + static bool ToolBarIsDisabled (ToolBarItem item) + { + return !item.Button.Enabled; + } + static bool ToolBarIsPressed (ToolBarItem item) + { + return item.Pressed; + } + static bool ToolBarIsChecked (ToolBarItem item) + { + return item.Button.Pushed; + } + static bool ToolBarIsHot (ToolBarItem item) + { + return item.Hilight; + } + #region Border + protected override void DrawToolBarButtonBorder (Graphics dc, ToolBarItem item, bool is_flat) + { + if (!RenderClientAreas) { + base.DrawToolBarButtonBorder (dc, item, is_flat); + return; + } + if (item.Button.Style == ToolBarButtonStyle.Separator) + return; + VisualStyleElement element; + if (item.Button.Style == ToolBarButtonStyle.DropDownButton) + element = ToolBarGetDropDownButtonVisualStyleElement (item); + else + element = ToolBarGetButtonVisualStyleElement (item); + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.DrawToolBarButtonBorder (dc, item, is_flat); + return; + } + Rectangle rectangle = item.Rectangle; + if (item.Button.Style == ToolBarButtonStyle.DropDownButton && item.Button.Parent.DropDownArrows) + rectangle.Width -= ToolBarDropDownWidth; + new VisualStyleRenderer (element).DrawBackground (dc, rectangle); + } + private static VisualStyleElement ToolBarGetDropDownButtonVisualStyleElement (ToolBarItem item) + { + if (item.Button.Parent.DropDownArrows) { + if (ToolBarIsDisabled (item)) + return VisualStyleElement.ToolBar.SplitButton.Disabled; + if (ToolBarIsPressed (item)) + return VisualStyleElement.ToolBar.SplitButton.Pressed; + if (ToolBarIsChecked (item)) + if (ToolBarIsHot (item)) + return VisualStyleElement.ToolBar.SplitButton.HotChecked; + else + return VisualStyleElement.ToolBar.SplitButton.Checked; + if (ToolBarIsHot (item)) + return VisualStyleElement.ToolBar.SplitButton.Hot; + return VisualStyleElement.ToolBar.SplitButton.Normal; + } else { + if (ToolBarIsDisabled (item)) + return VisualStyleElement.ToolBar.DropDownButton.Disabled; + if (ToolBarIsPressed (item)) + return VisualStyleElement.ToolBar.DropDownButton.Pressed; + if (ToolBarIsChecked (item)) + if (ToolBarIsHot (item)) + return VisualStyleElement.ToolBar.DropDownButton.HotChecked; + else + return VisualStyleElement.ToolBar.DropDownButton.Checked; + if (ToolBarIsHot (item)) + return VisualStyleElement.ToolBar.DropDownButton.Hot; + return VisualStyleElement.ToolBar.DropDownButton.Normal; + } + } + private static VisualStyleElement ToolBarGetButtonVisualStyleElement (ToolBarItem item) + { + if (ToolBarIsDisabled (item)) + return VisualStyleElement.ToolBar.Button.Disabled; + if (ToolBarIsPressed (item)) + return VisualStyleElement.ToolBar.Button.Pressed; + if (ToolBarIsChecked (item)) + if (ToolBarIsHot (item)) + return VisualStyleElement.ToolBar.Button.HotChecked; + else + return VisualStyleElement.ToolBar.Button.Checked; + if (ToolBarIsHot (item)) + return VisualStyleElement.ToolBar.Button.Hot; + return VisualStyleElement.ToolBar.Button.Normal; + } + #endregion + #region Separator + protected override void DrawToolBarSeparator (Graphics dc, ToolBarItem item) + { + if (!RenderClientAreas) { + base.DrawToolBarSeparator (dc, item); + return; + } + VisualStyleElement element = ToolBarGetSeparatorVisualStyleElement (item); + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.DrawToolBarSeparator (dc, item); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, item.Rectangle); + } + static VisualStyleElement ToolBarGetSeparatorVisualStyleElement (ToolBarItem toolBarItem) + { + return toolBarItem.Button.Parent.Vertical ? + VisualStyleElement.ToolBar.SeparatorVertical.Normal : + VisualStyleElement.ToolBar.SeparatorHorizontal.Normal; + } + #endregion + #region Toggle button background + protected override void DrawToolBarToggleButtonBackground (Graphics dc, ToolBarItem item) + { + if (!RenderClientAreas || + !VisualStyleRenderer.IsElementDefined (ToolBarGetButtonVisualStyleElement (item))) + base.DrawToolBarToggleButtonBackground (dc, item); + } + #endregion + #region Drop down arrow + protected override void DrawToolBarDropDownArrow (Graphics dc, ToolBarItem item, bool is_flat) + { + if (!RenderClientAreas) { + base.DrawToolBarDropDownArrow (dc, item, is_flat); + return; + } + VisualStyleElement element = ToolBarGetDropDownArrowVisualStyleElement (item); + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.DrawToolBarDropDownArrow (dc, item, is_flat); + return; + } + Rectangle rect = item.Rectangle; + rect.X = item.Rectangle.Right - ToolBarDropDownWidth; + rect.Width = ToolBarDropDownWidth; + new VisualStyleRenderer (element).DrawBackground (dc, rect); + } + private static VisualStyleElement ToolBarGetDropDownArrowVisualStyleElement (ToolBarItem item) + { + if (ToolBarIsDisabled (item)) + return VisualStyleElement.ToolBar.SplitButtonDropDown.Disabled; + if (ToolBarIsPressed (item)) + return VisualStyleElement.ToolBar.SplitButtonDropDown.Pressed; + if (ToolBarIsChecked (item)) + if (ToolBarIsHot (item)) + return VisualStyleElement.ToolBar.SplitButtonDropDown.HotChecked; + else + return VisualStyleElement.ToolBar.SplitButtonDropDown.Checked; + if (ToolBarIsHot (item)) + return VisualStyleElement.ToolBar.SplitButtonDropDown.Hot; + return VisualStyleElement.ToolBar.SplitButtonDropDown.Normal; + } + #endregion + public override bool ToolBarHasHotElementStyles (ToolBar toolBar) + { + if (!RenderClientAreas) + return base.ToolBarHasHotElementStyles (toolBar); + return true; + } + public override bool ToolBarHasHotCheckedElementStyles { + get { + if (!RenderClientAreas) + return base.ToolBarHasHotCheckedElementStyles; + return true; + } + } + #endregion*/ + #region ToolTip + protected override void ToolTipDrawBackground (Graphics dc, Rectangle clip_rectangle, ToolTip.ToolTipWindow control) + { + if (!RenderClientAreas) { + base.ToolTipDrawBackground (dc, clip_rectangle, control); + return; + } + VisualStyleElement element = VisualStyleElement.ToolTip.Standard.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.ToolTipDrawBackground (dc, clip_rectangle, control); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, control.ClientRectangle); + } + public override bool ToolTipTransparentBackground { + get { + if (!RenderClientAreas) + return base.ToolTipTransparentBackground; + VisualStyleElement element = VisualStyleElement.ToolTip.Standard.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) + return base.ToolTipTransparentBackground; + return new VisualStyleRenderer (element).IsBackgroundPartiallyTransparent (); + } + } + #endregion + #region TrackBar + protected override Size TrackBarGetThumbSize (TrackBar trackBar) + { + if (!RenderClientAreas) + return base.TrackBarGetThumbSize (trackBar); + VisualStyleElement element = TrackBarGetThumbVisualStyleElement (trackBar); + if (!VisualStyleRenderer.IsElementDefined (element)) + return base.TrackBarGetThumbSize (trackBar); + Graphics g = trackBar.CreateGraphics (); + Size result = new VisualStyleRenderer (element).GetPartSize (g, ThemeSizeType.True); + g.Dispose (); + return trackBar.Orientation == Orientation.Horizontal ? result : TrackBarRotateVerticalThumbSize (result); + } + static VisualStyleElement TrackBarGetThumbVisualStyleElement (TrackBar trackBar) + { + if (trackBar.Orientation == Orientation.Horizontal) + switch (trackBar.TickStyle) { + case TickStyle.BottomRight: + case TickStyle.None: + return TrackBarGetHorizontalThumbBottomVisualStyleElement (trackBar); + case TickStyle.TopLeft: + return TrackBarGetHorizontalThumbTopVisualStyleElement (trackBar); + default: + return TrackBarGetHorizontalThumbVisualStyleElement (trackBar); + } + else + switch (trackBar.TickStyle) { + case TickStyle.BottomRight: + case TickStyle.None: + return TrackBarGetVerticalThumbRightVisualStyleElement (trackBar); + case TickStyle.TopLeft: + return TrackBarGetVerticalThumbLeftVisualStyleElement (trackBar); + default: + return TrackBarGetVerticalThumbVisualStyleElement (trackBar); + } + } + static Size TrackBarRotateVerticalThumbSize (Size value) + { + int temporary = value.Width; + value.Width = value.Height; + value.Height = temporary; + return value; + } + #region Track + protected override void TrackBarDrawHorizontalTrack (Graphics dc, Rectangle thumb_area, Point channel_startpoint, Rectangle clippingArea) + { + if (!RenderClientAreas) { + base.TrackBarDrawHorizontalTrack (dc, thumb_area, channel_startpoint, clippingArea); + return; + } + VisualStyleElement element = VisualStyleElement.TrackBar.Track.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.TrackBarDrawHorizontalTrack (dc, thumb_area, channel_startpoint, clippingArea); + return; + } + VisualStyleRenderer renderer = new VisualStyleRenderer (element); + renderer.DrawBackground (dc, new Rectangle (channel_startpoint, new Size (thumb_area.Width, renderer.GetPartSize (dc, ThemeSizeType.True).Height)), clippingArea); + } + protected override void TrackBarDrawVerticalTrack (Graphics dc, Rectangle thumb_area, Point channel_startpoint, Rectangle clippingArea) + { + if (!RenderClientAreas) { + base.TrackBarDrawVerticalTrack (dc, thumb_area, channel_startpoint, clippingArea); + return; + } + VisualStyleElement element = VisualStyleElement.TrackBar.TrackVertical.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.TrackBarDrawVerticalTrack (dc, thumb_area, channel_startpoint, clippingArea); + return; + } + VisualStyleRenderer renderer = new VisualStyleRenderer (element); + renderer.DrawBackground (dc, new Rectangle (channel_startpoint, new Size (renderer.GetPartSize (dc, ThemeSizeType.True).Width, thumb_area.Height)), clippingArea); + } + #endregion + #region Thumb + static bool TrackBarIsDisabled (TrackBar trackBar) + { + return !trackBar.Enabled; + } + static bool TrackBarIsHot (TrackBar trackBar) + { + return trackBar.ThumbEntered; + } + static bool TrackBarIsPressed (TrackBar trackBar) + { + return trackBar.thumb_pressed; + } + static bool TrackBarIsFocused (TrackBar trackBar) + { + return trackBar.Focused; + } + #region Horizontal + protected override void TrackBarDrawHorizontalThumbBottom (Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + if (!RenderClientAreas) { + base.TrackBarDrawHorizontalThumbBottom (dc, thumb_pos, br_thumb, clippingArea, trackBar); + return; + } + VisualStyleElement element = TrackBarGetHorizontalThumbBottomVisualStyleElement (trackBar); + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.TrackBarDrawHorizontalThumbBottom (dc, thumb_pos, br_thumb, clippingArea, trackBar); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, thumb_pos, clippingArea); + } + static VisualStyleElement TrackBarGetHorizontalThumbBottomVisualStyleElement (TrackBar trackBar) + { + if (TrackBarIsDisabled (trackBar)) + return VisualStyleElement.TrackBar.ThumbBottom.Disabled; + else if (TrackBarIsPressed (trackBar)) + return VisualStyleElement.TrackBar.ThumbBottom.Pressed; + else if (TrackBarIsHot (trackBar)) + return VisualStyleElement.TrackBar.ThumbBottom.Hot; + else if (TrackBarIsFocused (trackBar)) + return VisualStyleElement.TrackBar.ThumbBottom.Focused; + return VisualStyleElement.TrackBar.ThumbBottom.Normal; + } + protected override void TrackBarDrawHorizontalThumbTop (Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + if (!RenderClientAreas) { + base.TrackBarDrawHorizontalThumbTop (dc, thumb_pos, br_thumb, clippingArea, trackBar); + return; + } + VisualStyleElement element = TrackBarGetHorizontalThumbTopVisualStyleElement (trackBar); + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.TrackBarDrawHorizontalThumbTop (dc, thumb_pos, br_thumb, clippingArea, trackBar); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, thumb_pos, clippingArea); + } + static VisualStyleElement TrackBarGetHorizontalThumbTopVisualStyleElement (TrackBar trackBar) + { + if (TrackBarIsDisabled (trackBar)) + return VisualStyleElement.TrackBar.ThumbTop.Disabled; + else if (TrackBarIsPressed (trackBar)) + return VisualStyleElement.TrackBar.ThumbTop.Pressed; + else if (TrackBarIsHot (trackBar)) + return VisualStyleElement.TrackBar.ThumbTop.Hot; + else if (TrackBarIsFocused (trackBar)) + return VisualStyleElement.TrackBar.ThumbTop.Focused; + return VisualStyleElement.TrackBar.ThumbTop.Normal; + } + protected override void TrackBarDrawHorizontalThumb (Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + if (!RenderClientAreas) { + base.TrackBarDrawHorizontalThumb (dc, thumb_pos, br_thumb, clippingArea, trackBar); + return; + } + VisualStyleElement element = TrackBarGetHorizontalThumbVisualStyleElement (trackBar); + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.TrackBarDrawHorizontalThumb (dc, thumb_pos, br_thumb, clippingArea, trackBar); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, thumb_pos, clippingArea); + } + static VisualStyleElement TrackBarGetHorizontalThumbVisualStyleElement (TrackBar trackBar) + { + if (TrackBarIsDisabled (trackBar)) + return VisualStyleElement.TrackBar.Thumb.Disabled; + else if (TrackBarIsPressed (trackBar)) + return VisualStyleElement.TrackBar.Thumb.Pressed; + else if (TrackBarIsHot (trackBar)) + return VisualStyleElement.TrackBar.Thumb.Hot; + else if (TrackBarIsFocused (trackBar)) + return VisualStyleElement.TrackBar.Thumb.Focused; + return VisualStyleElement.TrackBar.Thumb.Normal; + } + #endregion + #region Vertical + static Rectangle TrackBarRotateVerticalThumbSize (Rectangle value) + { + int temporary = value.Width; + value.Width = value.Height; + value.Height = temporary; + return value; + } + protected override void TrackBarDrawVerticalThumbRight (Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + if (!RenderClientAreas) { + base.TrackBarDrawVerticalThumbRight (dc, thumb_pos, br_thumb, clippingArea, trackBar); + return; + } + VisualStyleElement element = TrackBarGetVerticalThumbRightVisualStyleElement (trackBar); + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.TrackBarDrawVerticalThumbRight (dc, thumb_pos, br_thumb, clippingArea, trackBar); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, TrackBarRotateVerticalThumbSize (thumb_pos), clippingArea); + } + static VisualStyleElement TrackBarGetVerticalThumbRightVisualStyleElement (TrackBar trackBar) + { + if (TrackBarIsDisabled (trackBar)) + return VisualStyleElement.TrackBar.ThumbRight.Disabled; + else if (TrackBarIsPressed (trackBar)) + return VisualStyleElement.TrackBar.ThumbRight.Pressed; + else if (TrackBarIsHot (trackBar)) + return VisualStyleElement.TrackBar.ThumbRight.Hot; + else if (TrackBarIsFocused (trackBar)) + return VisualStyleElement.TrackBar.ThumbRight.Focused; + return VisualStyleElement.TrackBar.ThumbRight.Normal; + } + protected override void TrackBarDrawVerticalThumbLeft (Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + if (!RenderClientAreas) { + base.TrackBarDrawVerticalThumbLeft (dc, thumb_pos, br_thumb, clippingArea, trackBar); + return; + } + VisualStyleElement element = TrackBarGetVerticalThumbLeftVisualStyleElement (trackBar); + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.TrackBarDrawVerticalThumbLeft (dc, thumb_pos, br_thumb, clippingArea, trackBar); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, TrackBarRotateVerticalThumbSize (thumb_pos), clippingArea); + } + static VisualStyleElement TrackBarGetVerticalThumbLeftVisualStyleElement (TrackBar trackBar) + { + if (TrackBarIsDisabled (trackBar)) + return VisualStyleElement.TrackBar.ThumbLeft.Disabled; + else if (TrackBarIsPressed (trackBar)) + return VisualStyleElement.TrackBar.ThumbLeft.Pressed; + else if (TrackBarIsHot (trackBar)) + return VisualStyleElement.TrackBar.ThumbLeft.Hot; + else if (TrackBarIsFocused (trackBar)) + return VisualStyleElement.TrackBar.ThumbLeft.Focused; + return VisualStyleElement.TrackBar.ThumbLeft.Normal; + } + protected override void TrackBarDrawVerticalThumb (Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + if (!RenderClientAreas) { + base.TrackBarDrawVerticalThumb (dc, thumb_pos, br_thumb, clippingArea, trackBar); + return; + } + VisualStyleElement element = TrackBarGetVerticalThumbVisualStyleElement (trackBar); + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.TrackBarDrawVerticalThumb (dc, thumb_pos, br_thumb, clippingArea, trackBar); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, TrackBarRotateVerticalThumbSize (thumb_pos), clippingArea); + } + static VisualStyleElement TrackBarGetVerticalThumbVisualStyleElement (TrackBar trackBar) + { + if (TrackBarIsDisabled (trackBar)) + return VisualStyleElement.TrackBar.ThumbVertical.Disabled; + else if (TrackBarIsPressed (trackBar)) + return VisualStyleElement.TrackBar.ThumbVertical.Pressed; + else if (TrackBarIsHot (trackBar)) + return VisualStyleElement.TrackBar.ThumbVertical.Hot; + else if (TrackBarIsFocused (trackBar)) + return VisualStyleElement.TrackBar.ThumbVertical.Focused; + return VisualStyleElement.TrackBar.ThumbVertical.Normal; + } + #endregion + #endregion + #region Ticks + const EdgeStyle TrackBarTickEdgeStyle = EdgeStyle.Bump; + const EdgeEffects TrackBarTickEdgeEffects = EdgeEffects.None; + #region Horizontal + protected override ITrackBarTickPainter TrackBarGetHorizontalTickPainter (Graphics g) + { + if (!RenderClientAreas || + !VisualStyleRenderer.IsElementDefined (VisualStyleElement.TrackBar.Ticks.Normal)) + return base.TrackBarGetHorizontalTickPainter (g); + return new TrackBarHorizontalTickPainter (g); + } + class TrackBarHorizontalTickPainter : ITrackBarTickPainter + { + readonly Graphics g; + readonly VisualStyleRenderer renderer; + public TrackBarHorizontalTickPainter (Graphics g) + { + this.g = g; + renderer = new VisualStyleRenderer (VisualStyleElement.TrackBar.Ticks.Normal); + } + public void Paint (float x1, float y1, float x2, float y2) + { + renderer.DrawEdge (g, new Rectangle ( + (int)Math.Round (x1), + (int)Math.Round (y1), + 1, + (int)Math.Round (y2 - y1) + 1), Edges.Left, TrackBarTickEdgeStyle, TrackBarTickEdgeEffects); + } + } + #endregion + #region Vertical + protected override ITrackBarTickPainter TrackBarGetVerticalTickPainter (Graphics g) + { + if (!RenderClientAreas || + !VisualStyleRenderer.IsElementDefined (VisualStyleElement.TrackBar.TicksVertical.Normal)) + return base.TrackBarGetVerticalTickPainter (g); + return new TrackBarVerticalTickPainter (g); + } + class TrackBarVerticalTickPainter : ITrackBarTickPainter + { + readonly Graphics g; + readonly VisualStyleRenderer renderer; + public TrackBarVerticalTickPainter (Graphics g) + { + this.g = g; + renderer = new VisualStyleRenderer (VisualStyleElement.TrackBar.TicksVertical.Normal); + } + public void Paint (float x1, float y1, float x2, float y2) + { + renderer.DrawEdge (g, new Rectangle ( + (int)Math.Round (x1), + (int)Math.Round (y1), + (int)Math.Round (x2 - x1) + 1, + 1), Edges.Top, TrackBarTickEdgeStyle, TrackBarTickEdgeEffects); + } + } + #endregion + #endregion + public override bool TrackBarHasHotThumbStyle { + get { + if (!RenderClientAreas) + return base.TrackBarHasHotThumbStyle; + return true; + } + } + #endregion + #region TreeView + [MonoInternalNote ("Use the sizing information provided by the VisualStyles API.")] + public override void TreeViewDrawNodePlusMinus (TreeView treeView, TreeNode node, Graphics dc, int x, int middle) + { + if (!RenderClientAreas) { + base.TreeViewDrawNodePlusMinus (treeView, node, dc, x, middle); + return; + } + VisualStyleElement element = node.IsExpanded ? + VisualStyleElement.TreeView.Glyph.Opened : + VisualStyleElement.TreeView.Glyph.Closed; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.TreeViewDrawNodePlusMinus (treeView, node, dc, x, middle); + return; + } + new VisualStyleRenderer (element).DrawBackground (dc, new Rectangle (x, middle - 4, 9, 9)); + } + #endregion + #region UpDownBase + public override void UpDownBaseDrawButton (Graphics g, Rectangle bounds, bool top, PushButtonState state) + { + if (!RenderClientAreas) { + base.UpDownBaseDrawButton (g, bounds, top, state); + return; + } + VisualStyleElement element; + if (top) + switch (state) { + case PushButtonState.Disabled: + element = VisualStyleElement.Spin.Up.Disabled; + break; + case PushButtonState.Pressed: + element = VisualStyleElement.Spin.Up.Pressed; + break; + case PushButtonState.Hot: + element = VisualStyleElement.Spin.Up.Hot; + break; + default: + element = VisualStyleElement.Spin.Up.Normal; + break; + } + else + switch (state) { + case PushButtonState.Disabled: + element = VisualStyleElement.Spin.Down.Disabled; + break; + case PushButtonState.Pressed: + element = VisualStyleElement.Spin.Down.Pressed; + break; + case PushButtonState.Hot: + element = VisualStyleElement.Spin.Down.Hot; + break; + default: + element = VisualStyleElement.Spin.Down.Normal; + break; + } + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.UpDownBaseDrawButton (g, bounds, top, state); + return; + } + new VisualStyleRenderer (element).DrawBackground (g, bounds); + } + public override bool UpDownBaseHasHotButtonStyle { + get { + if (!RenderClientAreas) + return base.UpDownBaseHasHotButtonStyle; + return true; + } + } + #endregion + #endregion + + static bool AreEqual (VisualStyleElement value1, VisualStyleElement value2) + { + return + value1.ClassName == value1.ClassName && + value1.Part == value2.Part && + value1.State == value2.State; + } + + #region Measurement device context + static Widget control; + static IDeviceContext GetMeasurementDeviceContext () + { + if (control == null) + control = new Widget (); + return control.CreateGraphics (); + } + static void ReleaseMeasurementDeviceContext (IDeviceContext dc) + { + dc.Dispose (); + } + #endregion + } +} diff --git a/source/ShiftUI/Theming/ThemeWin32Classic.cs b/source/ShiftUI/Theming/ThemeWin32Classic.cs new file mode 100644 index 0000000..8c89066 --- /dev/null +++ b/source/ShiftUI/Theming/ThemeWin32Classic.cs @@ -0,0 +1,7815 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// Peter Bartok, pbartok@novell.com +// John BouAntoun, jba-mono@optusnet.com.au +// Marek Safar, marek.safar@seznam.cz +// Alexander Olk, alex.olk@googlemail.com +// + +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.Drawing.Printing; +using System.Drawing.Text; +using System.Text; +using ShiftUI.Theming; +using System; + +namespace ShiftUI +{ + + internal class ThemeWin32Classic : Theme + { + public override Version Version { + get { + return new Version(0, 1, 0, 0); + } + } + + /* Hardcoded colour values not exposed in the API constants in all configurations */ + protected static readonly Color arrow_color = Color.Black; + protected static readonly Color pen_ticks_color = Color.Black; + protected static StringFormat string_format_menu_text; + protected static StringFormat string_format_menu_shortcut; + protected static StringFormat string_format_menu_menubar_text; + static ImageAttributes imagedisabled_attributes; + Font window_border_font; + const int SEPARATOR_HEIGHT = 6; + const int SEPARATOR_MIN_WIDTH = 20; + const int SM_CXBORDER = 1; + const int SM_CYBORDER = 1; + const int MENU_TAB_SPACE = 8; // Pixels added to the width of an item because of a tabd + const int MENU_BAR_ITEMS_SPACE = 8; // Space between menu bar items + const int CheckSize = 13; + + #region Principal Theme Methods + public ThemeWin32Classic () + { + ResetDefaults (); + } + + public override void ResetDefaults() { + defaultWindowBackColor = this.ColorWindow; + defaultWindowForeColor = this.ColorControlText; + window_border_font = null; + + /* Menu string formats */ + string_format_menu_text = new StringFormat (); + string_format_menu_text.LineAlignment = StringAlignment.Center; + string_format_menu_text.Alignment = StringAlignment.Near; + string_format_menu_text.HotkeyPrefix = HotkeyPrefix.Show; + string_format_menu_text.SetTabStops (0f, new float [] { 50f }); + string_format_menu_text.FormatFlags |= StringFormatFlags.NoWrap; + + string_format_menu_shortcut = new StringFormat (); + string_format_menu_shortcut.LineAlignment = StringAlignment.Center; + string_format_menu_shortcut.Alignment = StringAlignment.Far; + + string_format_menu_menubar_text = new StringFormat (); + string_format_menu_menubar_text.LineAlignment = StringAlignment.Center; + string_format_menu_menubar_text.Alignment = StringAlignment.Center; + string_format_menu_menubar_text.HotkeyPrefix = HotkeyPrefix.Show; + } + + public override bool DoubleBufferingSupported { + get {return true; } + } + + public override int HorizontalScrollBarHeight { + get { + return XplatUI.HorizontalScrollBarHeight; + } + } + + public override int VerticalScrollBarWidth { + get { + return XplatUI.VerticalScrollBarWidth; + } + } + + public override Font WindowBorderFont { + get { + return window_border_font ?? (window_border_font = new Font(FontFamily.GenericSansSerif, 8.25f, FontStyle.Bold)); + } + } + + #endregion // Principal Theme Methods + + #region Internal Methods + protected Brush GetControlBackBrush (Color c) { + if (c.ToArgb () == DefaultControlBackColor.ToArgb ()) + return SystemBrushes.Control; + return ResPool.GetSolidBrush (c); + } + + protected Brush GetControlForeBrush (Color c) { + if (c.ToArgb () == DefaultControlForeColor.ToArgb ()) + return SystemBrushes.ControlText; + return ResPool.GetSolidBrush (c); + } + #endregion // Internal Methods + + #region Widget + public override Font GetLinkFont (Widget control) + { + return new Font (control.Font.FontFamily, control.Font.Size, control.Font.Style | FontStyle.Underline, control.Font.Unit); + } + #endregion // Widget + + #region OwnerDraw Support + public override void DrawOwnerDrawBackground (DrawItemEventArgs e) + { + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) { + e.Graphics.FillRectangle (SystemBrushes.Highlight, e.Bounds); + return; + } + + e.Graphics.FillRectangle (ResPool.GetSolidBrush(e.BackColor), e.Bounds); + } + + public override void DrawOwnerDrawFocusRectangle (DrawItemEventArgs e) + { + if (e.State == DrawItemState.Focus) + CPDrawFocusRectangle (e.Graphics, e.Bounds, e.ForeColor, e.BackColor); + } + #endregion // OwnerDraw Support + + #region Button + #region Standard Button Style + public override void DrawButton (Graphics g, Button b, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle) + { + // Draw Button Background + DrawButtonBackground (g, b, clipRectangle); + + // If we have an image, draw it + if (imageBounds.Size != Size.Empty) + DrawButtonImage (g, b, imageBounds); + + // If we're focused, draw a focus rectangle + if (b.Focused && b.Enabled && b.ShowFocusCues) + DrawButtonFocus (g, b); + + // If we have text, draw it + if (textBounds != Rectangle.Empty) + DrawButtonText (g, b, textBounds); + } + + public virtual void DrawButtonBackground (Graphics g, Button button, Rectangle clipArea) + { + if (button.Pressed) + ThemeElements.DrawButton (g, button.ClientRectangle, ButtonThemeState.Pressed, button.BackColor, button.ForeColor); + else if (button.InternalSelected) + ThemeElements.DrawButton (g, button.ClientRectangle, ButtonThemeState.Default, button.BackColor, button.ForeColor); + else if (button.Entered) + ThemeElements.DrawButton (g, button.ClientRectangle, ButtonThemeState.Entered, button.BackColor, button.ForeColor); + else if (!button.Enabled) + ThemeElements.DrawButton (g, button.ClientRectangle, ButtonThemeState.Disabled, button.BackColor, button.ForeColor); + else + ThemeElements.DrawButton (g, button.ClientRectangle, ButtonThemeState.Normal, button.BackColor, button.ForeColor); + } + + public virtual void DrawButtonFocus (Graphics g, Button button) + { + WidgetPaint.DrawFocusRectangle (g, Rectangle.Inflate (button.ClientRectangle, -4, -4)); + } + + public virtual void DrawButtonImage (Graphics g, ButtonBase button, Rectangle imageBounds) + { + if (button.Enabled) + g.DrawImage (button.Image, imageBounds); + else + CPDrawImageDisabled (g, button.Image, imageBounds.Left, imageBounds.Top, ColorControl); + } + + public virtual void DrawButtonText (Graphics g, ButtonBase button, Rectangle textBounds) + { + // Ensure that at least one line is going to get displayed. + // Line limit does not ensure that despite its description. + if (button.Font != null && button.Font.Height > 0) + textBounds.Height = Math.Max (textBounds.Height, button.Font.Height); + + if (button.Enabled) + TextRenderer.DrawTextInternal (g, button.Text, button.Font, textBounds, button.ForeColor, button.TextFormatFlags, button.UseCompatibleTextRendering); + else + DrawStringDisabled20 (g, button.Text, button.Font, textBounds, button.BackColor, button.TextFormatFlags, button.UseCompatibleTextRendering); + } + #endregion + + #region FlatStyle Button Style + public override void DrawFlatButton (Graphics g, ButtonBase b, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle) + { + // Draw Button Background + if (b.BackgroundImage == null) + DrawFlatButtonBackground (g, b, clipRectangle); + + // If we have an image, draw it + if (imageBounds.Size != Size.Empty) + DrawFlatButtonImage (g, b, imageBounds); + + // If we're focused, draw a focus rectangle + if (b.Focused && b.Enabled && b.ShowFocusCues) + DrawFlatButtonFocus (g, b); + + // If we have text, draw it + if (textBounds != Rectangle.Empty) + DrawFlatButtonText (g, b, textBounds); + } + + public virtual void DrawFlatButtonBackground (Graphics g, ButtonBase button, Rectangle clipArea) + { + if (button.Pressed) + ThemeElements.DrawFlatButton (g, button.ClientRectangle, ButtonThemeState.Pressed, button.BackColor, button.ForeColor, button.FlatAppearance); + else if (button.InternalSelected) { + if (button.Entered) + ThemeElements.DrawFlatButton (g, button.ClientRectangle, ButtonThemeState.Default | ButtonThemeState.Entered, button.BackColor, button.ForeColor, button.FlatAppearance); + else + ThemeElements.DrawFlatButton (g, button.ClientRectangle, ButtonThemeState.Default, button.BackColor, button.ForeColor, button.FlatAppearance); + } + else if (button.Entered) + ThemeElements.DrawFlatButton (g, button.ClientRectangle, ButtonThemeState.Entered, button.BackColor, button.ForeColor, button.FlatAppearance); + else if (!button.Enabled) + ThemeElements.DrawFlatButton (g, button.ClientRectangle, ButtonThemeState.Disabled, button.BackColor, button.ForeColor, button.FlatAppearance); + else + ThemeElements.DrawFlatButton (g, button.ClientRectangle, ButtonThemeState.Normal, button.BackColor, button.ForeColor, button.FlatAppearance); + } + + public virtual void DrawFlatButtonFocus (Graphics g, ButtonBase button) + { + if (!button.Pressed) { + Color focus_color = WidgetPaint.Dark (button.BackColor); + g.DrawRectangle (ResPool.GetPen (focus_color), new Rectangle (button.ClientRectangle.Left + 4, button.ClientRectangle.Top + 4, button.ClientRectangle.Width - 9, button.ClientRectangle.Height - 9)); + } + } + + public virtual void DrawFlatButtonImage (Graphics g, ButtonBase button, Rectangle imageBounds) + { + // No changes from Standard for image for this theme + DrawButtonImage (g, button, imageBounds); + } + + public virtual void DrawFlatButtonText (Graphics g, ButtonBase button, Rectangle textBounds) + { + // No changes from Standard for text for this theme + DrawButtonText (g, button, textBounds); + } + #endregion + + #region Popup Button Style + public override void DrawPopupButton (Graphics g, Button b, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle) + { + // Draw Button Background + DrawPopupButtonBackground (g, b, clipRectangle); + + // If we have an image, draw it + if (imageBounds.Size != Size.Empty) + DrawPopupButtonImage (g, b, imageBounds); + + // If we're focused, draw a focus rectangle + if (b.Focused && b.Enabled && b.ShowFocusCues) + DrawPopupButtonFocus (g, b); + + // If we have text, draw it + if (textBounds != Rectangle.Empty) + DrawPopupButtonText (g, b, textBounds); + } + + public virtual void DrawPopupButtonBackground (Graphics g, Button button, Rectangle clipArea) + { + if (button.Pressed) + ThemeElements.DrawPopupButton (g, button.ClientRectangle, ButtonThemeState.Pressed, button.BackColor, button.ForeColor); + else if (button.Entered) + ThemeElements.DrawPopupButton (g, button.ClientRectangle, ButtonThemeState.Entered, button.BackColor, button.ForeColor); + else if (button.InternalSelected) + ThemeElements.DrawPopupButton (g, button.ClientRectangle, ButtonThemeState.Default, button.BackColor, button.ForeColor); + else if (!button.Enabled) + ThemeElements.DrawPopupButton (g, button.ClientRectangle, ButtonThemeState.Disabled, button.BackColor, button.ForeColor); + else + ThemeElements.DrawPopupButton (g, button.ClientRectangle, ButtonThemeState.Normal, button.BackColor, button.ForeColor); + } + + public virtual void DrawPopupButtonFocus (Graphics g, Button button) + { + // No changes from Standard for image for this theme + DrawButtonFocus (g, button); + } + + public virtual void DrawPopupButtonImage (Graphics g, Button button, Rectangle imageBounds) + { + // No changes from Standard for image for this theme + DrawButtonImage (g, button, imageBounds); + } + + public virtual void DrawPopupButtonText (Graphics g, Button button, Rectangle textBounds) + { + // No changes from Standard for image for this theme + DrawButtonText (g, button, textBounds); + } + #endregion + + #region Button Layout Calculations + public override Size CalculateButtonAutoSize (Button button) + { + Size ret_size = Size.Empty; + Size text_size = TextRenderer.MeasureTextInternal (button.Text, button.Font, button.UseCompatibleTextRendering); + Size image_size = button.Image == null ? Size.Empty : button.Image.Size; + + // Pad the text size + if (button.Text.Length != 0) { + text_size.Height += 4; + text_size.Width += 4; + } + + switch (button.TextImageRelation) { + case TextImageRelation.Overlay: + ret_size.Height = Math.Max (button.Text.Length == 0 ? 0 : text_size.Height, image_size.Height); + ret_size.Width = Math.Max (text_size.Width, image_size.Width); + break; + case TextImageRelation.ImageAboveText: + case TextImageRelation.TextAboveImage: + ret_size.Height = text_size.Height + image_size.Height; + ret_size.Width = Math.Max (text_size.Width, image_size.Width); + break; + case TextImageRelation.ImageBeforeText: + case TextImageRelation.TextBeforeImage: + ret_size.Height = Math.Max (text_size.Height, image_size.Height); + ret_size.Width = text_size.Width + image_size.Width; + break; + } + + // Pad the result + ret_size.Height += (button.Padding.Vertical + 6); + ret_size.Width += (button.Padding.Horizontal + 6); + + return ret_size; + } + + public override void CalculateButtonTextAndImageLayout (Graphics g, ButtonBase button, out Rectangle textRectangle, out Rectangle imageRectangle) + { + Image image = button.Image; + string text = button.Text; + Rectangle content_rect = button.PaddingClientRectangle; + Size text_size = TextRenderer.MeasureTextInternal (g, text, button.Font, content_rect.Size, button.TextFormatFlags, button.UseCompatibleTextRendering); + Size image_size = image == null ? Size.Empty : image.Size; + + textRectangle = Rectangle.Inflate (content_rect, -4, -4); + imageRectangle = Rectangle.Empty; + + bool displayEllipsis = (button.TextFormatFlags & (TextFormatFlags.EndEllipsis | TextFormatFlags.PathEllipsis | TextFormatFlags.WordEllipsis)) != 0; + + switch (button.TextImageRelation) { + case TextImageRelation.Overlay: + // Overlay is easy, text always goes here + + // Image is dependent on ImageAlign + if (image == null) { + if (button.Pressed) + textRectangle.Offset (1, 1); + return; + } + + int image_x = 0; + int image_y = 0; + int image_height = image.Height; + int image_width = image.Width; + + switch (button.ImageAlign) { + case System.Drawing.ContentAlignment.TopLeft: + image_x = 5; + image_y = 5; + break; + case System.Drawing.ContentAlignment.TopCenter: + image_x = (content_rect.Width - image_width) / 2; + image_y = 5; + break; + case System.Drawing.ContentAlignment.TopRight: + image_x = content_rect.Width - image_width - 5; + image_y = 5; + break; + case System.Drawing.ContentAlignment.MiddleLeft: + image_x = 5; + image_y = (content_rect.Height - image_height) / 2; + break; + case System.Drawing.ContentAlignment.MiddleCenter: + image_x = (content_rect.Width - image_width) / 2; + image_y = (content_rect.Height - image_height) / 2; + break; + case System.Drawing.ContentAlignment.MiddleRight: + image_x = content_rect.Width - image_width - 4; + image_y = (content_rect.Height - image_height) / 2; + break; + case System.Drawing.ContentAlignment.BottomLeft: + image_x = 5; + image_y = content_rect.Height - image_height - 4; + break; + case System.Drawing.ContentAlignment.BottomCenter: + image_x = (content_rect.Width - image_width) / 2; + image_y = content_rect.Height - image_height - 4; + break; + case System.Drawing.ContentAlignment.BottomRight: + image_x = content_rect.Width - image_width - 4; + image_y = content_rect.Height - image_height - 4; + break; + default: + image_x = 5; + image_y = 5; + break; + } + + imageRectangle = new Rectangle (image_x, image_y, image_width, image_height); + break; + case TextImageRelation.ImageAboveText: + LayoutTextAboveOrBelowImage (textRectangle, false, text_size, image_size, button.TextAlign, button.ImageAlign, displayEllipsis, out textRectangle, out imageRectangle); + break; + case TextImageRelation.TextAboveImage: + LayoutTextAboveOrBelowImage (textRectangle, true, text_size, image_size, button.TextAlign, button.ImageAlign, displayEllipsis, out textRectangle, out imageRectangle); + break; + case TextImageRelation.ImageBeforeText: + LayoutTextBeforeOrAfterImage (textRectangle, false, text_size, image_size, button.TextAlign, button.ImageAlign, out textRectangle, out imageRectangle); + break; + case TextImageRelation.TextBeforeImage: + LayoutTextBeforeOrAfterImage (textRectangle, true, text_size, image_size, button.TextAlign, button.ImageAlign, out textRectangle, out imageRectangle); + break; + } + if (button.Pressed) + textRectangle.Offset (1, 1); + } + + private void LayoutTextBeforeOrAfterImage (Rectangle totalArea, bool textFirst, Size textSize, Size imageSize, System.Drawing.ContentAlignment textAlign, System.Drawing.ContentAlignment imageAlign, out Rectangle textRect, out Rectangle imageRect) + { + int element_spacing = 0; // Spacing between the Text and the Image + int total_width = textSize.Width + element_spacing + imageSize.Width; + + if (!textFirst) + element_spacing += 2; + + // If the text is too big, chop it down to the size we have available to it + if (total_width > totalArea.Width) { + textSize.Width = totalArea.Width - element_spacing - imageSize.Width; + total_width = totalArea.Width; + } + + int excess_width = totalArea.Width - total_width; + int offset = 0; + + Rectangle final_text_rect; + Rectangle final_image_rect; + + HorizontalAlignment h_text = GetHorizontalAlignment (textAlign); + HorizontalAlignment h_image = GetHorizontalAlignment (imageAlign); + + if (h_image == HorizontalAlignment.Left) + offset = 0; + else if (h_image == HorizontalAlignment.Right && h_text == HorizontalAlignment.Right) + offset = excess_width; + else if (h_image == HorizontalAlignment.Center && (h_text == HorizontalAlignment.Left || h_text == HorizontalAlignment.Center)) + offset += (int)(excess_width / 3); + else + offset += (int)(2 * (excess_width / 3)); + + if (textFirst) { + final_text_rect = new Rectangle (totalArea.Left + offset, AlignInRectangle (totalArea, textSize, textAlign).Top, textSize.Width, textSize.Height); + final_image_rect = new Rectangle (final_text_rect.Right + element_spacing, AlignInRectangle (totalArea, imageSize, imageAlign).Top, imageSize.Width, imageSize.Height); + } + else { + final_image_rect = new Rectangle (totalArea.Left + offset, AlignInRectangle (totalArea, imageSize, imageAlign).Top, imageSize.Width, imageSize.Height); + final_text_rect = new Rectangle (final_image_rect.Right + element_spacing, AlignInRectangle (totalArea, textSize, textAlign).Top, textSize.Width, textSize.Height); + } + + textRect = final_text_rect; + imageRect = final_image_rect; + } + + private void LayoutTextAboveOrBelowImage (Rectangle totalArea, bool textFirst, Size textSize, Size imageSize, System.Drawing.ContentAlignment textAlign, System.Drawing.ContentAlignment imageAlign, bool displayEllipsis, out Rectangle textRect, out Rectangle imageRect) + { + int element_spacing = 0; // Spacing between the Text and the Image + int total_height = textSize.Height + element_spacing + imageSize.Height; + + if (textFirst) + element_spacing += 2; + + if (textSize.Width > totalArea.Width) + textSize.Width = totalArea.Width; + + // If the there isn't enough room and we're text first, cut out the image + if (total_height > totalArea.Height && textFirst) { + imageSize = Size.Empty; + total_height = totalArea.Height; + } + + int excess_height = totalArea.Height - total_height; + int offset = 0; + + Rectangle final_text_rect; + Rectangle final_image_rect; + + VerticalAlignment v_text = GetVerticalAlignment (textAlign); + VerticalAlignment v_image = GetVerticalAlignment (imageAlign); + + if (v_image == VerticalAlignment.Top) + offset = 0; + else if (v_image == VerticalAlignment.Bottom && v_text == VerticalAlignment.Bottom) + offset = excess_height; + else if (v_image == VerticalAlignment.Center && (v_text == VerticalAlignment.Top || v_text == VerticalAlignment.Center)) + offset += (int)(excess_height / 3); + else + offset += (int)(2 * (excess_height / 3)); + + if (textFirst) { + var textHeight = excess_height >= 0 ? totalArea.Height - imageSize.Height - element_spacing: textSize.Height; + final_text_rect = new Rectangle (AlignInRectangle (totalArea, textSize, textAlign).Left, totalArea.Top + offset, textSize.Width, textHeight); + final_image_rect = new Rectangle (AlignInRectangle (totalArea, imageSize, imageAlign).Left, final_text_rect.Bottom + element_spacing, imageSize.Width, imageSize.Height); + } + else { + final_image_rect = new Rectangle (AlignInRectangle (totalArea, imageSize, imageAlign).Left, totalArea.Top + offset, imageSize.Width, imageSize.Height); + var textHeight = excess_height >= 0 ? totalArea.Height - final_image_rect.Height : textSize.Height; + final_text_rect = new Rectangle (AlignInRectangle (totalArea, textSize, textAlign).Left, final_image_rect.Bottom + element_spacing, textSize.Width, textHeight); + + if (final_text_rect.Bottom > totalArea.Bottom) { + final_text_rect.Y -= (final_text_rect.Bottom - totalArea.Bottom); + if (final_text_rect.Y < totalArea.Top) + final_text_rect.Y = totalArea.Top; + } + } + + if (displayEllipsis) { + // Don't use more space than is available otherwise ellipsis won't show + if (final_text_rect.Height > totalArea.Bottom) + final_text_rect.Height = totalArea.Bottom - final_text_rect.Top; + } + + textRect = final_text_rect; + imageRect = final_image_rect; + } + + private HorizontalAlignment GetHorizontalAlignment (System.Drawing.ContentAlignment align) + { + switch (align) { + case System.Drawing.ContentAlignment.BottomLeft: + case System.Drawing.ContentAlignment.MiddleLeft: + case System.Drawing.ContentAlignment.TopLeft: + return HorizontalAlignment.Left; + case System.Drawing.ContentAlignment.BottomCenter: + case System.Drawing.ContentAlignment.MiddleCenter: + case System.Drawing.ContentAlignment.TopCenter: + return HorizontalAlignment.Center; + case System.Drawing.ContentAlignment.BottomRight: + case System.Drawing.ContentAlignment.MiddleRight: + case System.Drawing.ContentAlignment.TopRight: + return HorizontalAlignment.Right; + } + + return HorizontalAlignment.Left; + } + + private enum VerticalAlignment + { + Top = 0, + Center = 1, + Bottom = 2 + } + + private VerticalAlignment GetVerticalAlignment (System.Drawing.ContentAlignment align) + { + switch (align) { + case System.Drawing.ContentAlignment.TopLeft: + case System.Drawing.ContentAlignment.TopCenter: + case System.Drawing.ContentAlignment.TopRight: + return VerticalAlignment.Top; + case System.Drawing.ContentAlignment.MiddleLeft: + case System.Drawing.ContentAlignment.MiddleCenter: + case System.Drawing.ContentAlignment.MiddleRight: + return VerticalAlignment.Center; + case System.Drawing.ContentAlignment.BottomLeft: + case System.Drawing.ContentAlignment.BottomCenter: + case System.Drawing.ContentAlignment.BottomRight: + return VerticalAlignment.Bottom; + } + + return VerticalAlignment.Top; + } + + internal Rectangle AlignInRectangle (Rectangle outer, Size inner, System.Drawing.ContentAlignment align) + { + int x = 0; + int y = 0; + + if (align == System.Drawing.ContentAlignment.BottomLeft || align == System.Drawing.ContentAlignment.MiddleLeft || align == System.Drawing.ContentAlignment.TopLeft) + x = outer.X; + else if (align == System.Drawing.ContentAlignment.BottomCenter || align == System.Drawing.ContentAlignment.MiddleCenter || align == System.Drawing.ContentAlignment.TopCenter) + x = Math.Max (outer.X + ((outer.Width - inner.Width) / 2), outer.Left); + else if (align == System.Drawing.ContentAlignment.BottomRight || align == System.Drawing.ContentAlignment.MiddleRight || align == System.Drawing.ContentAlignment.TopRight) + x = outer.Right - inner.Width; + if (align == System.Drawing.ContentAlignment.TopCenter || align == System.Drawing.ContentAlignment.TopLeft || align == System.Drawing.ContentAlignment.TopRight) + y = outer.Y; + else if (align == System.Drawing.ContentAlignment.MiddleCenter || align == System.Drawing.ContentAlignment.MiddleLeft || align == System.Drawing.ContentAlignment.MiddleRight) + y = outer.Y + (outer.Height - inner.Height) / 2; + else if (align == System.Drawing.ContentAlignment.BottomCenter || align == System.Drawing.ContentAlignment.BottomRight || align == System.Drawing.ContentAlignment.BottomLeft) + y = outer.Bottom - inner.Height; + + return new Rectangle (x, y, Math.Min (inner.Width, outer.Width), Math.Min (inner.Height, outer.Height)); + } + #endregion + #endregion + + #region ButtonBase + public override void DrawButtonBase(Graphics dc, Rectangle clip_area, ButtonBase button) + { + // Draw the button: Draw border, etc. + ButtonBase_DrawButton(button, dc); + + // Draw the image + if (button.FlatStyle != FlatStyle.System && ((button.image != null) || (button.image_list != null))) + ButtonBase_DrawImage(button, dc); + + // Draw the focus rectangle + if (ShouldPaintFocusRectagle (button)) + ButtonBase_DrawFocus(button, dc); + + // Now the text + if (button.Text != null && button.Text != String.Empty) + ButtonBase_DrawText(button, dc); + } + + protected static bool ShouldPaintFocusRectagle (ButtonBase button) + { + return (button.Focused || button.paint_as_acceptbutton) && button.Enabled && button.ShowFocusCues; + } + + protected virtual void ButtonBase_DrawButton (ButtonBase button, Graphics dc) + { + Rectangle borderRectangle; + bool check_or_radio = false; + bool check_or_radio_checked = false; + + bool is_ColorControl = button.BackColor.ToArgb () == ColorControl.ToArgb () ? true : false; + + CPColor cpcolor = is_ColorControl ? CPColor.Empty : ResPool.GetCPColor (button.BackColor); + + if (button is CheckBox) { + check_or_radio = true; + check_or_radio_checked = ((CheckBox)button).Checked; + } else if (button is RadioButton) { + check_or_radio = true; + check_or_radio_checked = ((RadioButton)button).Checked; + } + + if (button.Focused && button.Enabled && !check_or_radio) { + // shrink the rectangle for the normal button drawing inside the focus rectangle + borderRectangle = Rectangle.Inflate (button.ClientRectangle, -1, -1); + } else { + borderRectangle = button.ClientRectangle; + } + + if (button.FlatStyle == FlatStyle.Popup) { + if (!button.is_pressed && !button.is_entered && !check_or_radio_checked) + Internal_DrawButton (dc, borderRectangle, 1, cpcolor, is_ColorControl, button.BackColor); + else if (!button.is_pressed && button.is_entered &&!check_or_radio_checked) + Internal_DrawButton (dc, borderRectangle, 2, cpcolor, is_ColorControl, button.BackColor); + else if (button.is_pressed || check_or_radio_checked) + Internal_DrawButton (dc, borderRectangle, 1, cpcolor, is_ColorControl, button.BackColor); + } else if (button.FlatStyle == FlatStyle.Flat) { + if (button.is_entered && !button.is_pressed && !check_or_radio_checked) { + if ((button.image == null) && (button.image_list == null)) { + Brush brush = is_ColorControl ? SystemBrushes.ControlDark : ResPool.GetSolidBrush (cpcolor.Dark); + dc.FillRectangle (brush, borderRectangle); + } + } else if (button.is_pressed || check_or_radio_checked) { + if ((button.image == null) && (button.image_list == null)) { + Brush brush = is_ColorControl ? SystemBrushes.ControlLightLight : ResPool.GetSolidBrush (cpcolor.LightLight); + dc.FillRectangle (brush, borderRectangle); + } + + Pen pen = is_ColorControl ? SystemPens.ControlDark : ResPool.GetPen (cpcolor.Dark); + dc.DrawRectangle (pen, borderRectangle.X + 4, borderRectangle.Y + 4, + borderRectangle.Width - 9, borderRectangle.Height - 9); + } + + Internal_DrawButton (dc, borderRectangle, 3, cpcolor, is_ColorControl, button.BackColor); + } else { + if ((!button.is_pressed || !button.Enabled) && !check_or_radio_checked) + Internal_DrawButton (dc, borderRectangle, 0, cpcolor, is_ColorControl, button.BackColor); + else + Internal_DrawButton (dc, borderRectangle, 1, cpcolor, is_ColorControl, button.BackColor); + } + } + + private void Internal_DrawButton (Graphics dc, Rectangle rect, int state, CPColor cpcolor, bool is_ColorControl, Color backcolor) + { + switch (state) { + case 0: // normal or normal disabled button + Pen pen = is_ColorControl ? SystemPens.ControlLightLight : ResPool.GetPen (cpcolor.LightLight); + dc.DrawLine (pen, rect.X, rect.Y, rect.X, rect.Bottom - 2); + dc.DrawLine (pen, rect.X + 1, rect.Y, rect.Right - 2, rect.Y); + + pen = is_ColorControl ? SystemPens.Control : ResPool.GetPen (backcolor); + dc.DrawLine (pen, rect.X + 1, rect.Y + 1, rect.X + 1, rect.Bottom - 3); + dc.DrawLine (pen, rect.X + 2, rect.Y + 1, rect.Right - 3, rect.Y + 1); + + pen = is_ColorControl ? SystemPens.ControlDark : ResPool.GetPen (cpcolor.Dark); + dc.DrawLine (pen, rect.X + 1, rect.Bottom - 2, rect.Right - 2, rect.Bottom - 2); + dc.DrawLine (pen, rect.Right - 2, rect.Y + 1, rect.Right - 2, rect.Bottom - 3); + + pen = is_ColorControl ? SystemPens.ControlDarkDark : ResPool.GetPen (cpcolor.DarkDark); + dc.DrawLine (pen, rect.X, rect.Bottom - 1, rect.Right - 1, rect.Bottom - 1); + dc.DrawLine (pen, rect.Right - 1, rect.Y, rect.Right - 1, rect.Bottom - 2); + break; + case 1: // popup button normal (or pressed normal or popup button) + pen = is_ColorControl ? SystemPens.ControlDark : ResPool.GetPen (cpcolor.Dark); + dc.DrawRectangle (pen, rect.X, rect.Y, rect.Width - 1, rect.Height - 1); + break; + case 2: // popup button poped up + pen = is_ColorControl ? SystemPens.ControlLightLight : ResPool.GetPen (cpcolor.LightLight); + dc.DrawLine (pen, rect.X, rect.Y, rect.X, rect.Bottom - 2); + dc.DrawLine (pen, rect.X + 1, rect.Y, rect.Right - 2, rect.Y); + + pen = is_ColorControl ? SystemPens.ControlDark : ResPool.GetPen (cpcolor.Dark); + dc.DrawLine (pen, rect.X, rect.Bottom - 1, rect.Right - 1, rect.Bottom - 1); + dc.DrawLine (pen, rect.Right - 1, rect.Y, rect.Right - 1, rect.Bottom - 2); + break; + case 3: // flat button not entered + pen = is_ColorControl ? SystemPens.ControlDarkDark : ResPool.GetPen (cpcolor.DarkDark); + dc.DrawRectangle (pen, rect.X, rect.Y, rect.Width - 1, rect.Height - 1); + break; + default: + break; + } + } + + protected virtual void ButtonBase_DrawImage(ButtonBase button, Graphics dc) + { + // Need to draw a picture + Image i; + int image_x; + int image_y; + int image_width; + int image_height; + + int width = button.ClientSize.Width; + int height = button.ClientSize.Height; + + if (button.ImageIndex != -1) { // We use ImageIndex instead of image_index since it will return -1 if image_list is null + i = button.image_list.Images[button.ImageIndex]; + } else { + i = button.image; + } + + image_width = i.Width; + image_height = i.Height; + + switch (button.ImageAlign) { + case ContentAlignment.TopLeft: { + image_x = 5; + image_y = 5; + break; + } + + case ContentAlignment.TopCenter: { + image_x = (width - image_width) / 2; + image_y = 5; + break; + } + + case ContentAlignment.TopRight: { + image_x = width - image_width - 5; + image_y = 5; + break; + } + + case ContentAlignment.MiddleLeft: { + image_x = 5; + image_y = (height - image_height) / 2; + break; + } + + case ContentAlignment.MiddleCenter: { + image_x = (width - image_width) / 2; + image_y = (height - image_height) / 2; + break; + } + + case ContentAlignment.MiddleRight: { + image_x = width - image_width - 4; + image_y = (height - image_height) / 2; + break; + } + + case ContentAlignment.BottomLeft: { + image_x = 5; + image_y = height - image_height - 4; + break; + } + + case ContentAlignment.BottomCenter: { + image_x = (width - image_width) / 2; + image_y = height - image_height - 4; + break; + } + + case ContentAlignment.BottomRight: { + image_x = width - image_width - 4; + image_y = height - image_height - 4; + break; + } + + default: { + image_x = 5; + image_y = 5; + break; + } + } + + dc.SetClip (new Rectangle(3, 3, width - 5, height - 5)); + + if (button.Enabled) + dc.DrawImage (i, image_x, image_y, image_width, image_height); + else + CPDrawImageDisabled (dc, i, image_x, image_y, ColorControl); + + dc.ResetClip (); + } + + protected virtual void ButtonBase_DrawFocus(ButtonBase button, Graphics dc) + { + Color focus_color = button.ForeColor; + + int inflate_value = -3; + + if (!(button is CheckBox) && !(button is RadioButton)) { + inflate_value = -4; + + if (button.FlatStyle == FlatStyle.Popup && !button.is_pressed) + focus_color = WidgetPaint.Dark(button.BackColor); + + dc.DrawRectangle (ResPool.GetPen (focus_color), button.ClientRectangle.X, button.ClientRectangle.Y, + button.ClientRectangle.Width - 1, button.ClientRectangle.Height - 1); + } + + if (button.Focused) { + Rectangle rect = Rectangle.Inflate (button.ClientRectangle, inflate_value, inflate_value); + WidgetPaint.DrawFocusRectangle (dc, rect); + } + } + + protected virtual void ButtonBase_DrawText(ButtonBase button, Graphics dc) + { + Rectangle buttonRectangle = button.ClientRectangle; + Rectangle text_rect = Rectangle.Inflate(buttonRectangle, -4, -4); + + if (button.is_pressed) { + text_rect.X++; + text_rect.Y++; + } + + // Ensure that at least one line is going to get displayed. + // Line limit does not ensure that despite its description. + text_rect.Height = Math.Max (button.Font.Height, text_rect.Height); + + if (button.Enabled) { + dc.DrawString(button.Text, button.Font, ResPool.GetSolidBrush (button.ForeColor), text_rect, button.text_format); + } else { + if (button.FlatStyle == FlatStyle.Flat || button.FlatStyle == FlatStyle.Popup) { + dc.DrawString(button.Text, button.Font, ResPool.GetSolidBrush (ColorGrayText), text_rect, button.text_format); + } else { + CPDrawStringDisabled (dc, button.Text, button.Font, button.BackColor, text_rect, button.text_format); + } + } + } + + public override Size ButtonBaseDefaultSize { + get { + return new Size (75, 23); + } + } + #endregion // ButtonBase + + #region CheckBox + public override void DrawCheckBox (Graphics g, CheckBox cb, Rectangle glyphArea, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle) + { + // Draw Button Background + if (cb.Appearance == Appearance.Button && cb.FlatStyle != FlatStyle.Flat) + ButtonBase_DrawButton (cb, g); + else if (cb.Appearance != Appearance.Button) + DrawCheckBoxGlyph (g, cb, glyphArea); + + // Draw the borders and such for a Flat CheckBox Button + if (cb.Appearance == Appearance.Button && cb.FlatStyle == FlatStyle.Flat) + DrawFlatButton (g, cb, textBounds, imageBounds, clipRectangle); + + // If we have an image, draw it + if (imageBounds.Size != Size.Empty) + DrawCheckBoxImage (g, cb, imageBounds); + + if (cb.Focused && cb.Enabled && cb.ShowFocusCues && textBounds != Rectangle.Empty) + DrawCheckBoxFocus (g, cb, textBounds); + + // If we have text, draw it + if (textBounds != Rectangle.Empty) + DrawCheckBoxText (g, cb, textBounds); + } + + public virtual void DrawCheckBoxGlyph (Graphics g, CheckBox cb, Rectangle glyphArea) + { + if (cb.Pressed) + ThemeElements.CurrentTheme.CheckBoxPainter.PaintCheckBox (g, glyphArea, cb.BackColor, cb.ForeColor, ElementState.Pressed, cb.FlatStyle, cb.CheckState); + else if (cb.InternalSelected) + ThemeElements.CurrentTheme.CheckBoxPainter.PaintCheckBox (g, glyphArea, cb.BackColor, cb.ForeColor, ElementState.Normal, cb.FlatStyle, cb.CheckState); + else if (cb.Entered) + ThemeElements.CurrentTheme.CheckBoxPainter.PaintCheckBox (g, glyphArea, cb.BackColor, cb.ForeColor, ElementState.Hot, cb.FlatStyle, cb.CheckState); + else if (!cb.Enabled) + ThemeElements.CurrentTheme.CheckBoxPainter.PaintCheckBox (g, glyphArea, cb.BackColor, cb.ForeColor, ElementState.Disabled, cb.FlatStyle, cb.CheckState); + else + ThemeElements.CurrentTheme.CheckBoxPainter.PaintCheckBox (g, glyphArea, cb.BackColor, cb.ForeColor, ElementState.Normal, cb.FlatStyle, cb.CheckState); + } + + public virtual void DrawCheckBoxFocus (Graphics g, CheckBox cb, Rectangle focusArea) + { + WidgetPaint.DrawFocusRectangle (g, focusArea); + } + + public virtual void DrawCheckBoxImage (Graphics g, CheckBox cb, Rectangle imageBounds) + { + if (cb.Enabled) + g.DrawImage (cb.Image, imageBounds); + else + CPDrawImageDisabled (g, cb.Image, imageBounds.Left, imageBounds.Top, ColorControl); + } + + public virtual void DrawCheckBoxText (Graphics g, CheckBox cb, Rectangle textBounds) + { + if (cb.Enabled) + TextRenderer.DrawTextInternal (g, cb.Text, cb.Font, textBounds, cb.ForeColor, cb.TextFormatFlags, cb.UseCompatibleTextRendering); + else + DrawStringDisabled20 (g, cb.Text, cb.Font, textBounds, cb.BackColor, cb.TextFormatFlags, cb.UseCompatibleTextRendering); + } + + public override void CalculateCheckBoxTextAndImageLayout (ButtonBase button, Point p, out Rectangle glyphArea, out Rectangle textRectangle, out Rectangle imageRectangle) + { + int check_size = CheckSize; + + if (button is CheckBox) + check_size = (button as CheckBox).Appearance == Appearance.Normal ? check_size : 0; + + glyphArea = new Rectangle (button.Padding.Left, button.Padding.Top, check_size, check_size); + + Rectangle content_rect = button.PaddingClientRectangle; + ContentAlignment align = ContentAlignment.TopLeft; + + if (button is CheckBox) + align = (button as CheckBox).CheckAlign; + else if (button is RadioButton) + align = (button as RadioButton).CheckAlign; + + switch (align) { + case ContentAlignment.BottomCenter: + glyphArea.Y += content_rect.Height - check_size - 2; + glyphArea.X += (content_rect.Width - check_size) / 2; + break; + case ContentAlignment.BottomLeft: + glyphArea.Y += content_rect.Height - check_size - 2; + content_rect.Width -= check_size; + content_rect.Offset (check_size, 0); + break; + case ContentAlignment.BottomRight: + glyphArea.Y += content_rect.Height - check_size - 2; + glyphArea.X += content_rect.Width - check_size; + content_rect.Width -= check_size; + break; + case ContentAlignment.MiddleCenter: + glyphArea.Y += (content_rect.Height - check_size) / 2; + glyphArea.X += (content_rect.Width - check_size) / 2; + break; + case ContentAlignment.MiddleLeft: + glyphArea.Y += (content_rect.Height - check_size) / 2; + content_rect.Width -= check_size; + content_rect.Offset (check_size, 0); + break; + case ContentAlignment.MiddleRight: + glyphArea.Y += (content_rect.Height - check_size) / 2; + glyphArea.X += content_rect.Width - check_size; + content_rect.Width -= check_size; + break; + case ContentAlignment.TopCenter: + glyphArea.X += (content_rect.Width - check_size) / 2; + break; + case ContentAlignment.TopLeft: + content_rect.Width -= check_size; + content_rect.Offset (check_size, 0); + break; + case ContentAlignment.TopRight: + glyphArea.X += content_rect.Width - check_size; + content_rect.Width -= check_size; + break; + } + + Image image = button.Image; + string text = button.Text; + + Size proposed = Size.Empty; + + // Force wrapping if we aren't AutoSize and our text is too long + if (!button.AutoSize) + proposed.Width = button.PaddingClientRectangle.Width - glyphArea.Width - 2; + + Size text_size = TextRenderer.MeasureTextInternal (text, button.Font, proposed, button.TextFormatFlags, button.UseCompatibleTextRendering); + + // Text can't be bigger than the content rectangle + text_size.Height = Math.Min (text_size.Height, content_rect.Height); + text_size.Width = Math.Min (text_size.Width, content_rect.Width); + + Size image_size = image == null ? Size.Empty : image.Size; + + textRectangle = Rectangle.Empty; + imageRectangle = Rectangle.Empty; + + switch (button.TextImageRelation) { + case TextImageRelation.Overlay: + // Text is centered vertically, and 2 pixels to the right + textRectangle.X = content_rect.Left + 2; + textRectangle.Y = button.PaddingClientRectangle.Top + ((content_rect.Height - text_size.Height) / 2) - 1; + textRectangle.Size = text_size; + + // Image is dependent on ImageAlign + if (image == null) + return; + + int image_x = button.PaddingClientRectangle.Left; + int image_y = button.PaddingClientRectangle.Top; + int image_height = image.Height; + int image_width = image.Width; + + switch (button.ImageAlign) { + case System.Drawing.ContentAlignment.TopLeft: + image_x += 5; + image_y += 5; + break; + case System.Drawing.ContentAlignment.TopCenter: + image_x += (content_rect.Width - image_width) / 2; + image_y += 5; + break; + case System.Drawing.ContentAlignment.TopRight: + image_x += content_rect.Width - image_width - 5; + image_y += 5; + break; + case System.Drawing.ContentAlignment.MiddleLeft: + image_x += 5; + image_y += (content_rect.Height - image_height) / 2; + break; + case System.Drawing.ContentAlignment.MiddleCenter: + image_x += (content_rect.Width - image_width) / 2; + image_y += (content_rect.Height - image_height) / 2; + break; + case System.Drawing.ContentAlignment.MiddleRight: + image_x += content_rect.Width - image_width - 4; + image_y += (content_rect.Height - image_height) / 2; + break; + case System.Drawing.ContentAlignment.BottomLeft: + image_x += 5; + image_y += content_rect.Height - image_height - 4; + break; + case System.Drawing.ContentAlignment.BottomCenter: + image_x += (content_rect.Width - image_width) / 2; + image_y += content_rect.Height - image_height - 4; + break; + case System.Drawing.ContentAlignment.BottomRight: + image_x += content_rect.Width - image_width - 4; + image_y += content_rect.Height - image_height - 4; + break; + default: + image_x += 5; + image_y += 5; + break; + } + + imageRectangle = new Rectangle (image_x + check_size, image_y, image_width, image_height); + break; + case TextImageRelation.ImageAboveText: + content_rect.Inflate (-4, -4); + LayoutTextAboveOrBelowImage (content_rect, false, text_size, image_size, button.TextAlign, button.ImageAlign, false, out textRectangle, out imageRectangle); + break; + case TextImageRelation.TextAboveImage: + content_rect.Inflate (-4, -4); + LayoutTextAboveOrBelowImage (content_rect, true, text_size, image_size, button.TextAlign, button.ImageAlign, false, out textRectangle, out imageRectangle); + break; + case TextImageRelation.ImageBeforeText: + content_rect.Inflate (-4, -4); + LayoutTextBeforeOrAfterImage (content_rect, false, text_size, image_size, button.TextAlign, button.ImageAlign, out textRectangle, out imageRectangle); + break; + case TextImageRelation.TextBeforeImage: + content_rect.Inflate (-4, -4); + LayoutTextBeforeOrAfterImage (content_rect, true, text_size, image_size, button.TextAlign, button.ImageAlign, out textRectangle, out imageRectangle); + break; + } + } + + public override Size CalculateCheckBoxAutoSize (CheckBox checkBox) + { + Size ret_size = Size.Empty; + Size text_size = TextRenderer.MeasureTextInternal (checkBox.Text, checkBox.Font, checkBox.UseCompatibleTextRendering); + Size image_size = checkBox.Image == null ? Size.Empty : checkBox.Image.Size; + + // Pad the text size + if (checkBox.Text.Length != 0) { + text_size.Height += 4; + text_size.Width += 4; + } + + switch (checkBox.TextImageRelation) { + case TextImageRelation.Overlay: + ret_size.Height = Math.Max (checkBox.Text.Length == 0 ? 0 : text_size.Height, image_size.Height); + ret_size.Width = Math.Max (text_size.Width, image_size.Width); + break; + case TextImageRelation.ImageAboveText: + case TextImageRelation.TextAboveImage: + ret_size.Height = text_size.Height + image_size.Height; + ret_size.Width = Math.Max (text_size.Width, image_size.Width); + break; + case TextImageRelation.ImageBeforeText: + case TextImageRelation.TextBeforeImage: + ret_size.Height = Math.Max (text_size.Height, image_size.Height); + ret_size.Width = text_size.Width + image_size.Width; + break; + } + + // Pad the result + ret_size.Height += (checkBox.Padding.Vertical); + ret_size.Width += (checkBox.Padding.Horizontal) + 15; + + // There seems to be a minimum height + if (ret_size.Height == checkBox.Padding.Vertical) + ret_size.Height += 14; + + return ret_size; + } + + public override void DrawCheckBox(Graphics dc, Rectangle clip_area, CheckBox checkbox) { + StringFormat text_format; + Rectangle client_rectangle; + Rectangle text_rectangle; + Rectangle checkbox_rectangle; + int checkmark_size = CheckSize; + int checkmark_space = 4; + + client_rectangle = checkbox.ClientRectangle; + text_rectangle = client_rectangle; + checkbox_rectangle = new Rectangle(text_rectangle.X, text_rectangle.Y, checkmark_size, checkmark_size); + + text_format = new StringFormat(); + text_format.Alignment = StringAlignment.Near; + text_format.LineAlignment = StringAlignment.Center; + if (checkbox.ShowKeyboardCuesInternal) + text_format.HotkeyPrefix = HotkeyPrefix.Show; + else + text_format.HotkeyPrefix = HotkeyPrefix.Hide; + + /* Calculate the position of text and checkbox rectangle */ + if (checkbox.appearance!=Appearance.Button) { + switch(checkbox.check_alignment) { + case ContentAlignment.BottomCenter: { + checkbox_rectangle.X=(client_rectangle.Right-client_rectangle.Left)/2-checkmark_size/2; + checkbox_rectangle.Y=client_rectangle.Bottom-checkmark_size; + text_rectangle.X=client_rectangle.X; + text_rectangle.Width=client_rectangle.Width; + text_rectangle.Height=client_rectangle.Height-checkbox_rectangle.Y-checkmark_space; + break; + } + + case ContentAlignment.BottomLeft: { + checkbox_rectangle.X=client_rectangle.Left; + checkbox_rectangle.Y=client_rectangle.Bottom-checkmark_size; + text_rectangle.X=client_rectangle.X+checkmark_size+checkmark_space; + text_rectangle.Width=client_rectangle.Width-checkmark_size-checkmark_space; + break; + } + + case ContentAlignment.BottomRight: { + checkbox_rectangle.X=client_rectangle.Right-checkmark_size; + checkbox_rectangle.Y=client_rectangle.Bottom-checkmark_size; + text_rectangle.X=client_rectangle.X; + text_rectangle.Width=client_rectangle.Width-checkmark_size-checkmark_space; + break; + } + + case ContentAlignment.MiddleCenter: { + checkbox_rectangle.X=(client_rectangle.Right-client_rectangle.Left)/2-checkmark_size/2; + checkbox_rectangle.Y=(client_rectangle.Bottom-client_rectangle.Top)/2-checkmark_size/2; + text_rectangle.X=client_rectangle.X; + text_rectangle.Width=client_rectangle.Width; + break; + } + + default: + case ContentAlignment.MiddleLeft: { + checkbox_rectangle.X=client_rectangle.Left; + checkbox_rectangle.Y=(client_rectangle.Bottom-client_rectangle.Top)/2-checkmark_size/2; + text_rectangle.X=client_rectangle.X+checkmark_size+checkmark_space; + text_rectangle.Width=client_rectangle.Width-checkmark_size-checkmark_space; + break; + } + + case ContentAlignment.MiddleRight: { + checkbox_rectangle.X=client_rectangle.Right-checkmark_size; + checkbox_rectangle.Y=(client_rectangle.Bottom-client_rectangle.Top)/2-checkmark_size/2; + text_rectangle.X=client_rectangle.X; + text_rectangle.Width=client_rectangle.Width-checkmark_size-checkmark_space; + break; + } + + case ContentAlignment.TopCenter: { + checkbox_rectangle.X=(client_rectangle.Right-client_rectangle.Left)/2-checkmark_size/2; + checkbox_rectangle.Y=client_rectangle.Top; + text_rectangle.X=client_rectangle.X; + text_rectangle.Width=client_rectangle.Width; + text_rectangle.Y=checkmark_size+checkmark_space; + text_rectangle.Height=client_rectangle.Height-checkmark_size-checkmark_space; + break; + } + + case ContentAlignment.TopLeft: { + checkbox_rectangle.X=client_rectangle.Left; + text_rectangle.X=client_rectangle.X+checkmark_size+checkmark_space; + text_rectangle.Width=client_rectangle.Width-checkmark_size-checkmark_space; + break; + } + + case ContentAlignment.TopRight: { + checkbox_rectangle.X=client_rectangle.Right-checkmark_size; + text_rectangle.X=client_rectangle.X; + text_rectangle.Width=client_rectangle.Width-checkmark_size-checkmark_space; + break; + } + } + } else { + text_rectangle.X=client_rectangle.X; + text_rectangle.Width=client_rectangle.Width; + } + + /* Set the horizontal alignment of our text */ + switch(checkbox.text_alignment) { + case ContentAlignment.BottomLeft: + case ContentAlignment.MiddleLeft: + case ContentAlignment.TopLeft: { + text_format.Alignment=StringAlignment.Near; + break; + } + + case ContentAlignment.BottomCenter: + case ContentAlignment.MiddleCenter: + case ContentAlignment.TopCenter: { + text_format.Alignment=StringAlignment.Center; + break; + } + + case ContentAlignment.BottomRight: + case ContentAlignment.MiddleRight: + case ContentAlignment.TopRight: { + text_format.Alignment=StringAlignment.Far; + break; + } + } + + /* Set the vertical alignment of our text */ + switch(checkbox.text_alignment) { + case ContentAlignment.TopLeft: + case ContentAlignment.TopCenter: + case ContentAlignment.TopRight: { + text_format.LineAlignment=StringAlignment.Near; + break; + } + + case ContentAlignment.BottomLeft: + case ContentAlignment.BottomCenter: + case ContentAlignment.BottomRight: { + text_format.LineAlignment=StringAlignment.Far; + break; + } + + case ContentAlignment.MiddleLeft: + case ContentAlignment.MiddleCenter: + case ContentAlignment.MiddleRight: { + text_format.LineAlignment=StringAlignment.Center; + break; + } + } + + ButtonState state = ButtonState.Normal; + if (checkbox.FlatStyle == FlatStyle.Flat) { + state |= ButtonState.Flat; + } + + if (checkbox.Checked) { + state |= ButtonState.Checked; + } + + if (checkbox.ThreeState && (checkbox.CheckState == CheckState.Indeterminate)) { + state |= ButtonState.Checked; + state |= ButtonState.Pushed; + } + + // finally make sure the pushed and inavtive states are rendered + if (!checkbox.Enabled) { + state |= ButtonState.Inactive; + } + else if (checkbox.is_pressed) { + state |= ButtonState.Pushed; + } + + // Start drawing + + CheckBox_DrawCheckBox(dc, checkbox, state, checkbox_rectangle); + + if ((checkbox.image != null) || (checkbox.image_list != null)) + ButtonBase_DrawImage(checkbox, dc); + + CheckBox_DrawText(checkbox, text_rectangle, dc, text_format); + + if (checkbox.Focused && checkbox.Enabled && checkbox.appearance != Appearance.Button && checkbox.Text != String.Empty && checkbox.ShowFocusCues) { + SizeF text_size = dc.MeasureString (checkbox.Text, checkbox.Font); + + Rectangle focus_rect = Rectangle.Empty; + focus_rect.X = text_rectangle.X; + focus_rect.Y = (int)((text_rectangle.Height - text_size.Height) / 2); + focus_rect.Size = text_size.ToSize (); + CheckBox_DrawFocus (checkbox, dc, focus_rect); + } + + text_format.Dispose (); + } + + protected virtual void CheckBox_DrawCheckBox( Graphics dc, CheckBox checkbox, ButtonState state, Rectangle checkbox_rectangle ) + { + Brush brush = checkbox.BackColor.ToArgb () == ColorControl.ToArgb () ? SystemBrushes.Control : ResPool.GetSolidBrush (checkbox.BackColor); + dc.FillRectangle (brush, checkbox.ClientRectangle); + // render as per normal button + if (checkbox.appearance==Appearance.Button) { + ButtonBase_DrawButton (checkbox, dc); + + if ((checkbox.Focused) && checkbox.Enabled) + ButtonBase_DrawFocus(checkbox, dc); + } else { + // establish if we are rendering a flat style of some sort + if (checkbox.FlatStyle == FlatStyle.Flat || checkbox.FlatStyle == FlatStyle.Popup) { + DrawFlatStyleCheckBox (dc, checkbox_rectangle, checkbox); + } else { + CPDrawCheckBox (dc, checkbox_rectangle, state); + } + } + } + + protected virtual void CheckBox_DrawText( CheckBox checkbox, Rectangle text_rectangle, Graphics dc, StringFormat text_format ) + { + DrawCheckBox_and_RadioButtonText (checkbox, text_rectangle, dc, + text_format, checkbox.Appearance, checkbox.Checked); + } + + protected virtual void CheckBox_DrawFocus( CheckBox checkbox, Graphics dc, Rectangle text_rectangle ) + { + DrawInnerFocusRectangle (dc, text_rectangle, checkbox.BackColor); + } + + // renders a checkBox with the Flat and Popup FlatStyle + protected virtual void DrawFlatStyleCheckBox (Graphics graphics, Rectangle rectangle, CheckBox checkbox) + { + Pen pen; + Rectangle rect; + Rectangle checkbox_rectangle; + Rectangle fill_rectangle; + int lineWidth; + int Scale; + + // set up our rectangles first + if (checkbox.FlatStyle == FlatStyle.Popup && checkbox.is_entered) { + // clip one pixel from bottom right for non popup rendered checkboxes + checkbox_rectangle = new Rectangle(rectangle.X, rectangle.Y, Math.Max(rectangle.Width-1, 0), Math.Max(rectangle.Height-1,0)); + fill_rectangle = new Rectangle(checkbox_rectangle.X+1, checkbox_rectangle.Y+1, Math.Max(checkbox_rectangle.Width-3, 0), Math.Max(checkbox_rectangle.Height-3,0)); + } else { + // clip two pixels from bottom right for non popup rendered checkboxes + checkbox_rectangle = new Rectangle(rectangle.X, rectangle.Y, Math.Max(rectangle.Width-2, 0), Math.Max(rectangle.Height-2,0)); + fill_rectangle = new Rectangle(checkbox_rectangle.X+1, checkbox_rectangle.Y+1, Math.Max(checkbox_rectangle.Width-2, 0), Math.Max(checkbox_rectangle.Height-2,0)); + } + + + // if disabled render in disabled state + if (checkbox.Enabled) { + // process the state of the checkbox + if (checkbox.is_entered || checkbox.Capture) { + // decide on which background color to use + if (checkbox.FlatStyle == FlatStyle.Popup && checkbox.is_entered && checkbox.Capture) { + graphics.FillRectangle(ResPool.GetSolidBrush (checkbox.BackColor), fill_rectangle); + } else if (checkbox.FlatStyle == FlatStyle.Flat) { + if (!checkbox.is_pressed) { + graphics.FillRectangle(ResPool.GetSolidBrush (checkbox.BackColor), fill_rectangle); + } else + graphics.FillRectangle(ResPool.GetSolidBrush (WidgetPaint.LightLight (checkbox.BackColor)), fill_rectangle); + } else { + // use regular window background color + graphics.FillRectangle(ResPool.GetSolidBrush (WidgetPaint.LightLight (checkbox.BackColor)), fill_rectangle); + } + + // render the outer border + if (checkbox.FlatStyle == FlatStyle.Flat) { + WidgetPaint.DrawBorder(graphics, checkbox_rectangle, checkbox.ForeColor, ButtonBorderStyle.Solid); + } else { + // draw sunken effect + CPDrawBorder3D (graphics, checkbox_rectangle, Border3DStyle.SunkenInner, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom, checkbox.BackColor); + } + } else { + graphics.FillRectangle(ResPool.GetSolidBrush (WidgetPaint.LightLight (checkbox.BackColor)), fill_rectangle); + + if (checkbox.FlatStyle == FlatStyle.Flat) { + WidgetPaint.DrawBorder(graphics, checkbox_rectangle, checkbox.ForeColor, ButtonBorderStyle.Solid); + } else { + // draw the outer border + WidgetPaint.DrawBorder(graphics, checkbox_rectangle, WidgetPaint.DarkDark (checkbox.BackColor), ButtonBorderStyle.Solid); + } + } + } else { + if (checkbox.FlatStyle == FlatStyle.Popup) { + graphics.FillRectangle(SystemBrushes.Control, fill_rectangle); + } + + // draw disabled state, + WidgetPaint.DrawBorder(graphics, checkbox_rectangle, ColorControlDark, ButtonBorderStyle.Solid); + } + + if (checkbox.Checked) { + /* Need to draw a check-mark */ + + /* Make sure we've got at least a line width of 1 */ + lineWidth = Math.Max(3, fill_rectangle.Width/3); + Scale=Math.Max(1, fill_rectangle.Width/9); + + // flat style check box is rendered inside a rectangle shifted down by one + rect=new Rectangle(fill_rectangle.X, fill_rectangle.Y+1, fill_rectangle.Width, fill_rectangle.Height); + if (checkbox.Enabled) { + pen=ResPool.GetPen(checkbox.ForeColor); + } else { + pen=SystemPens.ControlDark; + } + + for (int i=0; i text_rectangle.Height) { + text_format.FormatFlags |= StringFormatFlags.NoWrap; + } + if (button_base.Enabled) { + dc.DrawString (button_base.Text, button_base.Font, ResPool.GetSolidBrush (button_base.ForeColor), text_rectangle, text_format); + } else if (button_base.FlatStyle == FlatStyle.Flat || button_base.FlatStyle == FlatStyle.Popup) { + dc.DrawString (button_base.Text, button_base.Font, SystemBrushes.ControlDarkDark, text_rectangle, text_format); + } else { + CPDrawStringDisabled (dc, button_base.Text, button_base.Font, button_base.BackColor, text_rectangle, text_format); + } + } + #endregion // CheckBox + + #region CheckedListBox + + public override void DrawCheckedListBoxItem (CheckedListBox ctrl, DrawItemEventArgs e) + { + Color back_color, fore_color; + Rectangle item_rect = e.Bounds; + ButtonState state; + + /* Draw checkbox */ + + if ((e.State & DrawItemState.Checked) == DrawItemState.Checked) { + state = ButtonState.Checked; + if ((e.State & DrawItemState.Inactive) == DrawItemState.Inactive) + state |= ButtonState.Inactive; + } else + state = ButtonState.Normal; + + if (ctrl.ThreeDCheckBoxes == false) + state |= ButtonState.Flat; + + Rectangle checkbox_rect = new Rectangle (2, (item_rect.Height - 11) / 2, CheckSize, CheckSize); + WidgetPaint.DrawCheckBox (e.Graphics, + item_rect.X + checkbox_rect.X, item_rect.Y + checkbox_rect.Y, + checkbox_rect.Width, checkbox_rect.Height, + state); + + item_rect.X += checkbox_rect.Right; + item_rect.Width -= checkbox_rect.Right; + + /* Draw text*/ + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) { + back_color = ColorHighlight; + fore_color = ColorHighlightText; + } + else { + back_color = e.BackColor; + fore_color = e.ForeColor; + } + + e.Graphics.FillRectangle (ResPool.GetSolidBrush + (back_color), item_rect); + + e.Graphics.DrawString (ctrl.GetItemText (ctrl.Items[e.Index]), e.Font, + ResPool.GetSolidBrush (fore_color), + item_rect, ctrl.StringFormat); + + if ((e.State & DrawItemState.Focus) == DrawItemState.Focus) { + CPDrawFocusRectangle (e.Graphics, item_rect, + fore_color, back_color); + } + } + + #endregion // CheckedListBox + + #region ComboBox + public override void DrawComboBoxItem (ComboBox ctrl, DrawItemEventArgs e) + { + Color back_color, fore_color; + Rectangle text_draw = e.Bounds; + StringFormat string_format = new StringFormat (); + string_format.FormatFlags = StringFormatFlags.LineLimit; + + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) { + back_color = ColorHighlight; + fore_color = ColorHighlightText; + } + else { + back_color = e.BackColor; + fore_color = e.ForeColor; + } + + if (!ctrl.Enabled) + fore_color = ColorInactiveCaptionText; + + e.Graphics.FillRectangle (ResPool.GetSolidBrush (back_color), e.Bounds); + + if (e.Index != -1) { + e.Graphics.DrawString (ctrl.GetItemText (ctrl.Items[e.Index]), e.Font, + ResPool.GetSolidBrush (fore_color), + text_draw, string_format); + } + + if ((e.State & DrawItemState.Focus) == DrawItemState.Focus) { + CPDrawFocusRectangle (e.Graphics, e.Bounds, fore_color, back_color); + } + + string_format.Dispose (); + } + + public override void DrawFlatStyleComboButton (Graphics graphics, Rectangle rectangle, ButtonState state) + { + Point[] arrow = new Point[3]; + Point P1; + Point P2; + Point P3; + int centerX; + int centerY; + int shiftX; + int shiftY; + Rectangle rect; + + rect=new Rectangle(rectangle.X+rectangle.Width/4, rectangle.Y+rectangle.Height/4, rectangle.Width/2, rectangle.Height/2); + centerX=rect.Left+rect.Width/2; + centerY=rect.Top+rect.Height/2; + shiftX=Math.Max(1, rect.Width/8); + shiftY=Math.Max(1, rect.Height/8); + + if ((state & ButtonState.Pushed)!=0) { + shiftX++; + shiftY++; + } + + rect.Y-=shiftY; + centerY-=shiftY; + P1=new Point(rect.Left + 1, centerY); + P2=new Point(rect.Right - 1, centerY); + P3=new Point(centerX, rect.Bottom - 1); + + arrow[0]=P1; + arrow[1]=P2; + arrow[2]=P3; + + /* Draw the arrow */ + if ((state & ButtonState.Inactive)!=0) { + /* Move away from the shadow */ + arrow[0].X += 1; arrow[0].Y += 1; + arrow[1].X += 1; arrow[1].Y += 1; + arrow[2].X += 1; arrow[2].Y += 1; + + graphics.FillPolygon(SystemBrushes.ControlLightLight, arrow, FillMode.Winding); + + arrow[0]=P1; + arrow[1]=P2; + arrow[2]=P3; + + graphics.FillPolygon(SystemBrushes.ControlDark, arrow, FillMode.Winding); + } else { + graphics.FillPolygon(SystemBrushes.ControlText, arrow, FillMode.Winding); + } + } + public override void ComboBoxDrawNormalDropDownButton (ComboBox comboBox, Graphics g, Rectangle clippingArea, Rectangle area, ButtonState state) + { + CPDrawComboButton (g, area, state); + } + public override bool ComboBoxNormalDropDownButtonHasTransparentBackground (ComboBox comboBox, ButtonState state) + { + return true; + } + public override bool ComboBoxDropDownButtonHasHotElementStyle (ComboBox comboBox) + { + return false; + } + public override void ComboBoxDrawBackground (ComboBox comboBox, Graphics g, Rectangle clippingArea, FlatStyle style) + { + if (!comboBox.Enabled) + g.FillRectangle (ResPool.GetSolidBrush (ColorControl), comboBox.ClientRectangle); + + if (comboBox.DropDownStyle == ComboBoxStyle.Simple) + g.FillRectangle (ResPool.GetSolidBrush (comboBox.Parent.BackColor), comboBox.ClientRectangle); + + if (style == FlatStyle.Popup && (comboBox.Entered || comboBox.Focused)) { + Rectangle area = comboBox.TextArea; + area.Height -= 1; + area.Width -= 1; + g.DrawRectangle (ResPool.GetPen (SystemColors.ControlDark), area); + g.DrawLine (ResPool.GetPen (SystemColors.ControlDark), comboBox.ButtonArea.X - 1, comboBox.ButtonArea.Top, comboBox.ButtonArea.X - 1, comboBox.ButtonArea.Bottom); + } + bool is_flat = style == FlatStyle.Flat || style == FlatStyle.Popup; + if (!is_flat && clippingArea.IntersectsWith (comboBox.TextArea)) + WidgetPaint.DrawBorder3D (g, comboBox.TextArea, Border3DStyle.Sunken); + } + public override bool CombBoxBackgroundHasHotElementStyle (ComboBox comboBox) + { + return false; + } + #endregion ComboBox + + /* FIXME: NEIN. I will NOT port DataGrids over. + #region Datagrid + public override int DataGridPreferredColumnWidth { get { return 75;} } + public override int DataGridMinimumColumnCheckBoxHeight { get { return 16;} } + public override int DataGridMinimumColumnCheckBoxWidth { get { return 16;} } + public override Color DataGridAlternatingBackColor { get { return ColorWindow;} } + public override Color DataGridBackColor { get { return ColorWindow;} } + public override Color DataGridBackgroundColor { get { return ColorAppWorkspace;} } + public override Color DataGridCaptionBackColor { get { return ColorActiveCaption;} } + public override Color DataGridCaptionForeColor { get { return ColorActiveCaptionText;} } + public override Color DataGridGridLineColor { get { return ColorControl;} } + public override Color DataGridHeaderBackColor { get { return ColorControl;} } + public override Color DataGridHeaderForeColor { get { return ColorControlText;} } + public override Color DataGridLinkColor { get { return ColorHotTrack;} } + public override Color DataGridLinkHoverColor { get { return ColorHotTrack;} } + public override Color DataGridParentRowsBackColor { get { return ColorControl;} } + public override Color DataGridParentRowsForeColor { get { return ColorWindowText;} } + public override Color DataGridSelectionBackColor { get { return ColorActiveCaption;} } + public override Color DataGridSelectionForeColor { get { return ColorActiveCaptionText;} } + + public override void DataGridPaint (PaintEventArgs pe, DataGrid grid) + { + DataGridPaintCaption (pe.Graphics, pe.ClipRectangle, grid); + DataGridPaintParentRows (pe.Graphics, pe.ClipRectangle, grid); + DataGridPaintColumnHeaders (pe.Graphics, pe.ClipRectangle, grid); + DataGridPaintRows (pe.Graphics, grid.cells_area, pe.ClipRectangle, grid); + + // Paint scrollBar corner + if (grid.VScrollBar.Visible && grid.HScrollBar.Visible) { + + Rectangle corner = new Rectangle (grid.ClientRectangle.X + grid.ClientRectangle.Width - grid.VScrollBar.Width, + grid.ClientRectangle.Y + grid.ClientRectangle.Height - grid.HScrollBar.Height, + grid.VScrollBar.Width, grid.HScrollBar.Height); + + if (pe.ClipRectangle.IntersectsWith (corner)) { + pe.Graphics.FillRectangle (ResPool.GetSolidBrush (grid.ParentRowsBackColor), + corner); + } + } + } + + public override void DataGridPaintCaption (Graphics g, Rectangle clip, DataGrid grid) + { + Rectangle bounds = clip; + bounds.Intersect (grid.caption_area); + + // Background + g.FillRectangle (ResPool.GetSolidBrush (grid.CaptionBackColor), bounds); + + // Bottom line + g.DrawLine (ResPool.GetPen (grid.CurrentTableStyle.CurrentHeaderForeColor), + bounds.X, bounds.Y + bounds.Height -1, + bounds.X + bounds.Width, bounds.Y + bounds.Height -1); + + // Caption text + if (grid.CaptionText != String.Empty) { + Rectangle text_rect = grid.caption_area; + text_rect.Y += text_rect.Height / 2 - grid.CaptionFont.Height / 2; + text_rect.Height = grid.CaptionFont.Height; + + g.DrawString (grid.CaptionText, grid.CaptionFont, + ResPool.GetSolidBrush (grid.CaptionForeColor), + text_rect); + } + + // Back button + if (bounds.IntersectsWith (grid.back_button_rect)) { + g.DrawImage (grid.back_button_image, grid.back_button_rect); + if (grid.back_button_mouseover) { + CPDrawBorder3D (g, grid.back_button_rect, grid.back_button_active ? Border3DStyle.Sunken : Border3DStyle.Raised, all_sides); + } + } + + // Rows button + if (bounds.IntersectsWith (grid.parent_rows_button_rect)) { + g.DrawImage (grid.parent_rows_button_image, grid.parent_rows_button_rect); + if (grid.parent_rows_button_mouseover) { + CPDrawBorder3D (g, grid.parent_rows_button_rect, grid.parent_rows_button_active ? Border3DStyle.Sunken : Border3DStyle.Raised, all_sides); + } + } + } + + public override void DataGridPaintColumnHeaders (Graphics g, Rectangle clip, DataGrid grid) + { + if (!grid.CurrentTableStyle.ColumnHeadersVisible) + return; + + Rectangle columns_area = grid.column_headers_area; + + // Paint corner shared between row and column header + if (grid.CurrentTableStyle.CurrentRowHeadersVisible) { + Rectangle rect_bloc = grid.column_headers_area; + rect_bloc.Width = grid.RowHeaderWidth; + if (clip.IntersectsWith (rect_bloc)) { + if (grid.FlatMode) + g.FillRectangle (ResPool.GetSolidBrush (grid.CurrentTableStyle.CurrentHeaderBackColor), rect_bloc); + else + CPDrawBorder3D (g, rect_bloc, Border3DStyle.RaisedInner, + Border3DSide.Left | Border3DSide.Right | + Border3DSide.Top | Border3DSide.Bottom | Border3DSide.Middle, + grid.CurrentTableStyle.CurrentHeaderBackColor); + } + + columns_area.X += grid.RowHeaderWidth; + columns_area.Width -= grid.RowHeaderWidth; + } + + // Set column painting + Rectangle rect_columnhdr = new Rectangle (); + int col_pixel; + Region current_clip; + Region prev_clip = g.Clip; + rect_columnhdr.Y = columns_area.Y; + rect_columnhdr.Height = columns_area.Height; + + int column_cnt = grid.FirstVisibleColumn + grid.VisibleColumnCount; + for (int column = grid.FirstVisibleColumn; column < column_cnt; column++) { + if (grid.CurrentTableStyle.GridColumnStyles[column].bound == false) + continue; + + col_pixel = grid.GetColumnStartingPixel (column); + rect_columnhdr.X = columns_area.X + col_pixel - grid.HorizPixelOffset; + rect_columnhdr.Width = grid.CurrentTableStyle.GridColumnStyles[column].Width; + + if (clip.IntersectsWith (rect_columnhdr) == false) + continue; + + current_clip = new Region (rect_columnhdr); + current_clip.Intersect (columns_area); + current_clip.Intersect (prev_clip); + g.Clip = current_clip; + + DataGridPaintColumnHeader (g, rect_columnhdr, grid, column); + + current_clip.Dispose (); + } + + g.Clip = prev_clip; + + Rectangle not_usedarea = grid.column_headers_area; + not_usedarea.X = (column_cnt == 0) ? grid.RowHeaderWidth : rect_columnhdr.X + rect_columnhdr.Width; + not_usedarea.Width = grid.ClientRectangle.X + grid.ClientRectangle.Width - not_usedarea.X; + g.FillRectangle (ResPool.GetSolidBrush (grid.BackgroundColor), not_usedarea); + } + + public override void DataGridPaintColumnHeader (Graphics g, Rectangle bounds, DataGrid grid, int col) + { + // Background + g.FillRectangle (ResPool.GetSolidBrush (grid.CurrentTableStyle.HeaderBackColor), bounds); + + // Paint Borders + if (!grid.FlatMode) { + g.DrawLine (ResPool.GetPen (ColorControlLightLight), + bounds.X, bounds.Y, bounds.X + bounds.Width, bounds.Y); + + if (col == 0) { + g.DrawLine (ResPool.GetPen (ColorControlLightLight), + bounds.X, bounds.Y, bounds.X, bounds.Y + bounds.Height); + } else { + g.DrawLine (ResPool.GetPen (ColorControlLightLight), + bounds.X, bounds.Y + 2, bounds.X, bounds.Y + bounds.Height - 3); + } + + if (col == (grid.VisibleColumnCount -1)) { + g.DrawLine (ResPool.GetPen (ColorControlDark), + bounds.X + bounds.Width - 1, bounds.Y, + bounds.X + bounds.Width - 1, bounds.Y + bounds.Height); + } else { + g.DrawLine (ResPool.GetPen (ColorControlDark), + bounds.X + bounds.Width - 1, bounds.Y + 2, + bounds.X + bounds.Width - 1, bounds.Y + bounds.Height - 3); + } + + g.DrawLine (ResPool.GetPen (ColorControlDark), + bounds.X, bounds.Y + bounds.Height - 1, + bounds.X + bounds.Width, bounds.Y + bounds.Height - 1); + } + + bounds.X += 2; + bounds.Width -= 2; + + DataGridColumnStyle style = grid.CurrentTableStyle.GridColumnStyles[col]; + + if (style.ArrowDrawingMode != DataGridColumnStyle.ArrowDrawing.No) + bounds.Width -= 16; + + // Caption + StringFormat format = new StringFormat (); + format.FormatFlags |= StringFormatFlags.NoWrap; + format.LineAlignment = StringAlignment.Center; + format.Trimming = StringTrimming.Character; + + g.DrawString (style.HeaderText, grid.CurrentTableStyle.HeaderFont, + ResPool.GetSolidBrush (grid.CurrentTableStyle.CurrentHeaderForeColor), + bounds, format); + + // Arrow (6 x 6) + if (style.ArrowDrawingMode != DataGridColumnStyle.ArrowDrawing.No) { + Point pnt = new Point (bounds.X + bounds.Width + 4, bounds.Y + ((bounds.Height - 6)/2)); + + if (style.ArrowDrawingMode == DataGridColumnStyle.ArrowDrawing.Ascending) { + g.DrawLine (SystemPens.ControlLightLight, pnt.X + 6, pnt.Y + 6, pnt.X + 3, pnt.Y); + g.DrawLine (SystemPens.ControlDark, pnt.X, pnt.Y + 6, pnt.X + 6, pnt.Y + 6); + g.DrawLine (SystemPens.ControlDark, pnt.X, pnt.Y + 6, pnt.X + 3, pnt.Y); + } else { + g.DrawLine (SystemPens.ControlLightLight, pnt.X + 6, pnt.Y, pnt.X + 3, pnt.Y + 6); + g.DrawLine (SystemPens.ControlDark, pnt.X, pnt.Y, pnt.X + 6, pnt.Y); + g.DrawLine (SystemPens.ControlDark, pnt.X, pnt.Y, pnt.X + 3, pnt.Y + 6); + } + } + } + + public override void DataGridPaintParentRows (Graphics g, Rectangle clip, DataGrid grid) + { + Rectangle rect_row = new Rectangle (); + + rect_row.X = grid.ParentRowsArea.X; + rect_row.Width = grid.ParentRowsArea.Width; + rect_row.Height = (grid.CaptionFont.Height + 3); + + object[] parentRows = grid.data_source_stack.ToArray(); + + Region current_clip; + Region prev_clip = g.Clip; + for (int row = 0; row < parentRows.Length; row++) { + rect_row.Y = grid.ParentRowsArea.Y + row * rect_row.Height; + + if (clip.IntersectsWith (rect_row) == false) + continue; + + current_clip = new Region (rect_row); + current_clip.Intersect (prev_clip); + g.Clip = current_clip; + + DataGridPaintParentRow (g, rect_row, (DataGridDataSource)parentRows[parentRows.Length - row - 1], grid); + + current_clip.Dispose (); + } + + g.Clip = prev_clip; + } + + public override void DataGridPaintParentRow (Graphics g, Rectangle bounds, DataGridDataSource row, DataGrid grid) + { + // Background + g.FillRectangle (ResPool.GetSolidBrush (grid.ParentRowsBackColor), + bounds); + + Font bold_font = new Font (grid.Font.FontFamily, grid.Font.Size, grid.Font.Style | FontStyle.Bold); + // set up some standard string formating variables + StringFormat text_format = new StringFormat(); + text_format.LineAlignment = StringAlignment.Center; + text_format.Alignment = StringAlignment.Near; + + string table_name = ""; + if (row.view is DataRowView) + table_name = ((ITypedList)((DataRowView)row.view).DataView).GetListName (null) + ": "; + // XXX else? + + Rectangle text_rect; + Size text_size; + + text_size = g.MeasureString (table_name, bold_font).ToSize(); + text_rect = new Rectangle(new Point(bounds.X + 3, bounds.Y + bounds.Height - text_size.Height), text_size); + + g.DrawString (table_name, + bold_font, ResPool.GetSolidBrush (grid.ParentRowsForeColor), text_rect, text_format); + + foreach (PropertyDescriptor pd in ((ICustomTypeDescriptor)row.view).GetProperties()) { + if (typeof(IBindingList).IsAssignableFrom (pd.PropertyType)) + continue; + + text_rect.X += text_rect.Size.Width + 5; + + string text = String.Format ("{0}: {1}", + pd.Name, + pd.GetValue (row.view)); + + text_rect.Size = g.MeasureString (text, grid.Font).ToSize(); + text_rect.Y = bounds.Y + bounds.Height - text_rect.Height; // XXX + + g.DrawString (text, + grid.Font, ResPool.GetSolidBrush (grid.ParentRowsForeColor), text_rect, text_format); + } + + // Paint Borders + if (!grid.FlatMode) { + CPDrawBorder3D (g, bounds, Border3DStyle.RaisedInner, + Border3DSide.Left | Border3DSide.Right | + Border3DSide.Top | Border3DSide.Bottom); + } + } + + public override void DataGridPaintRowHeaderArrow (Graphics g, Rectangle bounds, DataGrid grid) + { + Point[] arrow = new Point[3]; + Point P1, P2, P3; + int centerX, centerY, shiftX; + Rectangle rect; + + rect = new Rectangle (bounds.X + bounds.Width /4, + bounds.Y + bounds.Height/4, bounds.Width / 2, bounds.Height / 2); + + centerX = rect.Left + rect.Width / 2; + centerY = rect.Top + rect.Height / 2; + shiftX = Math.Max (1, rect.Width / 8); + rect.X -= shiftX; + centerX -= shiftX; + P1 = new Point (centerX, rect.Top - 1); + P2 = new Point (centerX, rect.Bottom); + P3 = new Point (rect.Right, centerY); + arrow[0] = P1; + arrow[1] = P2; + arrow[2] = P3; + + g.FillPolygon (ResPool.GetSolidBrush + (grid.CurrentTableStyle.CurrentHeaderForeColor), arrow, FillMode.Winding); + } + + public override void DataGridPaintRowHeaderStar (Graphics g, Rectangle bounds, DataGrid grid) + { + int x = bounds.X + 4; + int y = bounds.Y + 3; + Pen pen = ResPool.GetPen (grid.CurrentTableStyle.CurrentHeaderForeColor); + + g.DrawLine (pen, x + 4, y, x + 4, y + 8); + g.DrawLine (pen, x, y + 4, x + 8, y + 4); + g.DrawLine (pen, x + 1, y + 1, x + 7, y + 7); + g.DrawLine (pen, x + 7, y + 1, x + 1, y + 7); + } + + public override void DataGridPaintRowHeader (Graphics g, Rectangle bounds, int row, DataGrid grid) + { + bool is_add_row = grid.ShowEditRow && row == grid.DataGridRows.Length - 1; + bool is_current_row = row == grid.CurrentCell.RowNumber; + + // Background + g.FillRectangle (ResPool.GetSolidBrush (grid.CurrentTableStyle.CurrentHeaderBackColor), bounds); + + // Draw arrow + if (is_current_row) { + if (grid.IsChanging) { + g.DrawString ("...", grid.Font, + ResPool.GetSolidBrush (grid.CurrentTableStyle.CurrentHeaderForeColor), + bounds); + } else { + Rectangle rect = new Rectangle (bounds.X - 2, bounds.Y, 18, 18); + DataGridPaintRowHeaderArrow (g, rect, grid); + } + } + else if (is_add_row) { + DataGridPaintRowHeaderStar (g, bounds, grid); + } + + if (!grid.FlatMode && !is_add_row) { + CPDrawBorder3D (g, bounds, Border3DStyle.RaisedInner, + Border3DSide.Left | Border3DSide.Right | + Border3DSide.Top | Border3DSide.Bottom); + } + } + + public override void DataGridPaintRows (Graphics g, Rectangle cells, Rectangle clip, DataGrid grid) + { + Rectangle rect_row = new Rectangle (); + Rectangle not_usedarea = new Rectangle (); + + int rowcnt = grid.VisibleRowCount; + + bool showing_add_row = false; + + if (grid.RowsCount < grid.DataGridRows.Length) { + /* the table has an add row + + if (grid.FirstVisibleRow + grid.VisibleRowCount >= grid.DataGridRows.Length) { + showing_add_row = true; + } + } + + rect_row.Width = cells.Width + grid.RowHeadersArea.Width; + for (int r = 0; r < rowcnt; r++) { + int row = grid.FirstVisibleRow + r; + if (row == grid.DataGridRows.Length - 1) + rect_row.Height = grid.DataGridRows[row].Height; + else + rect_row.Height = grid.DataGridRows[row + 1].VerticalOffset - grid.DataGridRows[row].VerticalOffset; + rect_row.Y = cells.Y + grid.DataGridRows[row].VerticalOffset - grid.DataGridRows[grid.FirstVisibleRow].VerticalOffset; + if (clip.IntersectsWith (rect_row)) { + if (grid.CurrentTableStyle.HasRelations + && !(showing_add_row && row == grid.DataGridRows.Length - 1)) + DataGridPaintRelationRow (g, row, rect_row, false, clip, grid); + else + DataGridPaintRow (g, row, rect_row, showing_add_row && row == grid.DataGridRows.Length - 1, clip, grid); + } + } + + not_usedarea.X = 0; + // the rowcnt == 0 check is needed because + // otherwise we'd draw over the caption on + // empty datasources (since rect_row would be + // Empty) + if (rowcnt == 0) + not_usedarea.Y = cells.Y; + else + not_usedarea.Y = rect_row.Y + rect_row.Height; + not_usedarea.Height = cells.Y + cells.Height - rect_row.Y - rect_row.Height; + not_usedarea.Width = cells.Width + grid.RowHeadersArea.Width; + + g.FillRectangle (ResPool.GetSolidBrush (grid.BackgroundColor), not_usedarea); + } + + public override void DataGridPaintRelationRow (Graphics g, int row, Rectangle row_rect, bool is_newrow, + Rectangle clip, DataGrid grid) + { + Rectangle rect_header; + Rectangle icon_bounds = new Rectangle (); + Pen pen = ThemeEngine.Current.ResPool.GetPen (grid.CurrentTableStyle.ForeColor); + + /* paint the header if it's visible and intersects the clip + if (grid.CurrentTableStyle.CurrentRowHeadersVisible) { + rect_header = row_rect; + rect_header.Width = grid.RowHeaderWidth; + row_rect.X += grid.RowHeaderWidth; + if (clip.IntersectsWith (rect_header)) { + DataGridPaintRowHeader (g, rect_header, row, grid); + } + + icon_bounds = rect_header; + icon_bounds.X += icon_bounds.Width / 2; + icon_bounds.Y += 3; + icon_bounds.Width = 8; + icon_bounds.Height = 8; + + g.DrawRectangle (pen, icon_bounds); + + /* the - part of the icon + g.DrawLine (pen, + icon_bounds.X + 2, icon_bounds.Y + icon_bounds.Height / 2, + icon_bounds.X + icon_bounds.Width - 2, icon_bounds.Y + icon_bounds.Height / 2); + + if (!grid.IsExpanded (row)) { + /* the | part of the icon + g.DrawLine (pen, + icon_bounds.X + icon_bounds.Width / 2, icon_bounds.Y + 2, + icon_bounds.X + icon_bounds.Width / 2, icon_bounds.Y + icon_bounds.Height - 2); + } + } + + Rectangle nested_rect = row_rect; + + if (grid.DataGridRows[row].IsExpanded) + nested_rect.Height -= grid.DataGridRows[row].RelationHeight; + + DataGridPaintRowContents (g, row, nested_rect, is_newrow, clip, grid); + + if (grid.DataGridRows[row].IsExpanded) { + // XXX we should create this in the + // datagrid and cache it for use by + // the theme instead of doing it each + // time through here + string[] relations = grid.CurrentTableStyle.Relations; + StringBuilder relation_builder = new StringBuilder (""); + + for (int i = 0; i < relations.Length; i ++) { + if (i > 0) + relation_builder.Append ("\n"); + + relation_builder.Append (relations[i]); + } + string relation_text = relation_builder.ToString (); + + StringFormat string_format = new StringFormat (); + string_format.FormatFlags |= StringFormatFlags.NoWrap; + + + //Region prev_clip = g.Clip; + //Region current_clip; + Rectangle rect_cell = row_rect; + + rect_cell.X = nested_rect.X + grid.GetColumnStartingPixel (grid.FirstVisibleColumn) - grid.HorizPixelOffset; + rect_cell.Y += nested_rect.Height; + rect_cell.Height = grid.DataGridRows[row].RelationHeight; + + rect_cell.Width = 0; + int column_cnt = grid.FirstVisibleColumn + grid.VisibleColumnCount; + for (int column = grid.FirstVisibleColumn; column < column_cnt; column++) { + if (grid.CurrentTableStyle.GridColumnStyles[column].bound == false) + continue; + rect_cell.Width += grid.CurrentTableStyle.GridColumnStyles[column].Width; + } + rect_cell.Width = Math.Max (rect_cell.Width, grid.DataGridRows[row].relation_area.Width); + + g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (grid.CurrentTableStyle.BackColor), + rect_cell); + + + /* draw the line leading from the +/- to the relation area + Rectangle outline = grid.DataGridRows[row].relation_area; + outline.Y = rect_cell.Y; + outline.Height --; + + g.DrawLine (pen, + icon_bounds.X + icon_bounds.Width / 2, icon_bounds.Y + icon_bounds.Height, + icon_bounds.X + icon_bounds.Width / 2, outline.Y + outline.Height / 2); + + g.DrawLine (pen, + icon_bounds.X + icon_bounds.Width / 2, outline.Y + outline.Height / 2, + outline.X, outline.Y + outline.Height / 2); + + g.DrawRectangle (pen, outline); + + g.DrawString (relation_text, grid.LinkFont, ResPool.GetSolidBrush (grid.LinkColor), + outline, string_format); + + if (row_rect.X + row_rect.Width > rect_cell.X + rect_cell.Width) { + Rectangle not_usedarea = new Rectangle (); + not_usedarea.X = rect_cell.X + rect_cell.Width; + not_usedarea.Width = row_rect.X + row_rect.Width - rect_cell.X - rect_cell.Width; + not_usedarea.Y = row_rect.Y; + not_usedarea.Height = row_rect.Height; + if (clip.IntersectsWith (not_usedarea)) + g.FillRectangle (ResPool.GetSolidBrush (grid.BackgroundColor), + not_usedarea); + } + } + } + + public override void DataGridPaintRowContents (Graphics g, int row, Rectangle row_rect, bool is_newrow, + Rectangle clip, DataGrid grid) + { + Rectangle rect_cell = new Rectangle (); + int col_pixel; + Color backcolor, forecolor; + Brush backBrush, foreBrush; + Rectangle not_usedarea = Rectangle.Empty; + + rect_cell.Y = row_rect.Y; + rect_cell.Height = row_rect.Height; + + if (grid.IsSelected (row)) { + backcolor = grid.SelectionBackColor; + forecolor = grid.SelectionForeColor; + } else { + if (row % 2 == 0) { + backcolor = grid.BackColor; + } else { + backcolor = grid.AlternatingBackColor; + } + + forecolor = grid.ForeColor; + } + + + backBrush = ResPool.GetSolidBrush (backcolor); + foreBrush = ResPool.GetSolidBrush (forecolor); + + // PaintCells at row, column + int column_cnt = grid.FirstVisibleColumn + grid.VisibleColumnCount; + DataGridCell current_cell = grid.CurrentCell; + + if (column_cnt > 0) { + Region prev_clip = g.Clip; + Region current_clip; + + for (int column = grid.FirstVisibleColumn; column < column_cnt; column++) { + if (grid.CurrentTableStyle.GridColumnStyles[column].bound == false) + continue; + + col_pixel = grid.GetColumnStartingPixel (column); + + rect_cell.X = row_rect.X + col_pixel - grid.HorizPixelOffset; + rect_cell.Width = grid.CurrentTableStyle.GridColumnStyles[column].Width; + + if (clip.IntersectsWith (rect_cell)) { + current_clip = new Region (rect_cell); + current_clip.Intersect (row_rect); + current_clip.Intersect (prev_clip); + g.Clip = current_clip; + + Brush colBackBrush = backBrush; + Brush colForeBrush = foreBrush; + + // If we are in the precise cell we are editing, then use the normal colors + // even if we are selected. + if (grid.is_editing && column == current_cell.ColumnNumber && row == current_cell.RowNumber) { + colBackBrush = ResPool.GetSolidBrush (grid.BackColor); + colForeBrush = ResPool.GetSolidBrush (grid.ForeColor); + } + + if (is_newrow) { + grid.CurrentTableStyle.GridColumnStyles[column].PaintNewRow (g, rect_cell, + colBackBrush, + colForeBrush); + } else { + grid.CurrentTableStyle.GridColumnStyles[column].Paint (g, rect_cell, grid.ListManager, row, + colBackBrush, + colForeBrush, + grid.RightToLeft == RightToLeft.Yes); + } + + current_clip.Dispose (); + } + } + + g.Clip = prev_clip; + + if (row_rect.X + row_rect.Width > rect_cell.X + rect_cell.Width) { + not_usedarea.X = rect_cell.X + rect_cell.Width; + not_usedarea.Width = row_rect.X + row_rect.Width - rect_cell.X - rect_cell.Width; + not_usedarea.Y = row_rect.Y; + not_usedarea.Height = row_rect.Height; + } + } + else { + not_usedarea = row_rect; + } + + if (!not_usedarea.IsEmpty && clip.IntersectsWith (not_usedarea)) + g.FillRectangle (ResPool.GetSolidBrush (grid.BackgroundColor), + not_usedarea); + } + + public override void DataGridPaintRow (Graphics g, int row, Rectangle row_rect, bool is_newrow, + Rectangle clip, DataGrid grid) + { + /* paint the header if it's visible and intersects the clip + if (grid.CurrentTableStyle.CurrentRowHeadersVisible) { + Rectangle rect_header = row_rect; + rect_header.Width = grid.RowHeaderWidth; + row_rect.X += grid.RowHeaderWidth; + if (clip.IntersectsWith (rect_header)) { + DataGridPaintRowHeader (g, rect_header, row, grid); + } + } + + DataGridPaintRowContents (g, row, row_rect, is_newrow, clip, grid); + } + + #endregion // Datagrid + + #region DataGridView + #region DataGridViewHeaderCell + #region DataGridViewRowHeaderCell + public override bool DataGridViewRowHeaderCellDrawBackground (DataGridViewRowHeaderCell cell, Graphics g, Rectangle bounds) + { + return false; + } + + public override bool DataGridViewRowHeaderCellDrawSelectionBackground (DataGridViewRowHeaderCell cell) + { + return false; + } + + public override bool DataGridViewRowHeaderCellDrawBorder (DataGridViewRowHeaderCell cell, Graphics g, Rectangle bounds) + { + return false; + } + #endregion + + #region DataGridViewColumnHeaderCell + public override bool DataGridViewColumnHeaderCellDrawBackground (DataGridViewColumnHeaderCell cell, Graphics g, Rectangle bounds) + { + return false; + } + + public override bool DataGridViewColumnHeaderCellDrawBorder (DataGridViewColumnHeaderCell cell, Graphics g, Rectangle bounds) + { + return false; + } + #endregion + + public override bool DataGridViewHeaderCellHasPressedStyle (DataGridView dataGridView) + { + return false; + } + + public override bool DataGridViewHeaderCellHasHotStyle (DataGridView dataGridView) + { + return false; + } + #endregion + #endregion +*/ + + #region DateTimePicker + protected virtual void DateTimePickerDrawBorder (DateTimePicker dateTimePicker, Graphics g, Rectangle clippingArea) + { + this.CPDrawBorder3D (g, dateTimePicker.ClientRectangle, Border3DStyle.Sunken, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom, dateTimePicker.BackColor); + } + + protected virtual void DateTimePickerDrawDropDownButton (DateTimePicker dateTimePicker, Graphics g, Rectangle clippingArea) + { + ButtonState state = dateTimePicker.is_drop_down_visible ? ButtonState.Pushed : ButtonState.Normal; + g.FillRectangle (ResPool.GetSolidBrush (ColorControl), dateTimePicker.drop_down_arrow_rect); + this.CPDrawComboButton ( + g, + dateTimePicker.drop_down_arrow_rect, + state); + } + + public override void DrawDateTimePicker(Graphics dc, Rectangle clip_rectangle, DateTimePicker dtp) + { + + if (!clip_rectangle.IntersectsWith (dtp.ClientRectangle)) + return; + + // draw the outer border + Rectangle button_bounds = dtp.ClientRectangle; + DateTimePickerDrawBorder (dtp, dc, clip_rectangle); + + // deflate by the border width + if (clip_rectangle.IntersectsWith (dtp.drop_down_arrow_rect)) { + button_bounds.Inflate (-2,-2); + if (!dtp.ShowUpDown) { + DateTimePickerDrawDropDownButton (dtp, dc, clip_rectangle); + } else { + ButtonState up_state = dtp.is_up_pressed ? ButtonState.Pushed : ButtonState.Normal; + ButtonState down_state = dtp.is_down_pressed ? ButtonState.Pushed : ButtonState.Normal; + Rectangle up_bounds = dtp.drop_down_arrow_rect; + Rectangle down_bounds = dtp.drop_down_arrow_rect; + + up_bounds.Height = up_bounds.Height / 2; + down_bounds.Y = up_bounds.Height; + down_bounds.Height = dtp.Height - up_bounds.Height; + if (down_bounds.Height > up_bounds.Height) + { + down_bounds.Y += 1; + down_bounds.Height -= 1; + } + + up_bounds.Inflate (-1, -1); + down_bounds.Inflate (-1, -1); + + WidgetPaint.DrawScrollButton (dc, up_bounds, ScrollButton.Up, up_state); + WidgetPaint.DrawScrollButton (dc, down_bounds, ScrollButton.Down, down_state); + } + } + + // render the date part + if (!clip_rectangle.IntersectsWith (dtp.date_area_rect)) + return; + + // fill the background + dc.FillRectangle (SystemBrushes.Window, dtp.date_area_rect); + + // Update date_area_rect if we are drawing the checkbox + Rectangle date_area_rect = dtp.date_area_rect; + if (dtp.ShowCheckBox) { + Rectangle check_box_rect = dtp.CheckBoxRect; + date_area_rect.X = date_area_rect.X + check_box_rect.Width + DateTimePicker.check_box_space * 2; + date_area_rect.Width = date_area_rect.Width - check_box_rect.Width - DateTimePicker.check_box_space * 2; + + ButtonState bs = dtp.Checked ? ButtonState.Checked : ButtonState.Normal; + CPDrawCheckBox(dc, check_box_rect, bs); + + if (dtp.is_checkbox_selected) + CPDrawFocusRectangle (dc, check_box_rect, dtp.foreground_color, dtp.background_color); + } + + // render each text part + using (StringFormat text_format = StringFormat.GenericTypographic) + { + text_format.LineAlignment = StringAlignment.Near; + text_format.Alignment = StringAlignment.Near; + text_format.FormatFlags = text_format.FormatFlags | StringFormatFlags.MeasureTrailingSpaces | StringFormatFlags.NoWrap | StringFormatFlags.FitBlackBox; + text_format.FormatFlags &= ~StringFormatFlags.NoClip; + + // Calculate the rectangles for each part + if (dtp.part_data.Length > 0 && dtp.part_data[0].drawing_rectangle.IsEmpty) + { + Graphics gr = dc; + for (int i = 0; i < dtp.part_data.Length; i++) + { + DateTimePicker.PartData fd = dtp.part_data[i]; + RectangleF text_rect = new RectangleF(); + string text = fd.GetText(dtp.Value); + text_rect.Size = gr.MeasureString (text, dtp.Font, 250, text_format); + if (!fd.is_literal) + text_rect.Width = Math.Max (dtp.CalculateMaxWidth(fd.value, gr, text_format), text_rect.Width); + + if (i > 0) { + text_rect.X = dtp.part_data[i - 1].drawing_rectangle.Right; + } else { + text_rect.X = date_area_rect.X; + } + text_rect.Y = 2; + text_rect.Inflate (1, 0); + fd.drawing_rectangle = text_rect; + } + } + + // draw the text part + Brush text_brush = ResPool.GetSolidBrush (dtp.ShowCheckBox && dtp.Checked == false ? + SystemColors.GrayText : dtp.ForeColor); // Use GrayText if Checked is false + RectangleF clip_rectangleF = clip_rectangle; + + for (int i = 0; i < dtp.part_data.Length; i++) + { + DateTimePicker.PartData fd = dtp.part_data [i]; + string text; + + if (!clip_rectangleF.IntersectsWith (fd.drawing_rectangle)) + continue; + + text = dtp.editing_part_index == i ? dtp.editing_text : fd.GetText (dtp.Value); + + PointF text_position = new PointF (); + SizeF text_size; + RectangleF text_rect; + + text_size = dc.MeasureString (text, dtp.Font, 250, text_format); + text_position.X = (fd.drawing_rectangle.Left + fd.drawing_rectangle.Width / 2) - text_size.Width / 2; + text_position.Y = (fd.drawing_rectangle.Top + fd.drawing_rectangle.Height / 2) - text_size.Height / 2; + text_rect = new RectangleF (text_position, text_size); + text_rect = RectangleF.Intersect (text_rect, date_area_rect); + + if (text_rect.IsEmpty) + break; + + if (text_rect.Right >= date_area_rect.Right) + text_format.FormatFlags &= ~StringFormatFlags.NoClip; + else + text_format.FormatFlags |= StringFormatFlags.NoClip; + + if (fd.Selected) { + dc.FillRectangle (SystemBrushes.Highlight, text_rect); + dc.DrawString (text, dtp.Font, SystemBrushes.HighlightText, text_rect, text_format); + + } else { + dc.DrawString (text, dtp.Font, text_brush, text_rect, text_format); + } + + if (fd.drawing_rectangle.Right > date_area_rect.Right) + break; // the next part would be not be visible, so don't draw anything more. + } + } + } + + public override bool DateTimePickerBorderHasHotElementStyle { + get { + return false; + } + } + + public override Rectangle DateTimePickerGetDropDownButtonArea (DateTimePicker dateTimePicker) + { + Rectangle rect = dateTimePicker.ClientRectangle; + rect.X = rect.Right - SystemInformation.VerticalScrollBarWidth - 2; + if (rect.Width > (SystemInformation.VerticalScrollBarWidth + 2)) { + rect.Width = SystemInformation.VerticalScrollBarWidth; + } else { + rect.Width = Math.Max (rect.Width - 2, 0); + } + + rect.Inflate (0, -2); + return rect; + } + + public override Rectangle DateTimePickerGetDateArea (DateTimePicker dateTimePicker) + { + Rectangle rect = dateTimePicker.ClientRectangle; + if (dateTimePicker.ShowUpDown) { + // set the space to the left of the up/down button + if (rect.Width > (DateTimePicker.up_down_width + 4)) { + rect.Width -= (DateTimePicker.up_down_width + 4); + } else { + rect.Width = 0; + } + } else { + // set the space to the left of the up/down button + // TODO make this use up down button + if (rect.Width > (SystemInformation.VerticalScrollBarWidth + 4)) { + rect.Width -= SystemInformation.VerticalScrollBarWidth; + } else { + rect.Width = 0; + } + } + + rect.Inflate (-2, -2); + return rect; + } + public override bool DateTimePickerDropDownButtonHasHotElementStyle { + get { + return false; + } + } + #endregion // DateTimePicker + + #region GroupBox + public override void DrawGroupBox (Graphics dc, Rectangle area, GroupBox box) { + StringFormat text_format; + SizeF size; + int width; + int y; + + dc.FillRectangle (GetControlBackBrush (box.BackColor), box.ClientRectangle); + + text_format = new StringFormat(); + text_format.HotkeyPrefix = HotkeyPrefix.Show; + + size = dc.MeasureString (box.Text, box.Font); + width = 0; + + if (size.Width > 0) { + width = ((int) size.Width) + 7; + + if (width > box.Width - 16) + width = box.Width - 16; + } + + y = box.Font.Height / 2; + + // Clip the are that the text will be in + Region prev_clip = dc.Clip; + dc.SetClip (new Rectangle (10, 0, width, box.Font.Height), CombineMode.Exclude); + /* Draw group box*/ + CPDrawBorder3D (dc, new Rectangle (0, y, box.Width, box.Height - y), Border3DStyle.Etched, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom, box.BackColor); + dc.Clip = prev_clip; + + /* Text */ + if (box.Text.Length != 0) { + if (box.Enabled) { + dc.DrawString (box.Text, box.Font, ResPool.GetSolidBrush (box.ForeColor), 10, 0, text_format); + } else { + CPDrawStringDisabled (dc, box.Text, box.Font, box.BackColor, + new RectangleF (10, 0, width, box.Font.Height), text_format); + } + } + + text_format.Dispose (); + } + + public override Size GroupBoxDefaultSize { + get { + return new Size (200,100); + } + } + #endregion + + #region HScrollBar + public override Size HScrollBarDefaultSize { + get { + return new Size (80, this.ScrollBarButtonSize); + } + } + + #endregion // HScrollBar + + #region ListBox + + public override void DrawListBoxItem (ListBox ctrl, DrawItemEventArgs e) + { + Color back_color, fore_color; + + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) { + back_color = ColorHighlight; + fore_color = ColorHighlightText; + } else { + back_color = e.BackColor; + fore_color = e.ForeColor; + } + + e.Graphics.FillRectangle (ResPool.GetSolidBrush (back_color), e.Bounds); + + e.Graphics.DrawString (ctrl.GetItemText (ctrl.Items[e.Index]), e.Font, + ResPool.GetSolidBrush (fore_color), + e.Bounds, ctrl.StringFormat); + + if ((e.State & DrawItemState.Focus) == DrawItemState.Focus) + CPDrawFocusRectangle (e.Graphics, e.Bounds, fore_color, back_color); + } + + #endregion ListBox + + #region ListView + // Drawing + public override void DrawListViewItems (Graphics dc, Rectangle clip, ListView control) + { + bool details = control.View == View.Details; + int first = control.FirstVisibleIndex; + int lastvisibleindex = control.LastVisibleIndex; + + if (control.VirtualMode) + control.OnCacheVirtualItems (new CacheVirtualItemsEventArgs (first, lastvisibleindex)); + + for (int i = first; i <= lastvisibleindex; i++) { + ListViewItem item = control.GetItemAtDisplayIndex (i); + if (clip.IntersectsWith (item.Bounds)) { + bool owner_draw = false; + if (control.OwnerDraw) + owner_draw = DrawListViewItemOwnerDraw (dc, item, i); + if (!owner_draw) + { + DrawListViewItem (dc, control, item); + if (control.View == View.Details) + DrawListViewSubItems (dc, control, item); + } + } + } + + if (control.UsingGroups) { + // Use InternalCount instead of Count to take into account Default Group as needed + for (int i = 0; i < control.Groups.InternalCount; i++) { + ListViewGroup group = control.Groups.GetInternalGroup (i); + if (group.ItemCount > 0 && clip.IntersectsWith (group.HeaderBounds)) + DrawListViewGroupHeader (dc, control, group); + } + } + + ListViewInsertionMark insertion_mark = control.InsertionMark; + int insertion_mark_index = insertion_mark.Index; + if (Application.VisualStylesEnabled && insertion_mark.Bounds != Rectangle.Empty && + (control.View != View.Details && control.View != View.List) && + insertion_mark_index > -1 && insertion_mark_index < control.Items.Count) { + + Brush brush = ResPool.GetSolidBrush (insertion_mark.Color); + dc.FillRectangle (brush, insertion_mark.Line); + dc.FillPolygon (brush, insertion_mark.TopTriangle); + dc.FillPolygon (brush, insertion_mark.BottomTriangle); + } + + // draw the gridlines + if (details && control.GridLines && !control.UsingGroups) { + Size control_size = control.ClientSize; + int top = (control.HeaderStyle == ColumnHeaderStyle.None) ? + 0 : control.header_control.Height; + + // draw vertical gridlines + foreach (ColumnHeader col in control.Columns) { + int column_right = col.Rect.Right - control.h_marker; + dc.DrawLine (SystemPens.Control, + column_right, top, + column_right, control_size.Height); + } + + // draw horizontal gridlines + int item_height = control.ItemSize.Height; + if (item_height == 0) + item_height = control.Font.Height + 2; + + int y = top + item_height - (control.v_marker % item_height); // scroll bar offset + while (y < control_size.Height) { + dc.DrawLine (SystemPens.Control, 0, y, control_size.Width, y); + y += item_height; + } + } + + // Draw corner between the two scrollbars + if (control.h_scroll.Visible == true && control.v_scroll.Visible == true) { + Rectangle rect = new Rectangle (); + rect.X = control.h_scroll.Location.X + control.h_scroll.Width; + rect.Width = control.v_scroll.Width; + rect.Y = control.v_scroll.Location.Y + control.v_scroll.Height; + rect.Height = control.h_scroll.Height; + dc.FillRectangle (SystemBrushes.Control, rect); + } + + Rectangle box_select_rect = control.item_control.BoxSelectRectangle; + if (!box_select_rect.Size.IsEmpty) + dc.DrawRectangle (ResPool.GetDashPen (ColorControlText, DashStyle.Dot), box_select_rect); + + } + + public override void DrawListViewHeader (Graphics dc, Rectangle clip, ListView control) + { + bool details = (control.View == View.Details); + + // border is drawn directly in the Paint method + if (details && control.HeaderStyle != ColumnHeaderStyle.None) { + dc.FillRectangle (SystemBrushes.Control, + 0, 0, control.TotalWidth, control.Font.Height + 5); + if (control.Columns.Count > 0) { + foreach (ColumnHeader col in control.Columns) { + Rectangle rect = col.Rect; + rect.X -= control.h_marker; + + bool owner_draw = false; + if (control.OwnerDraw) + owner_draw = DrawListViewColumnHeaderOwnerDraw (dc, control, col, rect); + if (owner_draw) + continue; + + ListViewDrawColumnHeaderBackground (control, col, dc, rect, clip); + rect.X += 5; + rect.Width -= 10; + if (rect.Width <= 0) + continue; + + int image_index; + if (control.SmallImageList == null) + image_index = -1; + else + image_index = col.ImageKey == String.Empty ? col.ImageIndex : control.SmallImageList.Images.IndexOfKey (col.ImageKey); + + if (image_index > -1 && image_index < control.SmallImageList.Images.Count) { + int image_width = control.SmallImageList.ImageSize.Width + 5; + int text_width = (int)dc.MeasureString (col.Text, control.Font).Width; + int x_origin = rect.X; + int y_origin = rect.Y + ((rect.Height - control.SmallImageList.ImageSize.Height) / 2); + + switch (col.TextAlign) { + case HorizontalAlignment.Left: + break; + case HorizontalAlignment.Right: + x_origin = rect.Right - (text_width + image_width); + break; + case HorizontalAlignment.Center: + x_origin = (rect.Width - (text_width + image_width)) / 2 + rect.X; + break; + } + + if (x_origin < rect.X) + x_origin = rect.X; + + control.SmallImageList.Draw (dc, new Point (x_origin, y_origin), image_index); + rect.X += image_width; + rect.Width -= image_width; + } + + dc.DrawString (col.Text, control.Font, SystemBrushes.ControlText, rect, col.Format); + } + int right = control.GetReorderedColumn (control.Columns.Count - 1).Rect.Right - control.h_marker; + if (right < control.Right) { + Rectangle rect = control.Columns [0].Rect; + rect.X = right; + rect.Width = control.Right - right; + ListViewDrawUnusedHeaderBackground (control, dc, rect, clip); + } + } + } + } + + protected virtual void ListViewDrawColumnHeaderBackground (ListView listView, ColumnHeader columnHeader, Graphics g, Rectangle area, Rectangle clippingArea) + { + ButtonState state; + if (listView.HeaderStyle == ColumnHeaderStyle.Clickable) + state = columnHeader.Pressed ? ButtonState.Pushed : ButtonState.Normal; + else + state = ButtonState.Flat; + CPDrawButton (g, area, state); + } + + protected virtual void ListViewDrawUnusedHeaderBackground (ListView listView, Graphics g, Rectangle area, Rectangle clippingArea) + { + ButtonState state; + if (listView.HeaderStyle == ColumnHeaderStyle.Clickable) + state = ButtonState.Normal; + else + state = ButtonState.Flat; + CPDrawButton (g, area, state); + } + + public override void DrawListViewHeaderDragDetails (Graphics dc, ListView view, ColumnHeader col, int target_x) + { + Rectangle rect = col.Rect; + rect.X -= view.h_marker; + Color color = Color.FromArgb (0x7f, ColorControlDark.R, ColorControlDark.G, ColorControlDark.B); + dc.FillRectangle (ResPool.GetSolidBrush (color), rect); + rect.X += 3; + rect.Width -= 8; + if (rect.Width <= 0) + return; + color = Color.FromArgb (0x7f, ColorControlText.R, ColorControlText.G, ColorControlText.B); + dc.DrawString (col.Text, view.Font, ResPool.GetSolidBrush (color), rect, col.Format); + dc.DrawLine (ResPool.GetSizedPen (ColorHighlight, 2), target_x, 0, target_x, col.Rect.Height); + } + + protected virtual bool DrawListViewColumnHeaderOwnerDraw (Graphics dc, ListView control, ColumnHeader column, Rectangle bounds) + { + ListViewItemStates state = ListViewItemStates.ShowKeyboardCues; + if (column.Pressed) + state |= ListViewItemStates.Selected; + + DrawListViewColumnHeaderEventArgs args = new DrawListViewColumnHeaderEventArgs (dc, + bounds, column.Index, column, state, SystemColors.ControlText, ThemeEngine.Current.ColorControl, DefaultFont); + control.OnDrawColumnHeader (args); + + return !args.DrawDefault; + } + + protected virtual bool DrawListViewItemOwnerDraw (Graphics dc, ListViewItem item, int index) + { + ListViewItemStates item_state = ListViewItemStates.ShowKeyboardCues; + if (item.Selected) + item_state |= ListViewItemStates.Selected; + if (item.Focused) + item_state |= ListViewItemStates.Focused; + + DrawListViewItemEventArgs args = new DrawListViewItemEventArgs (dc, + item, item.Bounds, index, item_state); + item.ListView.OnDrawItem (args); + + if (args.DrawDefault) + return false; + + if (item.ListView.View == View.Details) { + int count = Math.Min (item.ListView.Columns.Count, item.SubItems.Count); + + // Do system drawing for subitems if no owner draw is done + for (int j = 0; j < count; j++) { + if (!DrawListViewSubItemOwnerDraw (dc, item, item_state, j)) { + if (j == 0) // The first sub item contains the main item semantics + DrawListViewItem (dc, item.ListView, item); + else + DrawListViewSubItem (dc, item.ListView, item, j); + } + } + } + + return true; + } + + protected virtual void DrawListViewItem (Graphics dc, ListView control, ListViewItem item) + { + Rectangle rect_checkrect = item.CheckRectReal; + Rectangle icon_rect = item.GetBounds (ItemBoundsPortion.Icon); + Rectangle full_rect = item.GetBounds (ItemBoundsPortion.Entire); + Rectangle text_rect = item.GetBounds (ItemBoundsPortion.Label); + + // Tile view doesn't support CheckBoxes + if (control.CheckBoxes && control.View != View.Tile) { + if (control.StateImageList == null) { + // Make sure we've got at least a line width of 1 + int check_wd = Math.Max (3, rect_checkrect.Width / 6); + int scale = Math.Max (1, rect_checkrect.Width / 12); + + // set the checkbox background + dc.FillRectangle (SystemBrushes.Window, + rect_checkrect); + // define a rectangle inside the border area + Rectangle rect = new Rectangle (rect_checkrect.X + 2, + rect_checkrect.Y + 2, + rect_checkrect.Width - 4, + rect_checkrect.Height - 4); + Pen pen = ResPool.GetSizedPen (this.ColorWindowText, 2); + dc.DrawRectangle (pen, rect); + + // Need to draw a check-mark + if (item.Checked) { + Pen check_pen = ResPool.GetSizedPen (this.ColorWindowText, 1); + // adjustments to get the check-mark at the right place + rect.X ++; rect.Y ++; + // following logic is taken from DrawFrameControl method + int x_offset = rect.Width / 5; + int y_offset = rect.Height / 3; + for (int i = 0; i < check_wd; i++) { + dc.DrawLine (check_pen, rect.Left + x_offset, + rect.Top + y_offset + i, + rect.Left + x_offset + 2 * scale, + rect.Top + y_offset + 2 * scale + i); + dc.DrawLine (check_pen, + rect.Left + x_offset + 2 * scale, + rect.Top + y_offset + 2 * scale + i, + rect.Left + x_offset + 6 * scale, + rect.Top + y_offset - 2 * scale + i); + } + } + } + else { + int simage_idx; + if (item.Checked) + simage_idx = control.StateImageList.Images.Count > 1 ? 1 : -1; + else + simage_idx = control.StateImageList.Images.Count > 0 ? 0 : -1; + + if (simage_idx > -1) + control.StateImageList.Draw (dc, rect_checkrect.Location, simage_idx); + } + } + + ImageList image_list = control.View == View.LargeIcon || control.View == View.Tile ? control.LargeImageList : control.SmallImageList; + if (image_list != null) { + int idx; + + if (item.ImageKey != String.Empty) + idx = image_list.Images.IndexOfKey (item.ImageKey); + else + idx = item.ImageIndex; + + if (idx > -1 && idx < image_list.Images.Count) { + // Draw a thumbnail image if it exists for a FileViewListViewItem, otherwise draw + // the standard icon. See https://bugzilla.xamarin.com/show_bug.cgi?id=28025. + image_list.Draw(dc, icon_rect.Location, idx); + } + } + + // draw the item text + // format for the item text + StringFormat format = new StringFormat (); + if (control.View == View.SmallIcon || control.View == View.LargeIcon) + format.LineAlignment = StringAlignment.Near; + else + format.LineAlignment = StringAlignment.Center; + if (control.View == View.LargeIcon) + format.Alignment = StringAlignment.Center; + else + format.Alignment = StringAlignment.Near; + + if (control.LabelWrap && control.View != View.Details && control.View != View.Tile) + format.FormatFlags = StringFormatFlags.LineLimit; + else + format.FormatFlags = StringFormatFlags.NoWrap; + + if ((control.View == View.LargeIcon && !item.Focused) || control.View == View.Details || control.View == View.Tile) + format.Trimming = StringTrimming.EllipsisCharacter; + + Rectangle highlight_rect = text_rect; + if (control.View == View.Details) { // Adjustments for Details view + Size text_size = Size.Ceiling (dc.MeasureString (item.Text, item.Font)); + + if (!control.FullRowSelect) // Selection shouldn't be outside the item bounds + highlight_rect.Width = Math.Min (text_size.Width + 4, text_rect.Width); + } + + if (item.Selected && control.Focused) + dc.FillRectangle (SystemBrushes.Highlight, highlight_rect); + else if (item.Selected && !control.HideSelection) + dc.FillRectangle (SystemBrushes.Control, highlight_rect); + else + dc.FillRectangle (ResPool.GetSolidBrush (item.BackColor), text_rect); + + Brush textBrush = + !control.Enabled ? SystemBrushes.ControlLight : + (item.Selected && control.Focused) ? SystemBrushes.HighlightText : + this.ResPool.GetSolidBrush (item.ForeColor); + + // Tile view renders its Text in a different fashion + if (control.View == View.Tile && Application.VisualStylesEnabled) { + // Item.Text is drawn using its first subitem's bounds + dc.DrawString (item.Text, item.Font, textBrush, item.SubItems [0].Bounds, format); + + int count = Math.Min (control.Columns.Count, item.SubItems.Count); + for (int i = 1; i < count; i++) { + ListViewItem.ListViewSubItem sub_item = item.SubItems [i]; + if (sub_item.Text == null || sub_item.Text.Length == 0) + continue; + + Brush itemBrush = item.Selected && control.Focused ? + SystemBrushes.HighlightText : GetControlForeBrush (sub_item.ForeColor); + dc.DrawString (sub_item.Text, sub_item.Font, itemBrush, sub_item.Bounds, format); + } + } else + + if (item.Text != null && item.Text.Length > 0) { + Font font = item.Font; + + if (control.HotTracking && item.Hot) + font = item.HotFont; + + if (item.Selected && control.Focused) + dc.DrawString (item.Text, font, textBrush, highlight_rect, format); + else + dc.DrawString (item.Text, font, textBrush, text_rect, format); + } + + if (item.Focused && control.Focused) { + Rectangle focus_rect = highlight_rect; + if (control.FullRowSelect && control.View == View.Details) { + int width = 0; + foreach (ColumnHeader col in control.Columns) + width += col.Width; + focus_rect = new Rectangle (0, full_rect.Y, width, full_rect.Height); + } + if (control.ShowFocusCues) { + if (item.Selected) + CPDrawFocusRectangle (dc, focus_rect, ColorHighlightText, ColorHighlight); + else + CPDrawFocusRectangle (dc, focus_rect, control.ForeColor, control.BackColor); + } + } + + format.Dispose (); + } + + protected virtual void DrawListViewSubItems (Graphics dc, ListView control, ListViewItem item) + { + int columns_count = control.Columns.Count; + int count = Math.Min (item.SubItems.Count, columns_count); + // 0th item already done (in this case) + for (int i = 1; i < count; i++) + DrawListViewSubItem (dc, control, item, i); + + // Fill in selection for remaining columns if Column.Count > SubItems.Count + Rectangle sub_item_rect = item.GetBounds (ItemBoundsPortion.Label); + if (item.Selected && (control.Focused || !control.HideSelection) && control.FullRowSelect) { + for (int index = count; index < columns_count; index++) { + ColumnHeader col = control.Columns [index]; + sub_item_rect.X = col.Rect.X - control.h_marker; + sub_item_rect.Width = col.Wd; + dc.FillRectangle (control.Focused ? SystemBrushes.Highlight : SystemBrushes.Control, + sub_item_rect); + } + } + } + + protected virtual void DrawListViewSubItem (Graphics dc, ListView control, ListViewItem item, int index) + { + ListViewItem.ListViewSubItem subItem = item.SubItems [index]; + ColumnHeader col = control.Columns [index]; + StringFormat format = new StringFormat (); + format.Alignment = col.Format.Alignment; + format.LineAlignment = StringAlignment.Center; + format.FormatFlags = StringFormatFlags.NoWrap; + format.Trimming = StringTrimming.EllipsisCharacter; + + Rectangle sub_item_rect = subItem.Bounds; + Rectangle sub_item_text_rect = sub_item_rect; + sub_item_text_rect.X += 3; + sub_item_text_rect.Width -= ListViewItemPaddingWidth; + + SolidBrush sub_item_back_br = null; + SolidBrush sub_item_fore_br = null; + Font sub_item_font = null; + + if (item.UseItemStyleForSubItems) { + sub_item_back_br = ResPool.GetSolidBrush (item.BackColor); + sub_item_fore_br = ResPool.GetSolidBrush (item.ForeColor); + + // Hot tracking for subitems only applies when UseStyle is true + if (control.HotTracking && item.Hot) + sub_item_font = item.HotFont; + else + sub_item_font = item.Font; + } else { + sub_item_back_br = ResPool.GetSolidBrush (subItem.BackColor); + sub_item_fore_br = ResPool.GetSolidBrush (subItem.ForeColor); + sub_item_font = subItem.Font; + } + + if (item.Selected && (control.Focused || !control.HideSelection) && control.FullRowSelect) { + Brush bg, text; + if (control.Focused) { + bg = SystemBrushes.Highlight; + text = SystemBrushes.HighlightText; + } else { + bg = SystemBrushes.Control; + text = sub_item_fore_br; + + } + + dc.FillRectangle (bg, sub_item_rect); + if (subItem.Text != null && subItem.Text.Length > 0) + dc.DrawString (subItem.Text, sub_item_font, + text, sub_item_text_rect, format); + } else { + dc.FillRectangle (sub_item_back_br, sub_item_rect); + if (subItem.Text != null && subItem.Text.Length > 0) + dc.DrawString (subItem.Text, sub_item_font, + sub_item_fore_br, + sub_item_text_rect, format); + } + + format.Dispose (); + } + + protected virtual bool DrawListViewSubItemOwnerDraw (Graphics dc, ListViewItem item, ListViewItemStates state, int index) + { + ListView control = item.ListView; + ListViewItem.ListViewSubItem subitem = item.SubItems [index]; + + DrawListViewSubItemEventArgs args = new DrawListViewSubItemEventArgs (dc, subitem.Bounds, item, + subitem, item.Index, index, control.Columns [index], state); + control.OnDrawSubItem (args); + + return !args.DrawDefault; + } + + protected virtual void DrawListViewGroupHeader (Graphics dc, ListView control, ListViewGroup group) + { + Rectangle text_bounds = group.HeaderBounds; + Rectangle header_bounds = group.HeaderBounds; + text_bounds.Offset (8, 0); + text_bounds.Inflate (-8, 0); + int text_height = control.Font.Height + 2; // add a tiny padding between the text and the group line + + Font font = new Font (control.Font, control.Font.Style | FontStyle.Bold); + Brush brush = new LinearGradientBrush (new Point (header_bounds.Left, 0), new Point (header_bounds.Left + ListViewGroupLineWidth, 0), + SystemColors.Desktop, Color.White); + Pen pen = new Pen (brush); + + StringFormat sformat = new StringFormat (); + switch (group.HeaderAlignment) { + case HorizontalAlignment.Left: + sformat.Alignment = StringAlignment.Near; + break; + case HorizontalAlignment.Center: + sformat.Alignment = StringAlignment.Center; + break; + case HorizontalAlignment.Right: + sformat.Alignment = StringAlignment.Far; + break; + } + + sformat.LineAlignment = StringAlignment.Near; + dc.DrawString (group.Header, font, SystemBrushes.ControlText, text_bounds, sformat); + dc.DrawLine (pen, header_bounds.Left, header_bounds.Top + text_height, header_bounds.Left + ListViewGroupLineWidth, + header_bounds.Top + text_height); + + sformat.Dispose (); + font.Dispose (); + pen.Dispose (); + brush.Dispose (); + } + + public override bool ListViewHasHotHeaderStyle { + get { + return false; + } + } + + // Sizing + public override int ListViewGetHeaderHeight (ListView listView, Font font) + { + return ListViewGetHeaderHeight (font); + } + + static int ListViewGetHeaderHeight (Font font) + { + return font.Height + 5; + } + + public static int ListViewGetHeaderHeight () + { + return ListViewGetHeaderHeight (ThemeEngine.Current.DefaultFont); + } + + public override Size ListViewCheckBoxSize { + get { return new Size (16, 16); } + } + + public override int ListViewColumnHeaderHeight { + get { return 16; } + } + + public override int ListViewDefaultColumnWidth { + get { return 60; } + } + + public override int ListViewVerticalSpacing { + get { return 22; } + } + + public override int ListViewEmptyColumnWidth { + get { return 10; } + } + + public override int ListViewHorizontalSpacing { + get { return 4; } + } + + public override int ListViewItemPaddingWidth { + get { return 6; } + } + + public override Size ListViewDefaultSize { + get { return new Size (121, 97); } + } + + public override int ListViewGroupHeight { + get { return 20; } + } + + public int ListViewGroupLineWidth { + get { return 200; } + } + + public override int ListViewTileWidthFactor { + get { return 22; } + } + + public override int ListViewTileHeightFactor { + get { return 3; } + } + #endregion // ListView + + #region Menus + + public override void CalcItemSize (Graphics dc, MenuItem item, int y, int x, bool menuBar) + { + item.X = x; + item.Y = y; + + if (item.Visible == false) { + item.Width = 0; + item.Height = 0; + return; + } + + if (item.Separator == true) { + item.Height = SEPARATOR_HEIGHT; + item.Width = SEPARATOR_MIN_WIDTH; + return; + } + + if (item.MeasureEventDefined) { + MeasureItemEventArgs mi = new MeasureItemEventArgs (dc, item.Index); + item.PerformMeasureItem (mi); + item.Height = mi.ItemHeight; + item.Width = mi.ItemWidth; + return; + } else { + SizeF size; + size = dc.MeasureString (item.Text, MenuFont, int.MaxValue, string_format_menu_text); + item.Width = (int) size.Width; + item.Height = (int) size.Height; + + if (!menuBar) { + if (item.Shortcut != Shortcut.None && item.ShowShortcut) { + item.XTab = MenuCheckSize.Width + MENU_TAB_SPACE + (int) size.Width; + size = dc.MeasureString (" " + item.GetShortCutText (), MenuFont); + item.Width += MENU_TAB_SPACE + (int) size.Width; + } + + item.Width += 4 + (MenuCheckSize.Width * 2); + } else { + item.Width += MENU_BAR_ITEMS_SPACE; + x += item.Width; + } + + if (item.Height < MenuHeight) + item.Height = MenuHeight; + } + } + + // Updates the menu rect and returns the height + public override int CalcMenuBarSize (Graphics dc, Menu menu, int width) + { + int x = 0; + int y = 0; + menu.Height = 0; + + foreach (MenuItem item in menu.MenuItems) { + + CalcItemSize (dc, item, y, x, true); + + if (x + item.Width > width) { + item.X = 0; + y += item.Height; + item.Y = y; + x = 0; + } + + x += item.Width; + item.MenuBar = true; + + if (y + item.Height > menu.Height) + menu.Height = item.Height + y; + } + + menu.Width = width; + return menu.Height; + } + + public override void CalcPopupMenuSize (Graphics dc, Menu menu) + { + int x = 3; + int start = 0; + int i, n, y, max; + + menu.Height = 0; + + while (start < menu.MenuItems.Count) { + y = 3; + max = 0; + for (i = start; i < menu.MenuItems.Count; i++) { + MenuItem item = menu.MenuItems [i]; + + if ((i != start) && (item.Break || item.BarBreak)) + break; + + CalcItemSize (dc, item, y, x, false); + y += item.Height; + + if (item.Width > max) + max = item.Width; + } + + // Replace the -1 by the menu width (separators) + for (n = start; n < i; n++, start++) + menu.MenuItems [n].Width = max; + + if (y > menu.Height) + menu.Height = y; + + x+= max; + } + + menu.Width = x; + + //space for border + menu.Width += 2; + menu.Height += 2; + + menu.Width += SM_CXBORDER; + menu.Height += SM_CYBORDER; + } + + // Draws a menu bar in a window + public override void DrawMenuBar (Graphics dc, Menu menu, Rectangle rect) + { + if (menu.Height == 0) + CalcMenuBarSize (dc, menu, rect.Width); + + bool keynav = (menu as MainMenu).tracker.hotkey_active; + HotkeyPrefix hp = MenuAccessKeysUnderlined || keynav ? HotkeyPrefix.Show : HotkeyPrefix.Hide; + string_format_menu_menubar_text.HotkeyPrefix = hp; + string_format_menu_text.HotkeyPrefix = hp; + + rect.Height = menu.Height; + dc.FillRectangle (SystemBrushes.Menu, rect); + + for (int i = 0; i < menu.MenuItems.Count; i++) { + MenuItem item = menu.MenuItems [i]; + Rectangle item_rect = item.bounds; + item_rect.X += rect.X; + item_rect.Y += rect.Y; + item.MenuHeight = menu.Height; + item.PerformDrawItem (new DrawItemEventArgs (dc, MenuFont, item_rect, i, item.Status)); + } + } + + protected Bitmap CreateGlyphBitmap (Size size, MenuGlyph glyph, Color color) + { + Color bg_color; + if (color.R == 0 && color.G == 0 && color.B == 0) + bg_color = Color.White; + else + bg_color = Color.Black; + + Bitmap bmp = new Bitmap (size.Width, size.Height); + Graphics gr = Graphics.FromImage (bmp); + Rectangle rect = new Rectangle (Point.Empty, size); + gr.FillRectangle (ResPool.GetSolidBrush (bg_color), rect); + CPDrawMenuGlyph (gr, rect, glyph, color, Color.Empty); + bmp.MakeTransparent (bg_color); + gr.Dispose (); + + return bmp; + } + + public override void DrawMenuItem (MenuItem item, DrawItemEventArgs e) + { + StringFormat string_format; + Rectangle rect_text = e.Bounds; + + if (item.Visible == false) + return; + + if (item.MenuBar) + string_format = string_format_menu_menubar_text; + else + string_format = string_format_menu_text; + + if (item.Separator == true) { + int liney = e.Bounds.Y + (e.Bounds.Height / 2); + + e.Graphics.DrawLine (SystemPens.ControlDark, + e.Bounds.X, liney, e.Bounds.X + e.Bounds.Width, liney); + + e.Graphics.DrawLine (SystemPens.ControlLight, + e.Bounds.X, liney + 1, e.Bounds.X + e.Bounds.Width, liney + 1); + + return; + } + + if (!item.MenuBar) + rect_text.X += MenuCheckSize.Width; + + if (item.BarBreak) { /* Draw vertical break bar*/ + Rectangle rect = e.Bounds; + rect.Y++; + rect.Width = 3; + rect.Height = item.MenuHeight - 6; + + e.Graphics.DrawLine (SystemPens.ControlDark, + rect.X, rect.Y , rect.X, rect.Y + rect.Height); + + e.Graphics.DrawLine (SystemPens.ControlLight, + rect.X + 1, rect.Y , rect.X +1, rect.Y + rect.Height); + } + + Color color_text; + Color color_back; + Brush brush_text = null; + Brush brush_back = null; + + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected && !item.MenuBar) { + color_text = ColorHighlightText; + color_back = ColorHighlight; + brush_text = SystemBrushes.HighlightText; + brush_back = SystemBrushes.Highlight; + } else { + color_text = ColorMenuText; + color_back = ColorMenu; + brush_text = ResPool.GetSolidBrush (ColorMenuText); + brush_back = SystemBrushes.Menu; + } + + /* Draw background */ + if (!item.MenuBar) + e.Graphics.FillRectangle (brush_back, e.Bounds); + + if (item.Enabled) { + e.Graphics.DrawString (item.Text, e.Font, + brush_text, + rect_text, string_format); + + if (item.MenuBar) { + Border3DStyle border_style = Border3DStyle.Adjust; + if ((item.Status & DrawItemState.HotLight) != 0) + border_style = Border3DStyle.RaisedInner; + else if ((item.Status & DrawItemState.Selected) != 0) + border_style = Border3DStyle.SunkenOuter; + + if (border_style != Border3DStyle.Adjust) + CPDrawBorder3D(e.Graphics, e.Bounds, border_style, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom, ColorMenu); + } + } else { + if ((item.Status & DrawItemState.Selected) != DrawItemState.Selected) { + e.Graphics.DrawString (item.Text, e.Font, Brushes.White, + new RectangleF(rect_text.X + 1, rect_text.Y + 1, rect_text.Width, rect_text.Height), + string_format); + + } + + e.Graphics.DrawString (item.Text, e.Font, ResPool.GetSolidBrush(ColorGrayText), rect_text, string_format); + } + + if (!item.MenuBar && item.Shortcut != Shortcut.None && item.ShowShortcut) { + string str = item.GetShortCutText (); + Rectangle rect = rect_text; + rect.X = item.XTab; + rect.Width -= item.XTab; + + if (item.Enabled) { + e.Graphics.DrawString (str, e.Font, brush_text, rect, string_format_menu_shortcut); + } else { + if ((item.Status & DrawItemState.Selected) != DrawItemState.Selected) { + e.Graphics.DrawString (str, e.Font, Brushes.White, + new RectangleF(rect.X + 1, rect.Y + 1, rect.Width, rect_text.Height), + string_format_menu_shortcut); + + } + e.Graphics.DrawString (str, e.Font, ResPool.GetSolidBrush(ColorGrayText), rect, string_format_menu_shortcut); + } + } + + /* Draw arrow */ + if (item.MenuBar == false && (item.IsPopup || item.MdiList)) { + + int cx = MenuCheckSize.Width; + int cy = MenuCheckSize.Height; + Bitmap bmp = CreateGlyphBitmap (new Size (cx, cy), MenuGlyph.Arrow, color_text); + + if (item.Enabled) { + e.Graphics.DrawImage (bmp, e.Bounds.X + e.Bounds.Width - cx, + e.Bounds.Y + ((e.Bounds.Height - cy) /2)); + } else { + WidgetPaint.DrawImageDisabled (e.Graphics, bmp, e.Bounds.X + e.Bounds.Width - cx, + e.Bounds.Y + ((e.Bounds.Height - cy) /2), color_back); + } + + bmp.Dispose (); + } + + /* Draw checked or radio */ + if (item.MenuBar == false && item.Checked) { + + Rectangle area = e.Bounds; + int cx = MenuCheckSize.Width; + int cy = MenuCheckSize.Height; + Bitmap bmp = CreateGlyphBitmap (new Size (cx, cy), item.RadioCheck ? MenuGlyph.Bullet : MenuGlyph.Checkmark, color_text); + + e.Graphics.DrawImage (bmp, area.X, e.Bounds.Y + ((e.Bounds.Height - cy) / 2)); + + bmp.Dispose (); + } + } + + public override void DrawPopupMenu (Graphics dc, Menu menu, Rectangle cliparea, Rectangle rect) + { + // Fill rectangle area + dc.FillRectangle (SystemBrushes.Menu, cliparea); + + + // Draw menu items + for (int i = 0; i < menu.MenuItems.Count; i++) { + if (cliparea.IntersectsWith (menu.MenuItems [i].bounds)) { + MenuItem item = menu.MenuItems [i]; + item.MenuHeight = menu.Height; + item.PerformDrawItem (new DrawItemEventArgs (dc, MenuFont, item.bounds, i, item.Status)); + } + } + } + + #endregion // Menus + + #region MonthCalendar + + // draw the month calendar + public override void DrawMonthCalendar(Graphics dc, Rectangle clip_rectangle, MonthCalendar mc) + { + Rectangle client_rectangle = mc.ClientRectangle; + Size month_size = mc.SingleMonthSize; + // cache local copies of Marshal-by-ref internal members (gets around error CS0197) + Size calendar_spacing = (Size)((object)mc.calendar_spacing); + Size date_cell_size = (Size)((object)mc.date_cell_size); + + // draw the singlecalendars + int x_offset = 1; + int y_offset = 1; + // adjust for the position of the specific month + for (int i=0; i < mc.CalendarDimensions.Height; i++) + { + if (i > 0) + { + y_offset += month_size.Height + calendar_spacing.Height; + } + // now adjust for x position + for (int j=0; j < mc.CalendarDimensions.Width; j++) + { + if (j > 0) + { + x_offset += month_size.Width + calendar_spacing.Width; + } + else + { + x_offset = 1; + } + + Rectangle month_rect = new Rectangle (x_offset, y_offset, month_size.Width, month_size.Height); + if (month_rect.IntersectsWith (clip_rectangle)) { + DrawSingleMonth ( + dc, + clip_rectangle, + month_rect, + mc, + i, + j); + } + } + } + + Rectangle bottom_rect = new Rectangle ( + client_rectangle.X, + Math.Max(client_rectangle.Bottom - date_cell_size.Height - 3, 0), + client_rectangle.Width, + date_cell_size.Height + 2); + // draw the today date if it's set + if (mc.ShowToday && bottom_rect.IntersectsWith (clip_rectangle)) + { + dc.FillRectangle (GetControlBackBrush (mc.BackColor), bottom_rect); + if (mc.ShowToday) { + int today_offset = 5; + if (mc.ShowTodayCircle) + { + Rectangle today_circle_rect = new Rectangle ( + client_rectangle.X + 5, + Math.Max(client_rectangle.Bottom - date_cell_size.Height - 2, 0), + date_cell_size.Width, + date_cell_size.Height); + DrawTodayCircle (dc, today_circle_rect); + today_offset += date_cell_size.Width + 5; + } + // draw today's date + StringFormat text_format = new StringFormat(); + text_format.LineAlignment = StringAlignment.Center; + text_format.Alignment = StringAlignment.Near; + Rectangle today_rect = new Rectangle ( + today_offset + client_rectangle.X, + Math.Max(client_rectangle.Bottom - date_cell_size.Height, 0), + Math.Max(client_rectangle.Width - today_offset, 0), + date_cell_size.Height); + dc.DrawString ("Today: " + DateTime.Now.ToShortDateString(), mc.bold_font, GetControlForeBrush (mc.ForeColor), today_rect, text_format); + text_format.Dispose (); + } + } + + Brush border_brush; + + if (mc.owner == null) + border_brush = GetControlBackBrush (mc.BackColor); + else + border_brush = SystemBrushes.ControlDarkDark; + + // finally paint the borders of the calendars as required + for (int i = 0; i <= mc.CalendarDimensions.Width; i++) { + if (i == 0 && clip_rectangle.X == client_rectangle.X) { + dc.FillRectangle (border_brush, client_rectangle.X, client_rectangle.Y, 1, client_rectangle.Height); + } else if (i == mc.CalendarDimensions.Width && clip_rectangle.Right == client_rectangle.Right) { + dc.FillRectangle (border_brush, client_rectangle.Right - 1, client_rectangle.Y, 1, client_rectangle.Height); + } else { + Rectangle rect = new Rectangle ( + client_rectangle.X + (month_size.Width*i) + (calendar_spacing.Width * (i-1)) + 1, + client_rectangle.Y, + calendar_spacing.Width, + client_rectangle.Height); + if (i < mc.CalendarDimensions.Width && i > 0 && clip_rectangle.IntersectsWith (rect)) { + dc.FillRectangle (border_brush, rect); + } + } + } + for (int i = 0; i <= mc.CalendarDimensions.Height; i++) { + if (i == 0 && clip_rectangle.Y == client_rectangle.Y) { + dc.FillRectangle (border_brush, client_rectangle.X, client_rectangle.Y, client_rectangle.Width, 1); + } else if (i == mc.CalendarDimensions.Height && clip_rectangle.Bottom == client_rectangle.Bottom) { + dc.FillRectangle (border_brush, client_rectangle.X, client_rectangle.Bottom - 1, client_rectangle.Width, 1); + } else { + Rectangle rect = new Rectangle ( + client_rectangle.X, + client_rectangle.Y + (month_size.Height*i) + (calendar_spacing.Height*(i-1)) + 1, + client_rectangle.Width, + calendar_spacing.Height); + if (i < mc.CalendarDimensions.Height && i > 0 && clip_rectangle.IntersectsWith (rect)) { + dc.FillRectangle (border_brush, rect); + } + } + } + + // draw the drop down border if need + if (mc.owner != null) { + Rectangle bounds = mc.ClientRectangle; + if (clip_rectangle.Contains (mc.Location)) { + // find out if top or left line to draw + if(clip_rectangle.Contains (new Point (bounds.Left, bounds.Bottom))) { + + dc.DrawLine (SystemPens.ControlText, bounds.X, bounds.Y, bounds.X, bounds.Bottom-1); + } + if(clip_rectangle.Contains (new Point (bounds.Right, bounds.Y))) { + dc.DrawLine (SystemPens.ControlText, bounds.X, bounds.Y, bounds.Right-1, bounds.Y); + } + } + if (clip_rectangle.Contains (new Point(bounds.Right, bounds.Bottom))) { + // find out if bottom or right line to draw + if(clip_rectangle.Contains (new Point (bounds.Left, bounds.Bottom))) { + dc.DrawLine (SystemPens.ControlText, bounds.X, bounds.Bottom-1, bounds.Right-1, bounds.Bottom-1); + } + if(clip_rectangle.Contains (new Point (bounds.Right, bounds.Y))) { + dc.DrawLine (SystemPens.ControlText, bounds.Right-1, bounds.Y, bounds.Right-1, bounds.Bottom-1); + } + } + } + } + + // darws a single part of the month calendar (with one month) + private void DrawSingleMonth(Graphics dc, Rectangle clip_rectangle, Rectangle rectangle, MonthCalendar mc, int row, int col) + { + // cache local copies of Marshal-by-ref internal members (gets around error CS0197) + Size title_size = (Size)((object)mc.title_size); + Size date_cell_size = (Size)((object)mc.date_cell_size); + DateTime current_month = (DateTime)((object)mc.current_month); + DateTime sunday = new DateTime(2006, 10, 1); + + // draw the title back ground + DateTime this_month = current_month.AddMonths (row*mc.CalendarDimensions.Width+col); + Rectangle title_rect = new Rectangle(rectangle.X, rectangle.Y, title_size.Width, title_size.Height); + if (title_rect.IntersectsWith (clip_rectangle)) { + dc.FillRectangle (ResPool.GetSolidBrush (mc.TitleBackColor), title_rect); + // draw the title + string title_text = this_month.ToString ("MMMM yyyy"); + dc.DrawString (title_text, mc.bold_font, ResPool.GetSolidBrush (mc.TitleForeColor), title_rect, mc.centered_format); + + if (mc.ShowYearUpDown) { + Rectangle year_rect; + Rectangle upRect, downRect; + ButtonState upState, downState; + + mc.GetYearNameRectangles (title_rect, row * mc.CalendarDimensions.Width + col, out year_rect, out upRect, out downRect); + dc.FillRectangle (ResPool.GetSolidBrush (SystemColors.Control), year_rect); + dc.DrawString (this_month.ToString ("yyyy"), mc.bold_font, ResPool.GetSolidBrush (Color.Black), year_rect, mc.centered_format); + + upState = mc.IsYearGoingUp ? ButtonState.Pushed : ButtonState.Normal; + downState = mc.IsYearGoingDown ? ButtonState.Pushed : ButtonState.Normal; + + WidgetPaint.DrawScrollButton (dc, upRect, ScrollButton.Up, upState); + WidgetPaint.DrawScrollButton (dc, downRect, ScrollButton.Down, downState); + } + + // draw previous and next buttons if it's time + if (row == 0 && col == 0) + { + // draw previous button + DrawMonthCalendarButton ( + dc, + rectangle, + mc, + title_size, + mc.button_x_offset, + (System.Drawing.Size)((object)mc.button_size), + true); + } + if (row == 0 && col == mc.CalendarDimensions.Width-1) + { + // draw next button + DrawMonthCalendarButton ( + dc, + rectangle, + mc, + title_size, + mc.button_x_offset, + (System.Drawing.Size)((object)mc.button_size), + false); + } + } + + // set the week offset and draw week nums if needed + int col_offset = (mc.ShowWeekNumbers) ? 1 : 0; + Rectangle day_name_rect = new Rectangle( + rectangle.X, + rectangle.Y + title_size.Height, + (7 + col_offset) * date_cell_size.Width, + date_cell_size.Height); + if (day_name_rect.IntersectsWith (clip_rectangle)) { + dc.FillRectangle (GetControlBackBrush (mc.BackColor), day_name_rect); + // draw the day names + DayOfWeek first_day_of_week = mc.GetDayOfWeek(mc.FirstDayOfWeek); + for (int i=0; i < 7; i++) + { + int position = i - (int) first_day_of_week; + if (position < 0) + { + position = 7 + position; + } + // draw it + Rectangle day_rect = new Rectangle( + day_name_rect.X + ((i + col_offset)* date_cell_size.Width), + day_name_rect.Y, + date_cell_size.Width, + date_cell_size.Height); + dc.DrawString (sunday.AddDays (i + (int) first_day_of_week).ToString ("ddd"), mc.Font, ResPool.GetSolidBrush (mc.TitleBackColor), day_rect, mc.centered_format); + } + + // draw the vertical divider + int vert_divider_y = Math.Max(title_size.Height+ date_cell_size.Height-1, 0); + dc.DrawLine ( + ResPool.GetPen (mc.ForeColor), + rectangle.X + (col_offset * date_cell_size.Width) + mc.divider_line_offset, + rectangle.Y + vert_divider_y, + rectangle.Right - mc.divider_line_offset, + rectangle.Y + vert_divider_y); + } + + + // draw the actual date items in the grid (including the week numbers) + Rectangle date_rect = new Rectangle ( + rectangle.X, + rectangle.Y + title_size.Height + date_cell_size.Height, + date_cell_size.Width, + date_cell_size.Height); + int month_row_count = 0; + bool draw_week_num_divider = false; + DateTime current_date = mc.GetFirstDateInMonthGrid ( new DateTime (this_month.Year, this_month.Month, 1)); + for (int i=0; i < 6; i++) + { + // establish if this row is in our clip_area + Rectangle row_rect = new Rectangle ( + rectangle.X, + rectangle.Y + title_size.Height + (date_cell_size.Height * (i+1)), + date_cell_size.Width * 7, + date_cell_size.Height); + if (mc.ShowWeekNumbers) { + row_rect.Width += date_cell_size.Width; + } + + bool draw_row = row_rect.IntersectsWith (clip_rectangle); + if (draw_row) { + dc.FillRectangle (GetControlBackBrush (mc.BackColor), row_rect); + } + // establish if this is a valid week to draw + if (mc.IsValidWeekToDraw (this_month, current_date, row, col)) { + month_row_count = i; + } + + // draw the week number if required + if (mc.ShowWeekNumbers && month_row_count == i) { + if (!draw_week_num_divider) { + draw_week_num_divider = draw_row; + } + // get the week for this row + int week = mc.GetWeekOfYear (current_date); + + if (draw_row) { + dc.DrawString ( + week.ToString(), + mc.Font, + ResPool.GetSolidBrush (mc.TitleBackColor), + date_rect, + mc.centered_format); + } + date_rect.Offset(date_cell_size.Width, 0); + } + + // only draw the days if we have to + if(month_row_count == i) { + for (int j=0; j < 7; j++) + { + if (draw_row) { + DrawMonthCalendarDate ( + dc, + date_rect, + mc, + current_date, + this_month, + row, + col); + } + + // move the day on + current_date = current_date.AddDays(1); + date_rect.Offset(date_cell_size.Width, 0); + } + + // shift the rectangle down one row + int offset = (mc.ShowWeekNumbers) ? -8 : -7; + date_rect.Offset(offset*date_cell_size.Width, date_cell_size.Height); + } + } + + // month_row_count is zero based, so add one + month_row_count++; + + // draw week numbers if required + if (draw_week_num_divider) { + col_offset = 1; + dc.DrawLine ( + ResPool.GetPen (mc.ForeColor), + rectangle.X + date_cell_size.Width - 1, + rectangle.Y + title_size.Height + date_cell_size.Height + mc.divider_line_offset, + rectangle.X + date_cell_size.Width - 1, + rectangle.Y + title_size.Height + date_cell_size.Height + (month_row_count * date_cell_size.Height) - mc.divider_line_offset); + } + } + + // draws the pervious or next button + private void DrawMonthCalendarButton (Graphics dc, Rectangle rectangle, MonthCalendar mc, Size title_size, int x_offset, Size button_size, bool is_previous) + { + const int arrow_width = 4; + const int arrow_height = 7; + + bool is_clicked = false; + Rectangle button_rect; + PointF arrow_center; + PointF [] arrow_path = new PointF [3]; + + // prepare the button + if (is_previous) + { + is_clicked = mc.is_previous_clicked; + + button_rect = new Rectangle ( + rectangle.X + 1 + x_offset, + rectangle.Y + 1 + ((title_size.Height - button_size.Height)/2), + Math.Max(button_size.Width - 1, 0), + Math.Max(button_size.Height - 1, 0)); + + arrow_center = new PointF (button_rect.X + ((button_rect.Width + arrow_width) / 2.0f), + rectangle.Y + ((button_rect.Height + arrow_height) / 2) + 1); + if (is_clicked) { + arrow_center.X += 1; + arrow_center.Y += 1; + } + + arrow_path [0].X = arrow_center.X; + arrow_path [0].Y = arrow_center.Y - arrow_height / 2.0f + 0.5f; + arrow_path [1].X = arrow_center.X; + arrow_path [1].Y = arrow_center.Y + arrow_height / 2.0f + 0.5f; + arrow_path [2].X = arrow_center.X - arrow_width; + arrow_path [2].Y = arrow_center.Y + 0.5f; + } + else + { + is_clicked = mc.is_next_clicked; + + button_rect = new Rectangle ( + rectangle.Right - 1 - x_offset - button_size.Width, + rectangle.Y + 1 + ((title_size.Height - button_size.Height)/2), + Math.Max(button_size.Width - 1, 0), + Math.Max(button_size.Height - 1, 0)); + + arrow_center = new PointF (button_rect.X + ((button_rect.Width + arrow_width) / 2.0f), + rectangle.Y + ((button_rect.Height + arrow_height) / 2) + 1); + if (is_clicked) { + arrow_center.X += 1; + arrow_center.Y += 1; + } + + arrow_path [0].X = arrow_center.X - arrow_width; + arrow_path [0].Y = arrow_center.Y - arrow_height / 2.0f + 0.5f; + arrow_path [1].X = arrow_center.X - arrow_width; + arrow_path [1].Y = arrow_center.Y + arrow_height / 2.0f + 0.5f; + arrow_path [2].X = arrow_center.X; + arrow_path [2].Y = arrow_center.Y + 0.5f; + } + + // fill the background + dc.FillRectangle (SystemBrushes.Control, button_rect); + // draw the border + if (is_clicked) { + dc.DrawRectangle (SystemPens.ControlDark, button_rect); + } + else { + CPDrawBorder3D (dc, button_rect, Border3DStyle.Raised, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom); + } + // draw the arrow + dc.FillPolygon (SystemBrushes.ControlText, arrow_path); + //dc.FillPolygon (SystemBrushes.ControlText, arrow_path, FillMode.Winding); + } + + + // draws one day in the calendar grid + private void DrawMonthCalendarDate (Graphics dc, Rectangle rectangle, MonthCalendar mc, DateTime date, DateTime month, int row, int col) { + Color date_color = mc.ForeColor; + Rectangle interior = new Rectangle (rectangle.X, rectangle.Y, Math.Max(rectangle.Width - 1, 0), Math.Max(rectangle.Height - 1, 0)); + + // find out if we are the lead of the first calendar or the trail of the last calendar + if (date.Year != month.Year || date.Month != month.Month) { + DateTime check_date = month.AddMonths (-1); + // check if it's the month before + if (check_date.Year == date.Year && check_date.Month == date.Month && row == 0 && col == 0) { + date_color = mc.TrailingForeColor; + } else { + // check if it's the month after + check_date = month.AddMonths (1); + if (check_date.Year == date.Year && check_date.Month == date.Month && row == mc.CalendarDimensions.Height-1 && col == mc.CalendarDimensions.Width-1) { + date_color = mc.TrailingForeColor; + } else { + return; + } + } + } else { + date_color = mc.ForeColor; + } + + const int inflate = -1; + + if (date == mc.SelectionStart.Date && date == mc.SelectionEnd.Date) { + // see if the date is in the start of selection + date_color = mc.BackColor; + // draw the left hand of the back ground + Rectangle selection_rect = Rectangle.Inflate (rectangle, inflate, inflate); + dc.FillPie (ResPool.GetSolidBrush (mc.TitleBackColor), selection_rect, 0, 360); + } else if (date == mc.SelectionStart.Date) { + // see if the date is in the start of selection + date_color = mc.BackColor; + // draw the left hand of the back ground + Rectangle selection_rect = Rectangle.Inflate (rectangle, inflate, inflate); + dc.FillPie (ResPool.GetSolidBrush (mc.TitleBackColor), selection_rect, 90, 180); + // fill the other side as a straight rect + if (date < mc.SelectionEnd.Date) + { + // use rectangle instead of rectangle to go all the way to edge of rect + selection_rect.X = (int) Math.Floor((double)(rectangle.X + rectangle.Width / 2)); + selection_rect.Width = Math.Max(rectangle.Right - selection_rect.X, 0); + dc.FillRectangle (ResPool.GetSolidBrush (mc.TitleBackColor), selection_rect); + } + } else if (date == mc.SelectionEnd.Date) { + // see if it is the end of selection + date_color = mc.BackColor; + // draw the left hand of the back ground + Rectangle selection_rect = Rectangle.Inflate (rectangle, inflate, inflate); + dc.FillPie (ResPool.GetSolidBrush (mc.TitleBackColor), selection_rect, 270, 180); + // fill the other side as a straight rect + if (date > mc.SelectionStart.Date) { + selection_rect.X = rectangle.X; + selection_rect.Width = rectangle.Width - (rectangle.Width / 2); + dc.FillRectangle (ResPool.GetSolidBrush (mc.TitleBackColor), selection_rect); + } + } else if (date > mc.SelectionStart.Date && date < mc.SelectionEnd.Date) { + // now see if it's in the middle + date_color = mc.BackColor; + // draw the left hand of the back ground + Rectangle selection_rect = Rectangle.Inflate (rectangle, 0, inflate); + dc.FillRectangle (ResPool.GetSolidBrush (mc.TitleBackColor), selection_rect); + } + + // establish if it's a bolded font + Font font = mc.IsBoldedDate (date) ? mc.bold_font : mc.Font; + + // just draw the date now + dc.DrawString (date.Day.ToString(), font, ResPool.GetSolidBrush (date_color), rectangle, mc.centered_format); + + // today circle if needed + if (mc.ShowTodayCircle && date == DateTime.Now.Date) { + DrawTodayCircle (dc, interior); + } + + // draw the selection grid + if (mc.is_date_clicked && mc.clicked_date == date) { + Pen pen = ResPool.GetDashPen (Color.Black, DashStyle.Dot); + dc.DrawRectangle (pen, interior); + } + } + + private void DrawTodayCircle (Graphics dc, Rectangle rectangle) { + Color circle_color = Color.FromArgb (248, 0, 0); + // draw the left hand of the circle + Rectangle lhs_circle_rect = new Rectangle (rectangle.X + 1, rectangle.Y + 4, Math.Max(rectangle.Width - 2, 0), Math.Max(rectangle.Height - 5, 0)); + Rectangle rhs_circle_rect = new Rectangle (rectangle.X + 1, rectangle.Y + 1, Math.Max(rectangle.Width - 2, 0), Math.Max(rectangle.Height - 2, 0)); + Point [] curve_points = new Point [3]; + curve_points [0] = new Point (lhs_circle_rect.X, rhs_circle_rect.Y + rhs_circle_rect.Height/12); + curve_points [1] = new Point (lhs_circle_rect.X + lhs_circle_rect.Width/9, rhs_circle_rect.Y); + curve_points [2] = new Point (lhs_circle_rect.X + lhs_circle_rect.Width/2 + 1, rhs_circle_rect.Y); + + Pen pen = ResPool.GetSizedPen(circle_color, 2); + dc.DrawArc (pen, lhs_circle_rect, 90, 180); + dc.DrawArc (pen, rhs_circle_rect, 270, 180); + dc.DrawCurve (pen, curve_points); + dc.DrawLine (ResPool.GetPen (circle_color), curve_points [2], new Point (curve_points [2].X, lhs_circle_rect.Y)); + } + + #endregion // MonthCalendar + + #region Panel + public override Size PanelDefaultSize { + get { + return new Size (200, 100); + } + } + #endregion // Panel + + #region PictureBox + public override void DrawPictureBox (Graphics dc, Rectangle clip, PictureBox pb) { + Rectangle client = pb.ClientRectangle; + + client = new Rectangle (client.Left + pb.Padding.Left, client.Top + pb.Padding.Top, client.Width - pb.Padding.Horizontal, client.Height - pb.Padding.Vertical); + + // FIXME - instead of drawing the whole picturebox every time + // intersect the clip rectangle with the drawn picture and only draw what's needed, + // Also, we only need a background fill where no image goes + if (pb.Image != null) { + switch (pb.SizeMode) { + case PictureBoxSizeMode.StretchImage: + dc.DrawImage (pb.Image, client.Left, client.Top, client.Width, client.Height); + break; + + case PictureBoxSizeMode.CenterImage: + dc.DrawImage (pb.Image, (client.Width / 2) - (pb.Image.Width / 2), (client.Height / 2) - (pb.Image.Height / 2)); + break; + + case PictureBoxSizeMode.Zoom: + Size image_size; + + if (((float)pb.Image.Width / (float)pb.Image.Height) >= ((float)client.Width / (float)client.Height)) + image_size = new Size (client.Width, (pb.Image.Height * client.Width) / pb.Image.Width); + else + image_size = new Size ((pb.Image.Width * client.Height) / pb.Image.Height, client.Height); + + dc.DrawImage (pb.Image, (client.Width / 2) - (image_size.Width / 2), (client.Height / 2) - (image_size.Height / 2), image_size.Width, image_size.Height); + break; + + default: + // Normal, AutoSize + dc.DrawImage (pb.Image, client.Left, client.Top, pb.Image.Width, pb.Image.Height); + break; + } + + return; + } + } + + public override Size PictureBoxDefaultSize { + get { + return new Size (100, 50); + } + } + #endregion // PictureBox + + /* + #region PrintPreviewControl + public override int PrintPreviewControlPadding { + get { return 8; } + } + + public override Size PrintPreviewControlGetPageSize (PrintPreviewControl preview) + { + int page_width, page_height; + int padding = PrintPreviewControlPadding; + PreviewPageInfo[] pis = preview.page_infos; + + if (preview.AutoZoom) { + int height_available = preview.ClientRectangle.Height - (preview.Rows) * padding - 2 * padding; + int width_available = preview.ClientRectangle.Width - (preview.Columns - 1) * padding - 2 * padding; + + float image_ratio = (float)pis[0].Image.Width / pis[0].Image.Height; + + /* try to lay things out using the width to determine the size + page_width = width_available / preview.Columns; + page_height = (int)(page_width / image_ratio); + + /* does the height fit? + if (page_height * (preview.Rows + 1) > height_available) { + /* no, lay things out via the height + page_height = height_available / (preview.Rows + 1); + page_width = (int)(page_height * image_ratio); + } + } + else { + page_width = (int)(pis[0].Image.Width * preview.Zoom); + page_height = (int)(pis[0].Image.Height * preview.Zoom); + } + + return new Size (page_width, page_height); + } + + public override void PrintPreviewWidgetPaint (PaintEventArgs pe, PrintPreviewControl preview, Size page_size) + { + int padding = 8; + PreviewPageInfo[] pis = preview.page_infos; + if (pis == null) + return; + + int page_x, page_y; + + int width = page_size.Width * preview.Columns + padding * (preview.Columns - 1) + 2 * padding; + int height = page_size.Height * (preview.Rows + 1) + padding * preview.Rows + 2 * padding; + + Rectangle viewport = preview.ViewPort; + + pe.Graphics.Clip = new Region (viewport); + + /* center things if we can + int off_x = viewport.Width / 2 - width / 2; + if (off_x < 0) off_x = 0; + int off_y = viewport.Height / 2 - height / 2; + if (off_y < 0) off_y = 0; + + page_y = off_y + padding - preview.vbar_value; + + if (preview.StartPage > 0) { + int p = preview.StartPage - 1; + for (int py = 0; py < preview.Rows + 1; py ++) { + page_x = off_x + padding - preview.hbar_value; + for (int px = 0; px < preview.Columns; px ++) { + if (p >= pis.Length) + continue; + Image image = preview.image_cache[p]; + if (image == null) + image = pis[p].Image; + Rectangle dest = new Rectangle (new Point (page_x, page_y), page_size); + + pe.Graphics.DrawImage (image, dest, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel); + + page_x += padding + page_size.Width; + p++; + } + page_y += padding + page_size.Height; + } + } + } + #endregion // PrintPreviewControl*/ + + #region ProgressBar + public override void DrawProgressBar (Graphics dc, Rectangle clip_rect, ProgressBar ctrl) + { + Rectangle client_area = ctrl.client_area; + + /* Draw border */ + CPDrawBorder3D (dc, ctrl.ClientRectangle, Border3DStyle.SunkenOuter, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom & ~Border3DSide.Middle, ColorControl); + + /* Draw Blocks */ + int draw_mode = 0; + int max_blocks = int.MaxValue; + int start_pixel = client_area.X; + draw_mode = (int) ctrl.Style; + + switch (draw_mode) { + case 1: { // Continuous + int pixels_to_draw; + pixels_to_draw = (int)(client_area.Width * ((double)(ctrl.Value - ctrl.Minimum) / (double)(Math.Max(ctrl.Maximum - ctrl.Minimum, 1)))); + dc.FillRectangle (ResPool.GetSolidBrush (ctrl.ForeColor), new Rectangle (client_area.X, client_area.Y, pixels_to_draw, client_area.Height)); + break; + } + case 2: // Marquee + if (XplatUI.ThemesEnabled) { + int ms_diff = (int) (DateTime.Now - ctrl.start).TotalMilliseconds; + double percent_done = (double) ms_diff / ProgressBarMarqueeSpeedScaling + % (double)ctrl.MarqueeAnimationSpeed / (double)ctrl.MarqueeAnimationSpeed; + max_blocks = 5; + start_pixel = client_area.X + (int) (client_area.Width * percent_done); + } + + goto case 0; + case 0: + default: // Blocks + Rectangle block_rect; + int space_betweenblocks = ProgressBarChunkSpacing; + int block_width; + int increment; + int barpos_pixels; + int block_count = 0; + + block_width = ProgressBarGetChunkSize (client_area.Height); + block_width = Math.Max (block_width, 0); // block_width is used to break out the loop below, it must be >= 0! + barpos_pixels = (int)(((double)(ctrl.Value - ctrl.Minimum) * client_area.Width) / (Math.Max (ctrl.Maximum - ctrl.Minimum, 1))); + increment = block_width + space_betweenblocks; + + block_rect = new Rectangle (start_pixel, client_area.Y, block_width, client_area.Height); + while (true) { + if (max_blocks != int.MaxValue) { + if (block_count >= max_blocks) + break; + if (block_rect.X > client_area.Width) + block_rect.X -= client_area.Width; + } else { + if ((block_rect.X - client_area.X) >= barpos_pixels) + break; + } + + if (clip_rect.IntersectsWith (block_rect) == true) { + dc.FillRectangle (ResPool.GetSolidBrush (ctrl.ForeColor), block_rect); + } + + block_rect.X += increment; + block_count++; + } + break; + + } + } + + public const int ProgressBarChunkSpacing = 2; + + public static int ProgressBarGetChunkSize () + { + return ProgressBarGetChunkSize (ProgressBarDefaultHeight); + } + + static int ProgressBarGetChunkSize (int progressBarClientAreaHeight) + { + int size = (progressBarClientAreaHeight * 2) / 3; + return size; + } + + const int ProgressBarDefaultHeight = 23; + + public override Size ProgressBarDefaultSize { + get { + return new Size (100, ProgressBarDefaultHeight); + } + } + + public const double ProgressBarMarqueeSpeedScaling = 15; + + #endregion // ProgressBar + + #region RadioButton + public override void DrawRadioButton (Graphics dc, Rectangle clip_rectangle, RadioButton radio_button) { + StringFormat text_format; + Rectangle client_rectangle; + Rectangle text_rectangle; + Rectangle radiobutton_rectangle; + int radiobutton_size = 13; + int radiobutton_space = 4; + + client_rectangle = radio_button.ClientRectangle; + text_rectangle = client_rectangle; + radiobutton_rectangle = new Rectangle(text_rectangle.X, text_rectangle.Y, radiobutton_size, radiobutton_size); + + text_format = new StringFormat(); + text_format.Alignment = StringAlignment.Near; + text_format.LineAlignment = StringAlignment.Center; + text_format.HotkeyPrefix = HotkeyPrefix.Show; + + /* Calculate the position of text and checkbox rectangle */ + if (radio_button.appearance!=Appearance.Button) { + switch(radio_button.radiobutton_alignment) { + case ContentAlignment.BottomCenter: { + radiobutton_rectangle.X=(client_rectangle.Right-client_rectangle.Left)/2-radiobutton_size/2; + radiobutton_rectangle.Y=client_rectangle.Bottom-radiobutton_size; + text_rectangle.X=client_rectangle.X; + text_rectangle.Width=client_rectangle.Width; + text_rectangle.Height=client_rectangle.Height-radiobutton_size-radiobutton_space; + break; + } + + case ContentAlignment.BottomLeft: { + radiobutton_rectangle.X=client_rectangle.Left; + radiobutton_rectangle.Y=client_rectangle.Bottom-radiobutton_size; + text_rectangle.X=client_rectangle.X+radiobutton_size+radiobutton_space; + text_rectangle.Width=client_rectangle.Width-radiobutton_size-radiobutton_space; + break; + } + + case ContentAlignment.BottomRight: { + radiobutton_rectangle.X=client_rectangle.Right-radiobutton_size; + radiobutton_rectangle.Y=client_rectangle.Bottom-radiobutton_size; + text_rectangle.X=client_rectangle.X; + text_rectangle.Width=client_rectangle.Width-radiobutton_size-radiobutton_space; + break; + } + + case ContentAlignment.MiddleCenter: { + radiobutton_rectangle.X=(client_rectangle.Right-client_rectangle.Left)/2-radiobutton_size/2; + radiobutton_rectangle.Y=(client_rectangle.Bottom-client_rectangle.Top)/2-radiobutton_size/2; + text_rectangle.X=client_rectangle.X; + text_rectangle.Width=client_rectangle.Width; + break; + } + + default: + case ContentAlignment.MiddleLeft: { + radiobutton_rectangle.X=client_rectangle.Left; + radiobutton_rectangle.Y=(client_rectangle.Bottom-client_rectangle.Top)/2-radiobutton_size/2; + text_rectangle.X=client_rectangle.X+radiobutton_size+radiobutton_space; + text_rectangle.Width=client_rectangle.Width-radiobutton_size-radiobutton_space; + break; + } + + case ContentAlignment.MiddleRight: { + radiobutton_rectangle.X=client_rectangle.Right-radiobutton_size; + radiobutton_rectangle.Y=(client_rectangle.Bottom-client_rectangle.Top)/2-radiobutton_size/2; + text_rectangle.X=client_rectangle.X; + text_rectangle.Width=client_rectangle.Width-radiobutton_size-radiobutton_space; + break; + } + + case ContentAlignment.TopCenter: { + radiobutton_rectangle.X=(client_rectangle.Right-client_rectangle.Left)/2-radiobutton_size/2; + radiobutton_rectangle.Y=client_rectangle.Top; + text_rectangle.X=client_rectangle.X; + text_rectangle.Y=radiobutton_size+radiobutton_space; + text_rectangle.Width=client_rectangle.Width; + text_rectangle.Height=client_rectangle.Height-radiobutton_size-radiobutton_space; + break; + } + + case ContentAlignment.TopLeft: { + radiobutton_rectangle.X=client_rectangle.Left; + radiobutton_rectangle.Y=client_rectangle.Top; + text_rectangle.X=client_rectangle.X+radiobutton_size+radiobutton_space; + text_rectangle.Width=client_rectangle.Width-radiobutton_size-radiobutton_space; + break; + } + + case ContentAlignment.TopRight: { + radiobutton_rectangle.X=client_rectangle.Right-radiobutton_size; + radiobutton_rectangle.Y=client_rectangle.Top; + text_rectangle.X=client_rectangle.X; + text_rectangle.Width=client_rectangle.Width-radiobutton_size-radiobutton_space; + break; + } + } + } else { + text_rectangle.X=client_rectangle.X; + text_rectangle.Width=client_rectangle.Width; + } + + /* Set the horizontal alignment of our text */ + switch(radio_button.text_alignment) { + case ContentAlignment.BottomLeft: + case ContentAlignment.MiddleLeft: + case ContentAlignment.TopLeft: { + text_format.Alignment=StringAlignment.Near; + break; + } + + case ContentAlignment.BottomCenter: + case ContentAlignment.MiddleCenter: + case ContentAlignment.TopCenter: { + text_format.Alignment=StringAlignment.Center; + break; + } + + case ContentAlignment.BottomRight: + case ContentAlignment.MiddleRight: + case ContentAlignment.TopRight: { + text_format.Alignment=StringAlignment.Far; + break; + } + } + + /* Set the vertical alignment of our text */ + switch(radio_button.text_alignment) { + case ContentAlignment.TopLeft: + case ContentAlignment.TopCenter: + case ContentAlignment.TopRight: { + text_format.LineAlignment=StringAlignment.Near; + break; + } + + case ContentAlignment.BottomLeft: + case ContentAlignment.BottomCenter: + case ContentAlignment.BottomRight: { + text_format.LineAlignment=StringAlignment.Far; + break; + } + + case ContentAlignment.MiddleLeft: + case ContentAlignment.MiddleCenter: + case ContentAlignment.MiddleRight: { + text_format.LineAlignment=StringAlignment.Center; + break; + } + } + + ButtonState state = ButtonState.Normal; + if (radio_button.FlatStyle == FlatStyle.Flat) { + state |= ButtonState.Flat; + } + + if (radio_button.Checked) { + state |= ButtonState.Checked; + } + + if (!radio_button.Enabled) { + state |= ButtonState.Inactive; + } + + // Start drawing + RadioButton_DrawButton(radio_button, dc, state, radiobutton_rectangle); + + if ((radio_button.image != null) || (radio_button.image_list != null)) + ButtonBase_DrawImage(radio_button, dc); + + RadioButton_DrawText(radio_button, text_rectangle, dc, text_format); + + if (radio_button.Focused && radio_button.Enabled && radio_button.appearance != Appearance.Button && radio_button.Text != String.Empty && radio_button.ShowFocusCues) { + SizeF text_size = dc.MeasureString (radio_button.Text, radio_button.Font); + + Rectangle focus_rect = Rectangle.Empty; + focus_rect.X = text_rectangle.X; + focus_rect.Y = (int)((text_rectangle.Height - text_size.Height) / 2); + focus_rect.Size = text_size.ToSize (); + + RadioButton_DrawFocus (radio_button, dc, focus_rect); + } + + text_format.Dispose (); + } + + protected virtual void RadioButton_DrawButton(RadioButton radio_button, Graphics dc, ButtonState state, Rectangle radiobutton_rectangle) + { + dc.FillRectangle(GetControlBackBrush (radio_button.BackColor), radio_button.ClientRectangle); + + if (radio_button.appearance==Appearance.Button) { + ButtonBase_DrawButton (radio_button, dc); + + if ((radio_button.Focused) && radio_button.Enabled) + ButtonBase_DrawFocus(radio_button, dc); + } else { + // establish if we are rendering a flat style of some sort + if (radio_button.FlatStyle == FlatStyle.Flat || radio_button.FlatStyle == FlatStyle.Popup) { + DrawFlatStyleRadioButton (dc, radiobutton_rectangle, radio_button); + } else { + CPDrawRadioButton(dc, radiobutton_rectangle, state); + } + } + } + + protected virtual void RadioButton_DrawText(RadioButton radio_button, Rectangle text_rectangle, Graphics dc, StringFormat text_format) + { + DrawCheckBox_and_RadioButtonText (radio_button, text_rectangle, dc, + text_format, radio_button.Appearance, radio_button.Checked); + } + + protected virtual void RadioButton_DrawFocus(RadioButton radio_button, Graphics dc, Rectangle text_rectangle) + { + DrawInnerFocusRectangle (dc, text_rectangle, radio_button.BackColor); + } + + + // renders a radio button with the Flat and Popup FlatStyle + protected virtual void DrawFlatStyleRadioButton (Graphics graphics, Rectangle rectangle, RadioButton radio_button) + { + int lineWidth; + + if (radio_button.Enabled) { + + // draw the outer flatstyle arcs + if (radio_button.FlatStyle == FlatStyle.Flat) { + graphics.DrawArc (SystemPens.ControlDarkDark, rectangle, 0, 359); + + // fill in the area depending on whether or not the mouse is hovering + if ((radio_button.is_entered || radio_button.Capture) && !radio_button.is_pressed) { + graphics.FillPie (SystemBrushes.ControlLight, rectangle.X + 1, rectangle.Y + 1, rectangle.Width - 2, rectangle.Height - 2, 0, 359); + } else { + graphics.FillPie (SystemBrushes.ControlLightLight, rectangle.X + 1, rectangle.Y + 1, rectangle.Width - 2, rectangle.Height - 2, 0, 359); + } + } else { + // must be a popup radio button + // fill the control + graphics.FillPie (SystemBrushes.ControlLightLight, rectangle, 0, 359); + + if (radio_button.is_entered || radio_button.Capture) { + // draw the popup 3d button knob + graphics.DrawArc (SystemPens.ControlLight, rectangle.X+1, rectangle.Y+1, rectangle.Width-2, rectangle.Height-2, 0, 359); + + graphics.DrawArc (SystemPens.ControlDark, rectangle, 135, 180); + graphics.DrawArc (SystemPens.ControlLightLight, rectangle, 315, 180); + + } else { + // just draw lighter flatstyle outer circle + graphics.DrawArc (SystemPens.ControlDark, rectangle, 0, 359); + } + } + } else { + // disabled + // fill control background color regardless of actual backcolor + graphics.FillPie (SystemBrushes.Control, rectangle.X + 1, rectangle.Y + 1, rectangle.Width - 2, rectangle.Height - 2, 0, 359); + // draw the ark as control dark + graphics.DrawArc (SystemPens.ControlDark, rectangle, 0, 359); + } + + // draw the check + if (radio_button.Checked) { + lineWidth = Math.Max (1, Math.Min(rectangle.Width, rectangle.Height)/3); + + Pen dot_pen = SystemPens.ControlDarkDark; + Brush dot_brush = SystemBrushes.ControlDarkDark; + + if (!radio_button.Enabled || ((radio_button.FlatStyle == FlatStyle.Popup) && radio_button.is_pressed)) { + dot_pen = SystemPens.ControlDark; + dot_brush = SystemBrushes.ControlDark; + } + + if (rectangle.Height > 13) { + graphics.FillPie (dot_brush, rectangle.X + lineWidth, rectangle.Y + lineWidth, rectangle.Width - lineWidth * 2, rectangle.Height - lineWidth * 2, 0, 359); + } else { + int x_half_pos = (rectangle.Width / 2) + rectangle.X; + int y_half_pos = (rectangle.Height / 2) + rectangle.Y; + + graphics.DrawLine (dot_pen, x_half_pos - 1, y_half_pos, x_half_pos + 2, y_half_pos); + graphics.DrawLine (dot_pen, x_half_pos - 1, y_half_pos + 1, x_half_pos + 2, y_half_pos + 1); + + graphics.DrawLine (dot_pen, x_half_pos, y_half_pos - 1, x_half_pos, y_half_pos + 2); + graphics.DrawLine (dot_pen, x_half_pos + 1, y_half_pos - 1, x_half_pos + 1, y_half_pos + 2); + } + } + } + + public override Size RadioButtonDefaultSize { + get { + return new Size (104,24); + } + } + + public override void DrawRadioButton (Graphics g, RadioButton rb, Rectangle glyphArea, Rectangle textBounds, Rectangle imageBounds, Rectangle clipRectangle) + { + // Draw Button Background + if (rb.FlatStyle == FlatStyle.Flat || rb.FlatStyle == FlatStyle.Popup) { + glyphArea.Height -= 2; + glyphArea.Width -= 2; + } + + DrawRadioButtonGlyph (g, rb, glyphArea); + + // If we have an image, draw it + if (imageBounds.Size != Size.Empty) + DrawRadioButtonImage (g, rb, imageBounds); + + if (rb.Focused && rb.Enabled && rb.ShowFocusCues && textBounds.Size != Size.Empty) + DrawRadioButtonFocus (g, rb, textBounds); + + // If we have text, draw it + if (textBounds != Rectangle.Empty) + DrawRadioButtonText (g, rb, textBounds); + } + + public virtual void DrawRadioButtonGlyph (Graphics g, RadioButton rb, Rectangle glyphArea) + { + if (rb.Pressed) + ThemeElements.CurrentTheme.RadioButtonPainter.PaintRadioButton (g, glyphArea, rb.BackColor, rb.ForeColor, ElementState.Pressed, rb.FlatStyle, rb.Checked); + else if (rb.InternalSelected) + ThemeElements.CurrentTheme.RadioButtonPainter.PaintRadioButton (g, glyphArea, rb.BackColor, rb.ForeColor, ElementState.Normal, rb.FlatStyle, rb.Checked); + else if (rb.Entered) + ThemeElements.CurrentTheme.RadioButtonPainter.PaintRadioButton (g, glyphArea, rb.BackColor, rb.ForeColor, ElementState.Hot, rb.FlatStyle, rb.Checked); + else if (!rb.Enabled) + ThemeElements.CurrentTheme.RadioButtonPainter.PaintRadioButton (g, glyphArea, rb.BackColor, rb.ForeColor, ElementState.Disabled, rb.FlatStyle, rb.Checked); + else + ThemeElements.CurrentTheme.RadioButtonPainter.PaintRadioButton (g, glyphArea, rb.BackColor, rb.ForeColor, ElementState.Normal, rb.FlatStyle, rb.Checked); + } + + public virtual void DrawRadioButtonFocus (Graphics g, RadioButton rb, Rectangle focusArea) + { + WidgetPaint.DrawFocusRectangle (g, focusArea); + } + + public virtual void DrawRadioButtonImage (Graphics g, RadioButton rb, Rectangle imageBounds) + { + if (rb.Enabled) + g.DrawImage (rb.Image, imageBounds); + else + CPDrawImageDisabled (g, rb.Image, imageBounds.Left, imageBounds.Top, ColorControl); + } + + public virtual void DrawRadioButtonText (Graphics g, RadioButton rb, Rectangle textBounds) + { + if (rb.Enabled) + TextRenderer.DrawTextInternal (g, rb.Text, rb.Font, textBounds, rb.ForeColor, rb.TextFormatFlags, rb.UseCompatibleTextRendering); + else + DrawStringDisabled20 (g, rb.Text, rb.Font, textBounds, rb.BackColor, rb.TextFormatFlags, rb.UseCompatibleTextRendering); + } + + public override Size CalculateRadioButtonAutoSize (RadioButton rb) + { + Size ret_size = Size.Empty; + Size text_size = TextRenderer.MeasureTextInternal (rb.Text, rb.Font, rb.UseCompatibleTextRendering); + Size image_size = rb.Image == null ? Size.Empty : rb.Image.Size; + + // Pad the text size + if (rb.Text.Length != 0) { + text_size.Height += 4; + text_size.Width += 4; + } + + switch (rb.TextImageRelation) { + case TextImageRelation.Overlay: + ret_size.Height = Math.Max (rb.Text.Length == 0 ? 0 : text_size.Height, image_size.Height); + ret_size.Width = Math.Max (text_size.Width, image_size.Width); + break; + case TextImageRelation.ImageAboveText: + case TextImageRelation.TextAboveImage: + ret_size.Height = text_size.Height + image_size.Height; + ret_size.Width = Math.Max (text_size.Width, image_size.Width); + break; + case TextImageRelation.ImageBeforeText: + case TextImageRelation.TextBeforeImage: + ret_size.Height = Math.Max (text_size.Height, image_size.Height); + ret_size.Width = text_size.Width + image_size.Width; + break; + } + + // Pad the result + ret_size.Height += (rb.Padding.Vertical); + ret_size.Width += (rb.Padding.Horizontal) + 15; + + // There seems to be a minimum height + if (ret_size.Height == rb.Padding.Vertical) + ret_size.Height += 14; + + return ret_size; + } + + public override void CalculateRadioButtonTextAndImageLayout (ButtonBase b, Point offset, out Rectangle glyphArea, out Rectangle textRectangle, out Rectangle imageRectangle) + { + CalculateCheckBoxTextAndImageLayout (b, offset, out glyphArea, out textRectangle, out imageRectangle); + } + #endregion // RadioButton + + #region ScrollBar + public override void DrawScrollBar (Graphics dc, Rectangle clip, ScrollBar bar) + { + int scrollbutton_width = bar.scrollbutton_width; + int scrollbutton_height = bar.scrollbutton_height; + Rectangle first_arrow_area; + Rectangle second_arrow_area; + Rectangle thumb_pos; + + thumb_pos = bar.ThumbPos; + + if (bar.vert) { + first_arrow_area = new Rectangle(0, 0, bar.Width, scrollbutton_height); + bar.FirstArrowArea = first_arrow_area; + + second_arrow_area = new Rectangle(0, bar.ClientRectangle.Height - scrollbutton_height, bar.Width, scrollbutton_height); + bar.SecondArrowArea = second_arrow_area; + + thumb_pos.Width = bar.Width; + bar.ThumbPos = thumb_pos; + + Brush VerticalBrush; + /* Background, upper track */ + if (bar.thumb_moving == ScrollBar.ThumbMoving.Backwards) + VerticalBrush = ResPool.GetHatchBrush (HatchStyle.Percent50, Color.FromArgb (255, 63, 63, 63), Color.Black); + else + VerticalBrush = ResPool.GetHatchBrush (HatchStyle.Percent50, ColorScrollBar, Color.White); + Rectangle UpperTrack = new Rectangle (0, 0, bar.ClientRectangle.Width, bar.ThumbPos.Bottom); + if (clip.IntersectsWith (UpperTrack)) + dc.FillRectangle (VerticalBrush, UpperTrack); + + /* Background, lower track */ + if (bar.thumb_moving == ScrollBar.ThumbMoving.Forward) + VerticalBrush = ResPool.GetHatchBrush (HatchStyle.Percent50, Color.FromArgb (255, 63, 63, 63), Color.Black); + else + VerticalBrush = ResPool.GetHatchBrush (HatchStyle.Percent50, ColorScrollBar, Color.White); + Rectangle LowerTrack = new Rectangle (0, bar.ThumbPos.Bottom, bar.ClientRectangle.Width, bar.ClientRectangle.Height - bar.ThumbPos.Bottom); + if (clip.IntersectsWith (LowerTrack)) + dc.FillRectangle (VerticalBrush, LowerTrack); + + /* Buttons */ + if (clip.IntersectsWith (first_arrow_area)) + CPDrawScrollButton (dc, first_arrow_area, ScrollButton.Up, bar.firstbutton_state); + if (clip.IntersectsWith (second_arrow_area)) + CPDrawScrollButton (dc, second_arrow_area, ScrollButton.Down, bar.secondbutton_state); + } else { + first_arrow_area = new Rectangle(0, 0, scrollbutton_width, bar.Height); + bar.FirstArrowArea = first_arrow_area; + + second_arrow_area = new Rectangle (bar.ClientRectangle.Width - scrollbutton_width, 0, scrollbutton_width, bar.Height); + bar.SecondArrowArea = second_arrow_area; + + thumb_pos.Height = bar.Height; + bar.ThumbPos = thumb_pos; + + Brush HorizontalBrush; + //Background, left track + if (bar.thumb_moving == ScrollBar.ThumbMoving.Backwards) + HorizontalBrush = ResPool.GetHatchBrush (HatchStyle.Percent50, Color.FromArgb (255, 63, 63, 63), Color.Black); + else + HorizontalBrush = ResPool.GetHatchBrush (HatchStyle.Percent50, ColorScrollBar, Color.White); + Rectangle LeftTrack = new Rectangle (0, 0, bar.ThumbPos.Right, bar.ClientRectangle.Height); + if (clip.IntersectsWith (LeftTrack)) + dc.FillRectangle (HorizontalBrush, LeftTrack); + + //Background, right track + if (bar.thumb_moving == ScrollBar.ThumbMoving.Forward) + HorizontalBrush = ResPool.GetHatchBrush (HatchStyle.Percent50, Color.FromArgb (255, 63, 63, 63), Color.Black); + else + HorizontalBrush = ResPool.GetHatchBrush (HatchStyle.Percent50, ColorScrollBar, Color.White); + Rectangle RightTrack = new Rectangle (bar.ThumbPos.Right, 0, bar.ClientRectangle.Width - bar.ThumbPos.Right, bar.ClientRectangle.Height); + if (clip.IntersectsWith (RightTrack)) + dc.FillRectangle (HorizontalBrush, RightTrack); + + /* Buttons */ + if (clip.IntersectsWith (first_arrow_area)) + CPDrawScrollButton (dc, first_arrow_area, ScrollButton.Left, bar.firstbutton_state); + if (clip.IntersectsWith (second_arrow_area)) + CPDrawScrollButton (dc, second_arrow_area, ScrollButton.Right, bar.secondbutton_state); + } + + /* Thumb */ + ScrollBar_DrawThumb(bar, thumb_pos, clip, dc); + } + + protected virtual void ScrollBar_DrawThumb(ScrollBar bar, Rectangle thumb_pos, Rectangle clip, Graphics dc) + { + if (bar.Enabled && thumb_pos.Width > 0 && thumb_pos.Height > 0 && clip.IntersectsWith(thumb_pos)) + DrawScrollButtonPrimitive(dc, thumb_pos, ButtonState.Normal); + } + + public override int ScrollBarButtonSize { + get { return 16; } + } + + public override bool ScrollBarHasHotElementStyles { + get { + return false; + } + } + + public override bool ScrollBarHasPressedThumbStyle { + get { + return false; + } + } + + public override bool ScrollBarHasHoverArrowButtonStyle { + get { + return false; + } + } + #endregion // ScrollBar + + #region StatusBar + public override void DrawStatusBar (Graphics real_dc, Rectangle clip, StatusBar sb) { + Rectangle area = sb.ClientRectangle; + int horz_border = 2; + int vert_border = 2; + + Image backbuffer = new Bitmap (sb.ClientSize.Width, sb.ClientSize.Height, real_dc); + Graphics dc = Graphics.FromImage (backbuffer); + + DrawStatusBarBackground (dc, clip, sb); + + if (!sb.ShowPanels && sb.Text != String.Empty) { + string text = sb.Text; + StringFormat string_format = new StringFormat (); + string_format.Trimming = StringTrimming.Character; + string_format.FormatFlags = StringFormatFlags.NoWrap; + + if (text.Length > 127) + text = text.Substring (0, 127); + + if (text [0] == '\t') { + string_format.Alignment = StringAlignment.Center; + text = text.Substring (1); + if (text [0] == '\t') { + string_format.Alignment = StringAlignment.Far; + text = text.Substring (1); + } + } + + dc.DrawString (text, sb.Font, ResPool.GetSolidBrush (sb.ForeColor), + new Rectangle(area.X + 2, area.Y + 2, area.Width - 4, area.Height - 4), string_format); + string_format.Dispose (); + } else if (sb.ShowPanels) { + Brush br_forecolor = GetControlForeBrush (sb.ForeColor); + int prev_x = area.X + horz_border; + int y = area.Y + vert_border; + for (int i = 0; i < sb.Panels.Count; i++) { + Rectangle pr = new Rectangle (prev_x, y, + sb.Panels [i].Width, area.Height); + prev_x += pr.Width + StatusBarHorzGapWidth; + if (pr.IntersectsWith (clip)) + DrawStatusBarPanel (dc, pr, i, br_forecolor, sb.Panels [i]); + } + } + + if (sb.SizingGrip) + DrawStatusBarSizingGrip (dc, clip, sb, area); + + real_dc.DrawImage (backbuffer, 0, 0); + dc.Dispose (); + backbuffer.Dispose (); + + } + + protected virtual void DrawStatusBarBackground (Graphics dc, Rectangle clip, StatusBar sb) + { + bool is_color_control = sb.BackColor.ToArgb () == ColorControl.ToArgb (); + + Brush brush = is_color_control ? SystemBrushes.Control : ResPool.GetSolidBrush (sb.BackColor); + dc.FillRectangle (brush, clip); + } + + protected virtual void DrawStatusBarSizingGrip (Graphics dc, Rectangle clip, StatusBar sb, Rectangle area) + { + area = new Rectangle (area.Right - 16 - 2, area.Bottom - 12 - 1, 16, 16); + CPDrawSizeGrip (dc, ColorControl, area); + } + + protected virtual void DrawStatusBarPanel (Graphics dc, Rectangle area, int index, + Brush br_forecolor, StatusBarPanel panel) { + int border_size = 3; // this is actually const, even if the border style is none + int icon_width = 16; + + area.Height -= border_size; + + DrawStatusBarPanelBackground (dc, area, panel); + + if (panel.Style == StatusBarPanelStyle.OwnerDraw) { + StatusBarDrawItemEventArgs e = new StatusBarDrawItemEventArgs ( + dc, panel.Parent.Font, area, index, DrawItemState.Default, + panel, panel.Parent.ForeColor, panel.Parent.BackColor); + panel.Parent.OnDrawItemInternal (e); + return; + } + + string text = panel.Text; + StringFormat string_format = new StringFormat (); + string_format.Trimming = StringTrimming.Character; + string_format.FormatFlags = StringFormatFlags.NoWrap; + + + if (text != null && text.Length > 0 && text [0] == '\t') { + string_format.Alignment = StringAlignment.Center; + text = text.Substring (1); + if (text [0] == '\t') { + string_format.Alignment = StringAlignment.Far; + text = text.Substring (1); + } + } + + Rectangle string_rect = Rectangle.Empty; + int x; + int len; + int icon_x = 0; + int y = (area.Height / 2 - (int) panel.Parent.Font.Size / 2) - 1; + + switch (panel.Alignment) { + case HorizontalAlignment.Right: + len = (int) dc.MeasureString (text, panel.Parent.Font).Width; + x = area.Right - len - 4; + string_rect = new Rectangle (x, y, + area.Right - x - border_size, + area.Bottom - y - border_size); + if (panel.Icon != null) { + icon_x = x - icon_width - 2; + } + break; + case HorizontalAlignment.Center: + len = (int) dc.MeasureString (text, panel.Parent.Font).Width; + x = area.Left + ((panel.Width - len) / 2); + + string_rect = new Rectangle (x, y, + area.Right - x - border_size, + area.Bottom - y - border_size); + + if (panel.Icon != null) { + icon_x = x - icon_width - 2; + } + break; + + + default: + int left = area.Left + border_size;; + if (panel.Icon != null) { + icon_x = area.Left + 2; + left = icon_x + icon_width + 2; + } + + x = left; + string_rect = new Rectangle (x, y, + area.Right - x - border_size, + area.Bottom - y - border_size); + break; + } + + RectangleF clip_bounds = dc.ClipBounds; + dc.SetClip (area); + dc.DrawString (text, panel.Parent.Font, br_forecolor, string_rect, string_format); + dc.SetClip (clip_bounds); + + if (panel.Icon != null) { + dc.DrawIcon (panel.Icon, new Rectangle (icon_x, y, icon_width, icon_width)); + } + } + + protected virtual void DrawStatusBarPanelBackground (Graphics dc, Rectangle area, StatusBarPanel panel) + { + if (panel.BorderStyle != StatusBarPanelBorderStyle.None) { + Border3DStyle border_style = Border3DStyle.SunkenOuter; + if (panel.BorderStyle == StatusBarPanelBorderStyle.Raised) + border_style = Border3DStyle.RaisedInner; + + CPDrawBorder3D(dc, area, border_style, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom, panel.Parent.BackColor); + } + } + + public override int StatusBarSizeGripWidth { + get { return 15; } + } + + public override int StatusBarHorzGapWidth { + get { return 3; } + } + + public override Size StatusBarDefaultSize { + get { + return new Size (100, 22); + } + } + #endregion // StatusBar + + #region TabControl + + #region TabControl settings + + public override Size TabControlDefaultItemSize { + get { return ThemeElements.CurrentTheme.TabWidgetPainter.DefaultItemSize; } + } + + public override Point TabControlDefaultPadding { + get { return ThemeElements.CurrentTheme.TabWidgetPainter.DefaultPadding; } + } + + public override int TabControlMinimumTabWidth { + get { return ThemeElements.CurrentTheme.TabWidgetPainter.MinimumTabWidth; } + } + + public override Rectangle TabWidgetselectedDelta { + get { return ThemeElements.CurrentTheme.TabWidgetPainter.SelectedTabDelta; } + } + + public override int TabWidgetselectedSpacing { + get { return ThemeElements.CurrentTheme.TabWidgetPainter.SelectedSpacing; } + } + + public override int TabPanelOffsetX { + get { return ThemeElements.CurrentTheme.TabWidgetPainter.TabPanelOffset.X; } + } + + public override int TabPanelOffsetY { + get { return ThemeElements.CurrentTheme.TabWidgetPainter.TabPanelOffset.Y; } + } + + public override int TabControlColSpacing { + get { return ThemeElements.CurrentTheme.TabWidgetPainter.ColSpacing; } + } + + public override Point TabControlImagePadding { + get { return ThemeElements.CurrentTheme.TabWidgetPainter.ImagePadding; } + } + + public override int TabWidgetscrollerWidth { + get {return ThemeElements.CurrentTheme.TabWidgetPainter.ScrollerWidth; } + } + + + public override Size TabControlGetSpacing (TabWidget tab) + { + try { + return ThemeElements.CurrentTheme.TabWidgetPainter.RowSpacing (tab); + } catch { + throw new Exception ("Invalid Appearance value: " + tab.Appearance); + } + } + #endregion + + public override void DrawTabControl (Graphics dc, Rectangle area, TabWidget tab) + { + ThemeElements.CurrentTheme.TabWidgetPainter.Draw (dc, area, tab); + } + + public override Rectangle TabControlGetDisplayRectangle (TabWidget tab) + { + return ThemeElements.CurrentTheme.TabWidgetPainter.GetDisplayRectangle (tab); + } + + public override Rectangle TabControlGetPanelRect (TabWidget tab) + { + return ThemeElements.CurrentTheme.TabWidgetPainter.GetTabPanelRect (tab); + } + + #endregion + + #region TextBox + public override void TextBoxBaseFillBackground (TextBoxBase textBoxBase, Graphics g, Rectangle clippingArea) + { + if (textBoxBase.backcolor_set || (textBoxBase.Enabled && !textBoxBase.read_only)) { + g.FillRectangle(ResPool.GetSolidBrush(textBoxBase.BackColor), clippingArea); + } else { + g.FillRectangle(ResPool.GetSolidBrush(ColorControl), clippingArea); + } + } + + public override bool TextBoxBaseHandleWmNcPaint (TextBoxBase textBoxBase, ref Message m) + { + return false; + } + + public override bool TextBoxBaseShouldPaintBackground (TextBoxBase textBoxBase) + { + return true; + } + #endregion + + /* FIXME: I don't ever remember porting over this. + #region ToolBar + public override void DrawToolBar (Graphics dc, Rectangle clip_rectangle, ToolBar control) + { + StringFormat format = new StringFormat (); + format.Trimming = StringTrimming.EllipsisCharacter; + format.LineAlignment = StringAlignment.Center; + if (control.ShowKeyboardCuesInternal) + format.HotkeyPrefix = HotkeyPrefix.Show; + else + format.HotkeyPrefix = HotkeyPrefix.Hide; + + if (control.TextAlign == ToolBarTextAlign.Underneath) + format.Alignment = StringAlignment.Center; + else + format.Alignment = StringAlignment.Near; + + if (control.Appearance != ToolBarAppearance.Flat || control.Parent == null) { + dc.FillRectangle (SystemBrushes.Control, clip_rectangle); + } + + if (control.Divider && clip_rectangle.Y < 2) { + if (clip_rectangle.Y < 1) { + dc.DrawLine (SystemPens.ControlDark, clip_rectangle.X, 0, clip_rectangle.Right, 0); + } + dc.DrawLine (SystemPens.ControlLightLight, clip_rectangle.X, 1, clip_rectangle.Right, 1); + } + + foreach (ToolBarItem item in control.items) + if (item.Button.Visible && clip_rectangle.IntersectsWith (item.Rectangle)) + DrawToolBarButton (dc, control, item, format); + + format.Dispose (); + } + + protected virtual void DrawToolBarButton (Graphics dc, ToolBar control, ToolBarItem item, StringFormat format) + { + bool is_flat = (control.Appearance == ToolBarAppearance.Flat); + + DrawToolBarButtonBorder (dc, item, is_flat); + + switch (item.Button.Style) { + case ToolBarButtonStyle.DropDownButton: + if (control.DropDownArrows) + DrawToolBarDropDownArrow (dc, item, is_flat); + DrawToolBarButtonContents (dc, control, item, format); + break; + + case ToolBarButtonStyle.Separator: + if (is_flat) + DrawToolBarSeparator (dc, item); + break; + + case ToolBarButtonStyle.ToggleButton: + DrawToolBarToggleButtonBackground (dc, item); + DrawToolBarButtonContents (dc, control, item, format); + break; + + default: + DrawToolBarButtonContents (dc, control, item, format); + break; + } + } + + const Border3DSide all_sides = Border3DSide.Left | Border3DSide.Top | Border3DSide.Right | Border3DSide.Bottom; + + protected virtual void DrawToolBarButtonBorder (Graphics dc, ToolBarItem item, bool is_flat) + { + if (item.Button.Style == ToolBarButtonStyle.Separator) + return; + + Border3DStyle style; + + if (is_flat) { + if (item.Button.Pushed || item.Pressed) + style = Border3DStyle.SunkenOuter; + else if (item.Hilight) + style = Border3DStyle.RaisedInner; + else + return; + + } else { + if (item.Button.Pushed || item.Pressed) + style = Border3DStyle.Sunken; + else + style = Border3DStyle.Raised; + } + + Rectangle rect = item.Rectangle; + if ((item.Button.Style == ToolBarButtonStyle.DropDownButton) && (item.Button.Parent.DropDownArrows) && is_flat) + rect.Width -= ToolBarDropDownWidth; + + CPDrawBorder3D (dc, rect, style, all_sides); + } + + protected virtual void DrawToolBarSeparator (Graphics dc, ToolBarItem item) + { + Rectangle area = item.Rectangle; + int offset = (int) SystemPens.Widget.Width + 1; + dc.DrawLine (SystemPens.ControlDark, area.X + 1, area.Y, area.X + 1, area.Bottom); + dc.DrawLine (SystemPens.ControlLight, area.X + offset, area.Y, area.X + offset, area.Bottom); + } + + protected virtual void DrawToolBarToggleButtonBackground (Graphics dc, ToolBarItem item) + { + Brush brush; + Rectangle area = item.Rectangle; + area.X += ToolBarImageGripWidth; + area.Y += ToolBarImageGripWidth; + area.Width -= 2 * ToolBarImageGripWidth; + area.Height -= 2 * ToolBarImageGripWidth; + + if (item.Button.Pushed) + brush = (Brush) ResPool.GetHatchBrush (HatchStyle.Percent50, ColorScrollBar, ColorControlLightLight); + else if (item.Button.PartialPush) + brush = SystemBrushes.ControlLight; + else + brush = SystemBrushes.Control; + + dc.FillRectangle (brush, area); + } + + protected virtual void DrawToolBarDropDownArrow (Graphics dc, ToolBarItem item, bool is_flat) + { + Rectangle rect = item.Rectangle; + rect.X = item.Rectangle.Right - ToolBarDropDownWidth; + rect.Width = ToolBarDropDownWidth; + + if (is_flat) { + if (item.DDPressed) + CPDrawBorder3D (dc, rect, Border3DStyle.SunkenOuter, all_sides); + else if (item.Button.Pushed || item.Pressed) + CPDrawBorder3D (dc, rect, Border3DStyle.SunkenOuter, all_sides); + else if (item.Hilight) + CPDrawBorder3D (dc, rect, Border3DStyle.RaisedInner, all_sides); + } else { + if (item.DDPressed) + CPDrawBorder3D (dc, rect, Border3DStyle.Flat, all_sides); + else if (item.Button.Pushed || item.Pressed) + CPDrawBorder3D (dc, Rectangle.Inflate(rect, -1, -1), Border3DStyle.SunkenOuter, all_sides); + else + CPDrawBorder3D (dc, rect, Border3DStyle.Raised, all_sides); + } + + PointF [] vertices = new PointF [3]; + PointF ddCenter = new PointF (rect.X + (rect.Width/2.0f), rect.Y + (rect.Height / 2)); + + // Increase vertical and horizontal position by 1 when button is pressed + if (item.Pressed || item.Button.Pushed || item.DDPressed) { + ddCenter.X += 1; + ddCenter.Y += 1; + } + + vertices [0].X = ddCenter.X - ToolBarDropDownArrowWidth / 2.0f + 0.5f; + vertices [0].Y = ddCenter.Y; + vertices [1].X = ddCenter.X + ToolBarDropDownArrowWidth / 2.0f + 0.5f; + vertices [1].Y = ddCenter.Y; + vertices [2].X = ddCenter.X + 0.5f; // 0.5 is added for adjustment + vertices [2].Y = ddCenter.Y + ToolBarDropDownArrowHeight; + dc.FillPolygon (SystemBrushes.ControlText, vertices); + } + + protected virtual void DrawToolBarButtonContents (Graphics dc, ToolBar control, ToolBarItem item, StringFormat format) + { + if (item.Button.Image != null) { + int x = item.ImageRectangle.X + ToolBarImageGripWidth; + int y = item.ImageRectangle.Y + ToolBarImageGripWidth; + + // Increase vertical and horizontal position by 1 when button is pressed + if (item.Pressed || item.Button.Pushed) { + x += 1; + y += 1; + } + + if (item.Button.Enabled) + dc.DrawImage (item.Button.Image, x, y); + else + CPDrawImageDisabled (dc, item.Button.Image, x, y, ColorControl); + } + + Rectangle text_rect = item.TextRectangle; + if (text_rect.Width <= 0 || text_rect.Height <= 0) + return; + + if (item.Pressed || item.Button.Pushed) { + text_rect.X += 1; + text_rect.Y += 1; + } + + if (item.Button.Enabled) + dc.DrawString (item.Button.Text, control.Font, SystemBrushes.ControlText, text_rect, format); + else + CPDrawStringDisabled (dc, item.Button.Text, control.Font, control.BackColor, text_rect, format); + } + + // Grip width for the ToolBar + public override int ToolBarGripWidth { + get { return 2;} + } + + // Grip width for the Image on the ToolBarButton + public override int ToolBarImageGripWidth { + get { return 2;} + } + + // width of the separator + public override int ToolBarSeparatorWidth { + get { return 4; } + } + + // width of the dropdown arrow rect + public override int ToolBarDropDownWidth { + get { return 13; } + } + + // width for the dropdown arrow on the ToolBarButton + public override int ToolBarDropDownArrowWidth { + get { return 5;} + } + + // height for the dropdown arrow on the ToolBarButton + public override int ToolBarDropDownArrowHeight { + get { return 3;} + } + + public override Size ToolBarDefaultSize { + get { + return new Size (100, 42); + } + } + + public override bool ToolBarHasHotElementStyles (ToolBar toolBar) + { + return toolBar.Appearance == ToolBarAppearance.Flat; + } + + public override bool ToolBarHasHotCheckedElementStyles { + get { + return false; + } + } + #endregion // ToolBar*/ + + #region ToolTip + public override void DrawToolTip(Graphics dc, Rectangle clip_rectangle, ToolTip.ToolTipWindow control) + { + ToolTipDrawBackground (dc, clip_rectangle, control); + + TextFormatFlags flags = TextFormatFlags.HidePrefix; + + Color foreground = control.ForeColor; + if (control.title.Length > 0) { + Font bold_font = new Font (control.Font, control.Font.Style | FontStyle.Bold); + TextRenderer.DrawTextInternal (dc, control.title, bold_font, control.title_rect, + foreground, flags, false); + bold_font.Dispose (); + } + + if (control.icon != null) + dc.DrawIcon (control.icon, control.icon_rect); + + TextRenderer.DrawTextInternal (dc, control.Text, control.Font, control.text_rect, foreground, flags, false); + } + + protected virtual void ToolTipDrawBackground (Graphics dc, Rectangle clip_rectangle, ToolTip.ToolTipWindow control) + { + Brush back_brush = ResPool.GetSolidBrush (control.BackColor); + dc.FillRectangle (back_brush, control.ClientRectangle); + dc.DrawRectangle (SystemPens.WindowFrame, 0, 0, control.Width - 1, control.Height - 1); + } + + public override Size ToolTipSize(ToolTip.ToolTipWindow tt, string text) + { + Size size = TextRenderer.MeasureTextInternal (text, tt.Font, false); + size.Width += 4; + size.Height += 3; + Rectangle text_rect = new Rectangle (Point.Empty, size); + text_rect.Inflate (-2, -1); + tt.text_rect = text_rect; + tt.icon_rect = tt.title_rect = Rectangle.Empty; + + Size title_size = Size.Empty; + if (tt.title.Length > 0) { + Font bold_font = new Font (tt.Font, tt.Font.Style | FontStyle.Bold); + title_size = TextRenderer.MeasureTextInternal (tt.title, bold_font, false); + bold_font.Dispose (); + } + + Size icon_size = Size.Empty; + if (tt.icon != null) + icon_size = new Size (size.Height, size.Height); + + if (icon_size != Size.Empty || title_size != Size.Empty) { + int padding = 8; + int top_area_width = 0; + int top_area_height = icon_size.Height > title_size.Height ? icon_size.Height : title_size.Height; + Size text_size = size; + Point location = new Point (padding, padding); + + if (icon_size != Size.Empty) { + tt.icon_rect = new Rectangle (location, icon_size); + top_area_width = icon_size.Width + padding; + } + + if (title_size != Size.Empty) { + Rectangle title_rect = new Rectangle (location, new Size (title_size.Width, top_area_height)); + if (icon_size != Size.Empty) + title_rect.X += icon_size.Width + padding; + + tt.title_rect = title_rect; + top_area_width += title_size.Width; + } + + tt.text_rect = new Rectangle (new Point (location.X, location.Y + top_area_height + padding), + text_size); + + size.Height += padding + top_area_height; + if (top_area_width > size.Width) + size.Width = top_area_width; + + // margins + size.Width += padding * 2; + size.Height += padding * 2; + } + + return size; + } + + public override bool ToolTipTransparentBackground { + get { + return false; + } + } + #endregion // ToolTip + + #region BalloonWindow + NotifyIcon.BalloonWindow balloon_window; + + public override void ShowBalloonWindow (IntPtr handle, int timeout, string title, string text, ToolTipIcon icon) + { + Widget control = Widget.FromHandle(handle); + + if (control == null) + return; + + if (balloon_window != null) { + balloon_window.Close (); + balloon_window.Dispose (); + } + + balloon_window = new NotifyIcon.BalloonWindow (handle); + balloon_window.Title = title; + balloon_window.Text = text; + balloon_window.Icon = icon; + balloon_window.Timeout = timeout; + balloon_window.Show (); + } + + public override void HideBalloonWindow (IntPtr handle) + { + if (balloon_window == null || balloon_window.OwnerHandle != handle) + return; + + balloon_window.Close (); + balloon_window.Dispose (); + balloon_window = null; + } + + private const int balloon_iconsize = 16; + private const int balloon_bordersize = 8; + + public override void DrawBalloonWindow (Graphics dc, Rectangle clip, NotifyIcon.BalloonWindow control) + { + Brush solidbrush = ResPool.GetSolidBrush (this.ColorInfoText); + Rectangle rect = control.ClientRectangle; + int iconsize = (control.Icon == ToolTipIcon.None) ? 0 : balloon_iconsize; + + // Rectangle borders and background. + dc.FillRectangle (ResPool.GetSolidBrush (ColorInfo), rect); + dc.DrawRectangle (ResPool.GetPen (ColorWindowFrame), 0, 0, rect.Width - 1, rect.Height - 1); + + // Icon + Image image; + switch (control.Icon) { + case ToolTipIcon.Info: { + image = ThemeEngine.Current.Images(UIIcon.MessageBoxInfo, balloon_iconsize); + break; + } + + case ToolTipIcon.Warning: { + image = ThemeEngine.Current.Images(UIIcon.MessageBoxError, balloon_iconsize); + break; + } + + case ToolTipIcon.Error: { + image = ThemeEngine.Current.Images(UIIcon.MessageBoxWarning, balloon_iconsize); + break; + } + + default: { + image = null; + break; + } + } + + if (control.Icon != ToolTipIcon.None) + dc.DrawImage (image, new Rectangle (balloon_bordersize, balloon_bordersize, iconsize, iconsize)); + + // Title + Rectangle titlerect = new Rectangle (rect.X + balloon_bordersize + iconsize + (iconsize > 0 ? balloon_bordersize : 0), + rect.Y + balloon_bordersize, + rect.Width - ((3 * balloon_bordersize) + iconsize), + rect.Height - (2 * balloon_bordersize)); + + Font titlefont = new Font (control.Font.FontFamily, control.Font.Size, control.Font.Style | FontStyle.Bold, control.Font.Unit); + dc.DrawString (control.Title, titlefont, solidbrush, titlerect, control.Format); + + // Text + Rectangle textrect = new Rectangle (rect.X + balloon_bordersize, + rect.Y + balloon_bordersize, + rect.Width - (2 * balloon_bordersize), + rect.Height - (2 * balloon_bordersize)); + + StringFormat textformat = control.Format; + textformat.LineAlignment = StringAlignment.Far; + dc.DrawString (control.Text, control.Font, solidbrush, textrect, textformat); + } + + public override Rectangle BalloonWindowRect (NotifyIcon.BalloonWindow control) + { + Rectangle deskrect = Screen.GetWorkingArea (control); + SizeF maxsize = new SizeF (250, 200); + + SizeF titlesize = TextRenderer.MeasureString (control.Title, control.Font, maxsize, control.Format); + SizeF textsize = TextRenderer.MeasureString (control.Text, control.Font, maxsize, control.Format); + + if (titlesize.Height < balloon_iconsize) + titlesize.Height = balloon_iconsize; + + Rectangle rect = new Rectangle (); + rect.Height = (int) (titlesize.Height + textsize.Height + (3 * balloon_bordersize)); + rect.Width = (int) ((titlesize.Width > textsize.Width) ? titlesize.Width : textsize.Width) + (2 * balloon_bordersize); + rect.X = deskrect.Width - rect.Width - 2; + rect.Y = deskrect.Height - rect.Height - 2; + + return rect; + } + #endregion // BalloonWindow + + #region TrackBar + public override int TrackBarValueFromMousePosition (int x, int y, TrackBar tb) + { + int result = tb.Value; + int value_pos = tb.Value; + float pixels_betweenticks; + Rectangle thumb_pos = Rectangle.Empty, thumb_area = Rectangle.Empty; + Point channel_startpoint = Point.Empty, na_point = Point.Empty; + + GetTrackBarDrawingInfo (tb, out pixels_betweenticks, out thumb_area, out thumb_pos, out channel_startpoint, out na_point, out na_point); + + /* Convert thumb position from mouse position to value*/ + if (tb.Orientation == Orientation.Vertical) { + value_pos = (int)Math.Round (((thumb_area.Bottom - y - (float)thumb_pos.Height / 2) / (float)pixels_betweenticks), 0); + + if (value_pos + tb.Minimum > tb.Maximum) + value_pos = tb.Maximum - tb.Minimum; + else if (value_pos + tb.Minimum < tb.Minimum) + value_pos = 0; + + result = value_pos + tb.Minimum; + } else { + value_pos = (int)Math.Round (((x - channel_startpoint.X - (float)thumb_pos.Width / 2) / (float) pixels_betweenticks), 0); + + if (value_pos + tb.Minimum > tb.Maximum) + value_pos = tb.Maximum - tb.Minimum; + else if (value_pos + tb.Minimum < tb.Minimum) + value_pos = 0; + + result = value_pos + tb.Minimum; + } + + return result; + } + + private void GetTrackBarDrawingInfo (TrackBar tb, out float pixels_betweenticks, out Rectangle thumb_area, out Rectangle thumb_pos, out Point channel_startpoint, out Point bottomtick_startpoint, out Point toptick_startpoint) + { + thumb_area = Rectangle.Empty; + thumb_pos = Rectangle.Empty; + + if (tb.Orientation == Orientation.Vertical) { + toptick_startpoint = new Point (); + bottomtick_startpoint = new Point (); + channel_startpoint = new Point (); + float pixel_len; + const int space_from_right = 8; + const int space_from_left = 8; + const int space_from_bottom = 11; + Rectangle area = tb.ClientRectangle; + + switch (tb.TickStyle) { + case TickStyle.BottomRight: + case TickStyle.None: + channel_startpoint.Y = 8; + channel_startpoint.X = 9; + bottomtick_startpoint.Y = 13; + bottomtick_startpoint.X = 24; + break; + case TickStyle.TopLeft: + channel_startpoint.Y = 8; + channel_startpoint.X = 19; + toptick_startpoint.Y = 13; + toptick_startpoint.X = 8; + break; + case TickStyle.Both: + channel_startpoint.Y = 8; + channel_startpoint.X = 18; + bottomtick_startpoint.Y = 13; + bottomtick_startpoint.X = 32; + toptick_startpoint.Y = 13; + toptick_startpoint.X = 8; + break; + default: + break; + } + + thumb_area.X = area.X + channel_startpoint.X; + thumb_area.Y = area.Y + channel_startpoint.Y; + thumb_area.Height = area.Height - space_from_right - space_from_left; + thumb_area.Width = TrackBarVerticalTrackWidth; + + pixel_len = thumb_area.Height - 11; + if (tb.Maximum == tb.Minimum) { + pixels_betweenticks = 0; + } else { + pixels_betweenticks = pixel_len / (tb.Maximum - tb.Minimum); + } + + thumb_pos.Y = thumb_area.Bottom - space_from_bottom - (int)(pixels_betweenticks * (float)(tb.Value - tb.Minimum)); + } else { + toptick_startpoint = new Point (); + bottomtick_startpoint = new Point (); + channel_startpoint = new Point (); + float pixel_len; + const int space_from_right = 8; + const int space_from_left = 8; + Rectangle area = tb.ClientRectangle; + + switch (tb.TickStyle) { + case TickStyle.BottomRight: + case TickStyle.None: + channel_startpoint.X = 8; + channel_startpoint.Y = 9; + bottomtick_startpoint.X = 13; + bottomtick_startpoint.Y = 24; + break; + case TickStyle.TopLeft: + channel_startpoint.X = 8; + channel_startpoint.Y = 19; + toptick_startpoint.X = 13; + toptick_startpoint.Y = 8; + break; + case TickStyle.Both: + channel_startpoint.X = 8; + channel_startpoint.Y = 18; + bottomtick_startpoint.X = 13; + bottomtick_startpoint.Y = 32; + toptick_startpoint.X = 13; + toptick_startpoint.Y = 8; + break; + default: + break; + } + + thumb_area.X = area.X + channel_startpoint.X; + thumb_area.Y = area.Y + channel_startpoint.Y; + thumb_area.Width = area.Width - space_from_right - space_from_left; + thumb_area.Height = TrackBarHorizontalTrackHeight; + + pixel_len = thumb_area.Width - 11; + if (tb.Maximum == tb.Minimum) { + pixels_betweenticks = 0; + } else { + pixels_betweenticks = pixel_len / (tb.Maximum - tb.Minimum); + } + + thumb_pos.X = channel_startpoint.X + (int)(pixels_betweenticks * (float) (tb.Value - tb.Minimum)); + } + + thumb_pos.Size = TrackBarGetThumbSize (tb); + } + + protected virtual Size TrackBarGetThumbSize (TrackBar trackBar) + { + return TrackBarGetThumbSize (); + } + + public static Size TrackBarGetThumbSize () + { + /* Draw thumb fixed 10x22 size */ + return new Size (10, 22); + } + + public const int TrackBarVerticalTrackWidth = 4; + + public const int TrackBarHorizontalTrackHeight = 4; + + #region Ticks + protected interface ITrackBarTickPainter + { + void Paint (float x1, float y1, float x2, float y2); + } + + class TrackBarTickPainter : ITrackBarTickPainter + { + readonly Graphics g; + readonly Pen pen; + public TrackBarTickPainter (Graphics g, Pen pen) + { + this.g = g; + this.pen = pen; + } + public void Paint (float x1, float y1, float x2, float y2) + { + g.DrawLine (pen, x1, y1, x2, y2); + } + } + protected virtual ITrackBarTickPainter GetTrackBarTickPainter (Graphics g) + { + return new TrackBarTickPainter (g, ResPool.GetPen (pen_ticks_color)); + } + #endregion + + #region DrawTrackBar_Vertical + private void DrawTrackBar_Vertical (Graphics dc, Rectangle clip_rectangle, TrackBar tb, + ref Rectangle thumb_pos, ref Rectangle thumb_area, Brush br_thumb, + float ticks, int value_pos, bool mouse_value) { + + Point toptick_startpoint = new Point (); + Point bottomtick_startpoint = new Point (); + Point channel_startpoint = new Point (); + float pixel_len; + float pixels_betweenticks; + Rectangle area = tb.ClientRectangle; + + GetTrackBarDrawingInfo (tb, out pixels_betweenticks, out thumb_area, out thumb_pos, out channel_startpoint, out bottomtick_startpoint, out toptick_startpoint); + + #region Track + TrackBarDrawVerticalTrack (dc, thumb_area, channel_startpoint, clip_rectangle); + #endregion + + #region Thumb + switch (tb.TickStyle) { + case TickStyle.BottomRight: + case TickStyle.None: + thumb_pos.X = channel_startpoint.X - 8; + TrackBarDrawVerticalThumbRight (dc, thumb_pos, br_thumb, clip_rectangle, tb); + break; + case TickStyle.TopLeft: + thumb_pos.X = channel_startpoint.X - 10; + TrackBarDrawVerticalThumbLeft (dc, thumb_pos, br_thumb, clip_rectangle, tb); + break; + default: + thumb_pos.X = area.X + 10; + TrackBarDrawVerticalThumb (dc, thumb_pos, br_thumb, clip_rectangle, tb); + break; + } + #endregion + + pixel_len = thumb_area.Height - 11; + pixels_betweenticks = pixel_len / ticks; + + thumb_area.X = thumb_pos.X; + thumb_area.Y = channel_startpoint.Y; + thumb_area.Width = thumb_pos.Height; + + #region Ticks + if (pixels_betweenticks <= 0) + return; + if (tb.TickStyle == TickStyle.None) + return; + Region outside = new Region (area); + outside.Exclude (thumb_area); + + if (outside.IsVisible (clip_rectangle)) { + ITrackBarTickPainter tick_painter = TrackBarGetVerticalTickPainter (dc); + + if ((tb.TickStyle & TickStyle.BottomRight) == TickStyle.BottomRight) { + float x = area.X + bottomtick_startpoint.X; + for (float inc = 0; inc < pixel_len + 1; inc += pixels_betweenticks) { + float y = area.Y + bottomtick_startpoint.Y + inc; + tick_painter.Paint ( + x, y, + x + (inc == 0 || inc + pixels_betweenticks >= pixel_len + 1 ? 3 : 2), y); + } + } + + if ((tb.TickStyle & TickStyle.TopLeft) == TickStyle.TopLeft) { + float x = area.X + toptick_startpoint.X; + for (float inc = 0; inc < (pixel_len + 1); inc += pixels_betweenticks) { + float y = area.Y + toptick_startpoint.Y + inc; + tick_painter.Paint ( + x - (inc == 0 || inc + pixels_betweenticks >= pixel_len + 1 ? 3 : 2), y, + x, y); + } + } + } + + outside.Dispose (); + #endregion + } + + #region Track + protected virtual void TrackBarDrawVerticalTrack (Graphics dc, Rectangle thumb_area, Point channel_startpoint, Rectangle clippingArea) + { + dc.FillRectangle (SystemBrushes.ControlDark, channel_startpoint.X, channel_startpoint.Y, + 1, thumb_area.Height); + + dc.FillRectangle (SystemBrushes.ControlDarkDark, channel_startpoint.X + 1, channel_startpoint.Y, + 1, thumb_area.Height); + + dc.FillRectangle (SystemBrushes.ControlLight, channel_startpoint.X + 3, channel_startpoint.Y, + 1, thumb_area.Height); + } + #endregion + + #region Thumb + protected virtual void TrackBarDrawVerticalThumbRight (Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + Pen pen = SystemPens.ControlLightLight; + dc.DrawLine (pen, thumb_pos.X, thumb_pos.Y, thumb_pos.X, thumb_pos.Y + 10); + dc.DrawLine (pen, thumb_pos.X, thumb_pos.Y, thumb_pos.X + 16, thumb_pos.Y); + dc.DrawLine (pen, thumb_pos.X + 16, thumb_pos.Y, thumb_pos.X + 16 + 4, thumb_pos.Y + 4); + + pen = SystemPens.ControlDark; + dc.DrawLine (pen, thumb_pos.X + 1, thumb_pos.Y + 9, thumb_pos.X + 15, thumb_pos.Y + 9); + dc.DrawLine (pen, thumb_pos.X + 16, thumb_pos.Y + 9, thumb_pos.X + 16 + 4, thumb_pos.Y + 9 - 4); + + pen = SystemPens.ControlDarkDark; + dc.DrawLine (pen, thumb_pos.X, thumb_pos.Y + 10, thumb_pos.X + 16, thumb_pos.Y + 10); + dc.DrawLine (pen, thumb_pos.X + 16, thumb_pos.Y + 10, thumb_pos.X + 16 + 5, thumb_pos.Y + 10 - 5); + + dc.FillRectangle (br_thumb, thumb_pos.X + 1, thumb_pos.Y + 1, 16, 8); + dc.FillRectangle (br_thumb, thumb_pos.X + 17, thumb_pos.Y + 2, 1, 6); + dc.FillRectangle (br_thumb, thumb_pos.X + 18, thumb_pos.Y + 3, 1, 4); + dc.FillRectangle (br_thumb, thumb_pos.X + 19, thumb_pos.Y + 4, 1, 2); + } + + protected virtual void TrackBarDrawVerticalThumbLeft (Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + Pen pen = SystemPens.ControlLightLight; + dc.DrawLine (pen, thumb_pos.X + 4, thumb_pos.Y, thumb_pos.X + 4 + 16, thumb_pos.Y); + dc.DrawLine (pen, thumb_pos.X + 4, thumb_pos.Y, thumb_pos.X, thumb_pos.Y + 4); + + pen = SystemPens.ControlDark; + dc.DrawLine (pen, thumb_pos.X + 4, thumb_pos.Y + 9, thumb_pos.X + 4 + 16, thumb_pos.Y + 9); + dc.DrawLine (pen, thumb_pos.X + 4, thumb_pos.Y + 9, thumb_pos.X, thumb_pos.Y + 5); + dc.DrawLine (pen, thumb_pos.X + 19, thumb_pos.Y + 9, thumb_pos.X + 19, thumb_pos.Y + 1); + + pen = SystemPens.ControlDarkDark; + dc.DrawLine (pen, thumb_pos.X + 4, thumb_pos.Y + 10, thumb_pos.X + 4 + 16, thumb_pos.Y + 10); + dc.DrawLine (pen, thumb_pos.X + 4, thumb_pos.Y + 10, thumb_pos.X - 1, thumb_pos.Y + 5); + dc.DrawLine (pen, thumb_pos.X + 20, thumb_pos.Y, thumb_pos.X + 20, thumb_pos.Y + 10); + + dc.FillRectangle (br_thumb, thumb_pos.X + 4, thumb_pos.Y + 1, 15, 8); + dc.FillRectangle (br_thumb, thumb_pos.X + 3, thumb_pos.Y + 2, 1, 6); + dc.FillRectangle (br_thumb, thumb_pos.X + 2, thumb_pos.Y + 3, 1, 4); + dc.FillRectangle (br_thumb, thumb_pos.X + 1, thumb_pos.Y + 4, 1, 2); + } + + protected virtual void TrackBarDrawVerticalThumb (Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + Pen pen = SystemPens.ControlLightLight; + dc.DrawLine (pen, thumb_pos.X, thumb_pos.Y, thumb_pos.X, thumb_pos.Y + 9); + dc.DrawLine (pen, thumb_pos.X, thumb_pos.Y, thumb_pos.X + 19, thumb_pos.Y); + + pen = SystemPens.ControlDark; + dc.DrawLine (pen, thumb_pos.X + 1, thumb_pos.Y + 9, thumb_pos.X + 19, thumb_pos.Y + 9); + dc.DrawLine (pen, thumb_pos.X + 10, thumb_pos.Y + 1, thumb_pos.X + 19, thumb_pos.Y + 8); + + pen = SystemPens.ControlDarkDark; + dc.DrawLine (pen, thumb_pos.X, thumb_pos.Y + 10, thumb_pos.X + 20, thumb_pos.Y + 10); + dc.DrawLine (pen, thumb_pos.X + 20, thumb_pos.Y, thumb_pos.X + 20, thumb_pos.Y + 9); + + dc.FillRectangle (br_thumb, thumb_pos.X + 1, thumb_pos.Y + 1, 18, 8); + } + #endregion + + #region Ticks + protected virtual ITrackBarTickPainter TrackBarGetVerticalTickPainter (Graphics g) + { + return GetTrackBarTickPainter (g); + } + #endregion + #endregion + + #region DrawTrackBar_Horizontal + /* + Horizontal trackbar + + Does not matter the size of the control, Win32 always draws: + - Ticks starting from pixel 13, 8 + - Channel starting at pos 8, 19 and ends at Width - 8 + - Autosize makes always the control 45 pixels high + - Ticks are draw at (channel.Witdh - 10) / (Maximum - Minimum) + + */ + private void DrawTrackBar_Horizontal (Graphics dc, Rectangle clip_rectangle, TrackBar tb, + ref Rectangle thumb_pos, ref Rectangle thumb_area, Brush br_thumb, + float ticks, int value_pos, bool mouse_value) { + Point toptick_startpoint = new Point (); + Point bottomtick_startpoint = new Point (); + Point channel_startpoint = new Point (); + float pixel_len; + float pixels_betweenticks; + Rectangle area = tb.ClientRectangle; + + GetTrackBarDrawingInfo (tb , out pixels_betweenticks, out thumb_area, out thumb_pos, out channel_startpoint, out bottomtick_startpoint, out toptick_startpoint); + + #region Track + TrackBarDrawHorizontalTrack (dc, thumb_area, channel_startpoint, clip_rectangle); + #endregion + + #region Thumb + switch (tb.TickStyle) { + case TickStyle.BottomRight: + case TickStyle.None: + thumb_pos.Y = channel_startpoint.Y - 8; + TrackBarDrawHorizontalThumbBottom (dc, thumb_pos, br_thumb, clip_rectangle, tb); + break; + case TickStyle.TopLeft: + thumb_pos.Y = channel_startpoint.Y - 10; + TrackBarDrawHorizontalThumbTop (dc, thumb_pos, br_thumb, clip_rectangle, tb); + break; + default: + thumb_pos.Y = area.Y + 10; + TrackBarDrawHorizontalThumb (dc, thumb_pos, br_thumb, clip_rectangle, tb); + break; + } + #endregion + + pixel_len = thumb_area.Width - 11; + pixels_betweenticks = pixel_len / ticks; + + thumb_area.Y = thumb_pos.Y; + thumb_area.X = channel_startpoint.X; + thumb_area.Height = thumb_pos.Height; + #region Ticks + if (pixels_betweenticks <= 0) + return; + if (tb.TickStyle == TickStyle.None) + return; + Region outside = new Region (area); + outside.Exclude (thumb_area); + + if (outside.IsVisible (clip_rectangle)) { + ITrackBarTickPainter tick_painter = TrackBarGetHorizontalTickPainter (dc); + + if ((tb.TickStyle & TickStyle.BottomRight) == TickStyle.BottomRight) { + float y = area.Y + bottomtick_startpoint.Y; + for (float inc = 0; inc < pixel_len + 1; inc += pixels_betweenticks) { + float x = area.X + bottomtick_startpoint.X + inc; + tick_painter.Paint ( + x, y, + x, y + (inc == 0 || inc + pixels_betweenticks >= pixel_len + 1 ? 3 : 2)); + } + } + + if ((tb.TickStyle & TickStyle.TopLeft) == TickStyle.TopLeft) { + float y = area.Y + toptick_startpoint.Y; + for (float inc = 0; inc < pixel_len + 1; inc += pixels_betweenticks) { + float x = area.X + toptick_startpoint.X + inc; + tick_painter.Paint ( + x, y - (inc == 0 || (inc + pixels_betweenticks) >= pixel_len + 1 ? 3 : 2), + x, y); + } + } + } + + outside.Dispose (); + #endregion + } + + #region Track + protected virtual void TrackBarDrawHorizontalTrack (Graphics dc, Rectangle thumb_area, Point channel_startpoint, Rectangle clippingArea) + { + dc.FillRectangle (SystemBrushes.ControlDark, channel_startpoint.X, channel_startpoint.Y, + thumb_area.Width, 1); + + dc.FillRectangle (SystemBrushes.ControlDarkDark, channel_startpoint.X, channel_startpoint.Y + 1, + thumb_area.Width, 1); + + dc.FillRectangle (SystemBrushes.ControlLight, channel_startpoint.X, channel_startpoint.Y + 3, + thumb_area.Width, 1); + } + #endregion + + #region Thumb + protected virtual void TrackBarDrawHorizontalThumbBottom (Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + Pen pen = SystemPens.ControlLightLight; + dc.DrawLine (pen, thumb_pos.X, thumb_pos.Y, thumb_pos.X + 10, thumb_pos.Y); + dc.DrawLine (pen, thumb_pos.X, thumb_pos.Y, thumb_pos.X, thumb_pos.Y + 16); + dc.DrawLine (pen, thumb_pos.X, thumb_pos.Y + 16, thumb_pos.X + 4, thumb_pos.Y + 16 + 4); + + pen = SystemPens.ControlDark; + dc.DrawLine (pen, thumb_pos.X + 9, thumb_pos.Y + 1, thumb_pos.X + 9, thumb_pos.Y + 15); + dc.DrawLine (pen, thumb_pos.X + 9, thumb_pos.Y + 16, thumb_pos.X + 9 - 4, thumb_pos.Y + 16 + 4); + + pen = SystemPens.ControlDarkDark; + dc.DrawLine (pen, thumb_pos.X + 10, thumb_pos.Y, thumb_pos.X + 10, thumb_pos.Y + 16); + dc.DrawLine (pen, thumb_pos.X + 10, thumb_pos.Y + 16, thumb_pos.X + 10 - 5, thumb_pos.Y + 16 + 5); + + dc.FillRectangle (br_thumb, thumb_pos.X + 1, thumb_pos.Y + 1, 8, 16); + dc.FillRectangle (br_thumb, thumb_pos.X + 2, thumb_pos.Y + 17, 6, 1); + dc.FillRectangle (br_thumb, thumb_pos.X + 3, thumb_pos.Y + 18, 4, 1); + dc.FillRectangle (br_thumb, thumb_pos.X + 4, thumb_pos.Y + 19, 2, 1); + } + + protected virtual void TrackBarDrawHorizontalThumbTop (Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + Pen pen = SystemPens.ControlLightLight; + dc.DrawLine (pen, thumb_pos.X, thumb_pos.Y + 4, thumb_pos.X, thumb_pos.Y + 4 + 16); + dc.DrawLine (pen, thumb_pos.X, thumb_pos.Y + 4, thumb_pos.X + 4, thumb_pos.Y); + + pen = SystemPens.ControlDark; + dc.DrawLine (pen, thumb_pos.X + 9, thumb_pos.Y + 4, thumb_pos.X + 9, thumb_pos.Y + 4 + 16); + dc.DrawLine (pen, thumb_pos.X + 9, thumb_pos.Y + 4, thumb_pos.X + 5, thumb_pos.Y); + dc.DrawLine (pen, thumb_pos.X + 9, thumb_pos.Y + 19, thumb_pos.X + 1, thumb_pos.Y + 19); + + pen = SystemPens.ControlDarkDark; + dc.DrawLine (pen, thumb_pos.X + 10, thumb_pos.Y + 4, thumb_pos.X + 10, thumb_pos.Y + 4 + 16); + dc.DrawLine (pen, thumb_pos.X + 10, thumb_pos.Y + 4, thumb_pos.X + 5, thumb_pos.Y - 1); + dc.DrawLine (pen, thumb_pos.X, thumb_pos.Y + 20, thumb_pos.X + 10, thumb_pos.Y + 20); + + dc.FillRectangle (br_thumb, thumb_pos.X + 1, thumb_pos.Y + 4, 8, 15); + dc.FillRectangle (br_thumb, thumb_pos.X + 2, thumb_pos.Y + 3, 6, 1); + dc.FillRectangle (br_thumb, thumb_pos.X + 3, thumb_pos.Y + 2, 4, 1); + dc.FillRectangle (br_thumb, thumb_pos.X + 4, thumb_pos.Y + 1, 2, 1); + } + + protected virtual void TrackBarDrawHorizontalThumb (Graphics dc, Rectangle thumb_pos, Brush br_thumb, Rectangle clippingArea, TrackBar trackBar) + { + Pen pen = SystemPens.ControlLightLight; + dc.DrawLine (pen, thumb_pos.X, thumb_pos.Y, thumb_pos.X + 9, thumb_pos.Y); + dc.DrawLine (pen, thumb_pos.X, thumb_pos.Y, thumb_pos.X, thumb_pos.Y + 19); + + pen = SystemPens.ControlDark; + dc.DrawLine (pen, thumb_pos.X + 9, thumb_pos.Y + 1, thumb_pos.X + 9, thumb_pos.Y + 19); + dc.DrawLine (pen, thumb_pos.X + 1, thumb_pos.Y + 10, thumb_pos.X + 8, thumb_pos.Y + 19); + + pen = SystemPens.ControlDarkDark; + dc.DrawLine (pen, thumb_pos.X + 10, thumb_pos.Y, thumb_pos.X + 10, thumb_pos.Y + 20); + dc.DrawLine (pen, thumb_pos.X, thumb_pos.Y + 20, thumb_pos.X + 9, thumb_pos.Y + 20); + + dc.FillRectangle (br_thumb, thumb_pos.X + 1, thumb_pos.Y + 1, 8, 18); + } + #endregion + + #region Ticks + protected virtual ITrackBarTickPainter TrackBarGetHorizontalTickPainter (Graphics g) + { + return GetTrackBarTickPainter (g); + } + #endregion + #endregion + + public override void DrawTrackBar (Graphics dc, Rectangle clip_rectangle, TrackBar tb) + { + Brush br_thumb; + int value_pos; + bool mouse_value; + float ticks = (tb.Maximum - tb.Minimum) / tb.tickFrequency; /* N of ticks draw*/ + Rectangle area; + Rectangle thumb_pos = tb.ThumbPos; + Rectangle thumb_area = tb.ThumbArea; + + if (tb.thumb_pressed) { + value_pos = tb.thumb_mouseclick; + mouse_value = true; + } else { + value_pos = tb.Value - tb.Minimum; + mouse_value = false; + } + + area = tb.ClientRectangle; + + if (!tb.Enabled) { + br_thumb = (Brush) ResPool.GetHatchBrush (HatchStyle.Percent50, ColorControlLightLight, ColorControlLight); + } else if (tb.thumb_pressed == true) { + br_thumb = (Brush) ResPool.GetHatchBrush (HatchStyle.Percent50, ColorControlLight, ColorControl); + } else { + br_thumb = SystemBrushes.Control; + } + + + /* Widget Background */ + if (tb.BackColor.ToArgb () == DefaultControlBackColor.ToArgb ()) { + dc.FillRectangle (SystemBrushes.Control, clip_rectangle); + } else { + dc.FillRectangle (ResPool.GetSolidBrush (tb.BackColor), clip_rectangle); + } + + if (tb.Focused) { + CPDrawFocusRectangle(dc, area, tb.ForeColor, tb.BackColor); + } + + if (tb.Orientation == Orientation.Vertical) { + DrawTrackBar_Vertical (dc, clip_rectangle, tb, ref thumb_pos, ref thumb_area, + br_thumb, ticks, value_pos, mouse_value); + + } else { + DrawTrackBar_Horizontal (dc, clip_rectangle, tb, ref thumb_pos, ref thumb_area, + br_thumb, ticks, value_pos, mouse_value); + } + + tb.ThumbPos = thumb_pos; + tb.ThumbArea = thumb_area; + } + + public override Size TrackBarDefaultSize { + get { + return new Size (104, 42); + } + } + + public override bool TrackBarHasHotThumbStyle { + get { + return false; + } + } + #endregion // TrackBar + + #region UpDownBase + public override void UpDownBaseDrawButton (Graphics g, Rectangle bounds, bool top, VisualStyles.PushButtonState state) + { + WidgetPaint.DrawScrollButton (g, bounds, top ? ScrollButton.Up : ScrollButton.Down, state == VisualStyles.PushButtonState.Pressed ? ButtonState.Pushed : ButtonState.Normal); + } + + public override bool UpDownBaseHasHotButtonStyle { + get { + return false; + } + } + #endregion + + #region VScrollBar + public override Size VScrollBarDefaultSize { + get { + return new Size (this.ScrollBarButtonSize, 80); + } + } + #endregion // VScrollBar + + #region TreeView + public override Size TreeViewDefaultSize { + get { + return new Size (121, 97); + } + } + + public override void TreeViewDrawNodePlusMinus (TreeView treeView, TreeNode node, Graphics dc, int x, int middle) + { + int height = treeView.ActualItemHeight - 2; + dc.FillRectangle (ResPool.GetSolidBrush (treeView.BackColor), (x + 4) - (height / 2), node.GetY() + 1, height, height); + + dc.DrawRectangle (SystemPens.ControlDarkDark, x, middle - 4, 8, 8); + + if (node.IsExpanded) { + dc.DrawLine (SystemPens.ControlDarkDark, x + 2, middle, x + 6, middle); + } else { + dc.DrawLine (SystemPens.ControlDarkDark, x + 2, middle, x + 6, middle); + dc.DrawLine (SystemPens.ControlDarkDark, x + 4, middle - 2, x + 4, middle + 2); + } + } + #endregion + + #region Managed window + public override int ManagedWindowTitleBarHeight (InternalWindowManager wm) + { + if (wm.IsToolWindow && !wm.IsMinimized) + return SystemInformation.ToolWindowCaptionHeight; + if (wm.Form.FormBorderStyle == FormBorderStyle.None) + return 0; + return SystemInformation.CaptionHeight; + } + + public override int ManagedWindowBorderWidth (InternalWindowManager wm) + { + if ((wm.IsToolWindow && wm.form.FormBorderStyle == FormBorderStyle.FixedToolWindow) || + wm.IsMinimized) + return 3; + else + return 4; + } + + public override int ManagedWindowIconWidth (InternalWindowManager wm) + { + return ManagedWindowTitleBarHeight (wm) - 5; + } + + public override void ManagedWindowSetButtonLocations (InternalWindowManager wm) + { + TitleButtons buttons = wm.TitleButtons; + Form form = wm.form; + + buttons.HelpButton.Visible = form.HelpButton; + + foreach (TitleButton button in buttons) { + button.Visible = false; + } + + switch (form.FormBorderStyle) { + case FormBorderStyle.None: + if (form.WindowState != FormWindowState.Normal) + goto case FormBorderStyle.Sizable; + break; + case FormBorderStyle.FixedToolWindow: + case FormBorderStyle.SizableToolWindow: + buttons.CloseButton.Visible = true; + if (form.WindowState != FormWindowState.Normal) + goto case FormBorderStyle.Sizable; + break; + case FormBorderStyle.FixedSingle: + case FormBorderStyle.Fixed3D: + case FormBorderStyle.FixedDialog: + case FormBorderStyle.Sizable: + switch (form.WindowState) { + case FormWindowState.Normal: + buttons.MinimizeButton.Visible = true; + buttons.MaximizeButton.Visible = true; + buttons.RestoreButton.Visible = false; + break; + case FormWindowState.Maximized: + buttons.MinimizeButton.Visible = true; + buttons.MaximizeButton.Visible = false; + buttons.RestoreButton.Visible = true; + break; + case FormWindowState.Minimized: + buttons.MinimizeButton.Visible = false; + buttons.MaximizeButton.Visible = true; + buttons.RestoreButton.Visible = true; + break; + } + buttons.CloseButton.Visible = true; + break; + } + + // Respect MinimizeBox/MaximizeBox + if (form.MinimizeBox == false && form.MaximizeBox == false) { + buttons.MinimizeButton.Visible = false; + buttons.MaximizeButton.Visible = false; + } else if (form.MinimizeBox == false) + buttons.MinimizeButton.State = ButtonState.Inactive; + else if (form.MaximizeBox == false) + buttons.MaximizeButton.State = ButtonState.Inactive; + + int bw = ManagedWindowBorderWidth (wm); + Size btsize = ManagedWindowButtonSize (wm); + int btw = btsize.Width; + int bth = btsize.Height; + int top = bw + 2; + int left = form.Width - bw - btw - ManagedWindowSpacingAfterLastTitleButton; + + if ((!wm.IsToolWindow || wm.IsMinimized) && wm.HasBorders) { + buttons.CloseButton.Rectangle = new Rectangle (left, top, btw, bth); + left -= 2 + btw; + + if (buttons.MaximizeButton.Visible) { + buttons.MaximizeButton.Rectangle = new Rectangle (left, top, btw, bth); + left -= 2 + btw; + } + if (buttons.RestoreButton.Visible) { + buttons.RestoreButton.Rectangle = new Rectangle (left, top, btw, bth); + left -= 2 + btw; + } + + buttons.MinimizeButton.Rectangle = new Rectangle (left, top, btw, bth); + left -= 2 + btw; + } else if (wm.IsToolWindow) { + buttons.CloseButton.Rectangle = new Rectangle (left, top, btw, bth); + left -= 2 + btw; + } + } + + protected virtual Rectangle ManagedWindowDrawTitleBarAndBorders (Graphics dc, Rectangle clip, InternalWindowManager wm) + { + Form form = wm.Form; + int tbheight = ManagedWindowTitleBarHeight (wm); + int bdwidth = ManagedWindowBorderWidth (wm); + Color titlebar_color = Color.FromArgb (255, 10, 36, 106); + Color titlebar_color2 = Color.FromArgb (255, 166, 202, 240); + Color color = ThemeEngine.Current.ColorControlDark; + Color color2 = Color.FromArgb (255, 192, 192, 192); + + Pen pen = ResPool.GetPen (ColorControl); + Rectangle borders = new Rectangle (0, 0, form.Width, form.Height); + WidgetPaint.DrawBorder3D (dc, borders, Border3DStyle.Raised); + // The 3d border is only 2 pixels wide, so we draw the innermost pixels ourselves + borders = new Rectangle (2, 2, form.Width - 5, form.Height - 5); + for (int i = 2; i < bdwidth; i++) { + dc.DrawRectangle (pen, borders); + borders.Inflate (-1, -1); + } + + + bool draw_titlebar_enabled = false; + if (wm.Form.Parent != null && wm.Form.Parent is Form) { + draw_titlebar_enabled = false; + } else if (wm.IsActive && !wm.IsMaximized) { + draw_titlebar_enabled = true; + } + if (draw_titlebar_enabled) { + color = titlebar_color; + color2 = titlebar_color2; + } + + Rectangle tb = new Rectangle (bdwidth, bdwidth, form.Width - (bdwidth * 2), tbheight - 1); + + // HACK: For now always draw the titlebar until we get updates better + if (tb.Width > 0 && tb.Height > 0) { + using (System.Drawing.Drawing2D.LinearGradientBrush gradient = new LinearGradientBrush (tb, color, color2, LinearGradientMode.Horizontal)) + { + dc.FillRectangle (gradient, tb); + } + } + + if (!wm.IsMinimized) + // Draw the line just beneath the title bar + dc.DrawLine (ResPool.GetPen (SystemColors.Control), bdwidth, + tbheight + bdwidth - 1, form.Width - bdwidth - 1, + tbheight + bdwidth - 1); + return tb; + } + + public override void DrawManagedWindowDecorations (Graphics dc, Rectangle clip, InternalWindowManager wm) + { +#if debug + Console.WriteLine (DateTime.Now.ToLongTimeString () + " DrawManagedWindowDecorations"); + dc.FillRectangle (Brushes.Black, clip); +#endif + Rectangle tb = ManagedWindowDrawTitleBarAndBorders (dc, clip, wm); + + Form form = wm.Form; + if (wm.ShowIcon) { + Rectangle icon = ManagedWindowGetTitleBarIconArea (wm); + if (icon.IntersectsWith (clip)) + dc.DrawIcon (form.Icon, icon); + const int SpacingBetweenIconAndCaption = 2; + tb.Width -= icon.Right + SpacingBetweenIconAndCaption - tb.X ; + tb.X = icon.Right + SpacingBetweenIconAndCaption; + } + + foreach (TitleButton button in wm.TitleButtons.AllButtons) { + tb.Width -= Math.Max (0, tb.Right - DrawTitleButton (dc, button, clip, form)); + } + const int SpacingBetweenCaptionAndLeftMostButton = 3; + tb.Width -= SpacingBetweenCaptionAndLeftMostButton; + + string window_caption = form.Text; + window_caption = window_caption.Replace (Environment.NewLine, string.Empty); + + if (window_caption != null && window_caption != string.Empty) { + StringFormat format = new StringFormat (); + format.FormatFlags = StringFormatFlags.NoWrap; + format.Trimming = StringTrimming.EllipsisCharacter; + format.LineAlignment = StringAlignment.Center; + + if (tb.IntersectsWith (clip)) + dc.DrawString (window_caption, WindowBorderFont, + ThemeEngine.Current.ResPool.GetSolidBrush (Color.White), + tb, format); + } + } + + public override Size ManagedWindowButtonSize (InternalWindowManager wm) + { + int height = ManagedWindowTitleBarHeight (wm); + if (!wm.IsMaximized && !wm.IsMinimized) { + if (wm.IsToolWindow) + return new Size (SystemInformation.ToolWindowCaptionButtonSize.Width - 2, + height - 5); + if (wm.Form.FormBorderStyle == FormBorderStyle.None) + return Size.Empty; + } else + height = SystemInformation.CaptionHeight; + + return new Size (SystemInformation.CaptionButtonSize.Width - 2, + height - 5); + } + + private int DrawTitleButton (Graphics dc, TitleButton button, Rectangle clip, Form form) + { + if (!button.Visible) { + return int.MaxValue; + } + + if (button.Rectangle.IntersectsWith (clip)) { + ManagedWindowDrawTitleButton (dc, button, clip, form); + } + return button.Rectangle.Left; + } + + protected virtual void ManagedWindowDrawTitleButton (Graphics dc, TitleButton button, Rectangle clip, Form form) + { + dc.FillRectangle (SystemBrushes.Control, button.Rectangle); + + WidgetPaint.DrawCaptionButton (dc, button.Rectangle, + button.Caption, button.State); + } + + public override Rectangle ManagedWindowGetTitleBarIconArea (InternalWindowManager wm) + { + int bw = ManagedWindowBorderWidth (wm); + return new Rectangle (bw + 3, bw + 2, wm.IconWidth, wm.IconWidth); + } + + public override Size ManagedWindowGetMenuButtonSize (InternalWindowManager wm) + { + Size result = SystemInformation.MenuButtonSize; + result.Width -= 2; + result.Height -= 4; + return result; + } + + public override bool ManagedWindowTitleButtonHasHotElementStyle (TitleButton button, Form form) + { + return false; + } + + public override void ManagedWindowDrawMenuButton (Graphics dc, TitleButton button, Rectangle clip, InternalWindowManager wm) + { + dc.FillRectangle (SystemBrushes.Control, button.Rectangle); + WidgetPaint.DrawCaptionButton (dc, button.Rectangle, + button.Caption, button.State); + } + + public override void ManagedWindowOnSizeInitializedOrChanged (Form form) + { + } + #endregion + + #region WidgetPaint + public override void CPDrawBorder (Graphics graphics, Rectangle bounds, Color leftColor, int leftWidth, + ButtonBorderStyle leftStyle, Color topColor, int topWidth, ButtonBorderStyle topStyle, + Color rightColor, int rightWidth, ButtonBorderStyle rightStyle, Color bottomColor, + int bottomWidth, ButtonBorderStyle bottomStyle) { + DrawBorderInternal(graphics, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom-1, leftWidth, leftColor, leftStyle, Border3DSide.Left); + DrawBorderInternal(graphics, bounds.Left, bounds.Top, bounds.Right-1, bounds.Top, topWidth, topColor, topStyle, Border3DSide.Top); + DrawBorderInternal(graphics, bounds.Right-1, bounds.Top, bounds.Right-1, bounds.Bottom-1, rightWidth, rightColor, rightStyle, Border3DSide.Right); + DrawBorderInternal(graphics, bounds.Left, bounds.Bottom-1, bounds.Right-1, bounds.Bottom-1, bottomWidth, bottomColor, bottomStyle, Border3DSide.Bottom); + } + + public override void CPDrawBorder (Graphics graphics, RectangleF bounds, Color leftColor, int leftWidth, + ButtonBorderStyle leftStyle, Color topColor, int topWidth, ButtonBorderStyle topStyle, + Color rightColor, int rightWidth, ButtonBorderStyle rightStyle, Color bottomColor, + int bottomWidth, ButtonBorderStyle bottomStyle) { + DrawBorderInternal(graphics, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom-1, leftWidth, leftColor, leftStyle, Border3DSide.Left); + DrawBorderInternal(graphics, bounds.Left, bounds.Top, bounds.Right-1, bounds.Top, topWidth, topColor, topStyle, Border3DSide.Top); + DrawBorderInternal(graphics, bounds.Right-1, bounds.Top, bounds.Right-1, bounds.Bottom-1, rightWidth, rightColor, rightStyle, Border3DSide.Right); + DrawBorderInternal(graphics, bounds.Left, bounds.Bottom-1, bounds.Right-1, bounds.Bottom-1, bottomWidth, bottomColor, bottomStyle, Border3DSide.Bottom); + } + + public override void CPDrawBorder3D (Graphics graphics, Rectangle rectangle, Border3DStyle style, Border3DSide sides) { + CPDrawBorder3D(graphics, rectangle, style, sides, ColorControl); + } + + public override void CPDrawBorder3D (Graphics graphics, Rectangle rectangle, Border3DStyle style, Border3DSide sides, Color control_color) + { + Pen penTopLeft; + Pen penTopLeftInner; + Pen penBottomRight; + Pen penBottomRightInner; + Rectangle rect= new Rectangle (rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); + bool is_ColorControl = control_color.ToArgb () == ColorControl.ToArgb () ? true : false; + + if ((style & Border3DStyle.Adjust) != 0) { + rect.Y -= 2; + rect.X -= 2; + rect.Width += 4; + rect.Height += 4; + } + + penTopLeft = penTopLeftInner = penBottomRight = penBottomRightInner = is_ColorControl ? SystemPens.Control : ResPool.GetPen (control_color); + + CPColor cpcolor = CPColor.Empty; + + if (!is_ColorControl) + cpcolor = ResPool.GetCPColor (control_color); + + switch (style) { + case Border3DStyle.Raised: + penTopLeftInner = is_ColorControl ? SystemPens.ControlLightLight : ResPool.GetPen (cpcolor.LightLight); + penBottomRight = is_ColorControl ? SystemPens.ControlDarkDark : ResPool.GetPen (cpcolor.DarkDark); + penBottomRightInner = is_ColorControl ? SystemPens.ControlDark : ResPool.GetPen (cpcolor.Dark); + break; + case Border3DStyle.Sunken: + penTopLeft = is_ColorControl ? SystemPens.ControlDark : ResPool.GetPen (cpcolor.Dark); + penTopLeftInner = is_ColorControl ? SystemPens.ControlDarkDark : ResPool.GetPen (cpcolor.DarkDark); + penBottomRight = is_ColorControl ? SystemPens.ControlLightLight : ResPool.GetPen (cpcolor.LightLight); + break; + case Border3DStyle.Etched: + penTopLeft = penBottomRightInner = is_ColorControl ? SystemPens.ControlDark : ResPool.GetPen (cpcolor.Dark); + penTopLeftInner = penBottomRight = is_ColorControl ? SystemPens.ControlLightLight : ResPool.GetPen (cpcolor.LightLight); + break; + case Border3DStyle.RaisedOuter: + penBottomRight = is_ColorControl ? SystemPens.ControlDarkDark : ResPool.GetPen (cpcolor.DarkDark); + break; + case Border3DStyle.SunkenOuter: + penTopLeft = is_ColorControl ? SystemPens.ControlDark : ResPool.GetPen (cpcolor.Dark); + penBottomRight = is_ColorControl ? SystemPens.ControlLightLight : ResPool.GetPen (cpcolor.LightLight); + break; + case Border3DStyle.RaisedInner: + penTopLeft = is_ColorControl ? SystemPens.ControlLightLight : ResPool.GetPen (cpcolor.LightLight); + penBottomRight = is_ColorControl ? SystemPens.ControlDark : ResPool.GetPen (cpcolor.Dark); + break; + case Border3DStyle.SunkenInner: + penTopLeft = is_ColorControl ? SystemPens.ControlDarkDark : ResPool.GetPen (cpcolor.DarkDark); + break; + case Border3DStyle.Flat: + penTopLeft = penBottomRight = is_ColorControl ? SystemPens.ControlDark : ResPool.GetPen (cpcolor.Dark); + break; + case Border3DStyle.Bump: + penTopLeftInner = penBottomRight = is_ColorControl ? SystemPens.ControlDarkDark : ResPool.GetPen (cpcolor.DarkDark); + break; + default: + break; + } + + bool inner = ((style != Border3DStyle.RaisedOuter) && (style != Border3DStyle.SunkenOuter)); + + if ((sides & Border3DSide.Middle) != 0) { + Brush brush = is_ColorControl ? SystemBrushes.Control : ResPool.GetSolidBrush (control_color); + graphics.FillRectangle (brush, rect); + } + + if ((sides & Border3DSide.Left) != 0) { + graphics.DrawLine (penTopLeft, rect.Left, rect.Bottom - 2, rect.Left, rect.Top); + if ((rect.Width > 2) && inner) + graphics.DrawLine (penTopLeftInner, rect.Left + 1, rect.Bottom - 2, rect.Left + 1, rect.Top); + } + + if ((sides & Border3DSide.Top) != 0) { + graphics.DrawLine (penTopLeft, rect.Left, rect.Top, rect.Right - 2, rect.Top); + if ((rect.Height > 2) && inner) + graphics.DrawLine (penTopLeftInner, rect.Left + 1, rect.Top + 1, rect.Right - 3, rect.Top + 1); + } + + if ((sides & Border3DSide.Right) != 0) { + graphics.DrawLine (penBottomRight, rect.Right - 1, rect.Top, rect.Right - 1, rect.Bottom - 1); + if ((rect.Width > 3) && inner) + graphics.DrawLine (penBottomRightInner, rect.Right - 2, rect.Top + 1, rect.Right - 2, rect.Bottom - 2); + } + + if ((sides & Border3DSide.Bottom) != 0) { + graphics.DrawLine (penBottomRight, rect.Left, rect.Bottom - 1, rect.Right - 1, rect.Bottom - 1); + if ((rect.Height > 3) && inner) + graphics.DrawLine (penBottomRightInner, rect.Left + 1, rect.Bottom - 2, rect.Right - 2, rect.Bottom - 2); + } + } + + public override void CPDrawButton (Graphics dc, Rectangle rectangle, ButtonState state) + { + CPDrawButtonInternal (dc, rectangle, state, SystemPens.ControlDarkDark, SystemPens.ControlDark, SystemPens.ControlLight); + } + + private void CPDrawButtonInternal (Graphics dc, Rectangle rectangle, ButtonState state, Pen DarkPen, Pen NormalPen, Pen LightPen) + { + // sadly enough, the rectangle gets always filled with a hatchbrush + dc.FillRectangle (ResPool.GetHatchBrush (HatchStyle.Percent50, + Color.FromArgb (Clamp (ColorControl.R + 3, 0, 255), + ColorControl.G, ColorControl.B), + ColorControl), + rectangle.X + 1, rectangle.Y + 1, rectangle.Width - 2, rectangle.Height - 2); + + if ((state & ButtonState.All) == ButtonState.All || ((state & ButtonState.Checked) == ButtonState.Checked && (state & ButtonState.Flat) == ButtonState.Flat)) { + dc.FillRectangle (ResPool.GetHatchBrush (HatchStyle.Percent50, ColorControlLight, ColorControl), rectangle.X + 2, rectangle.Y + 2, rectangle.Width - 4, rectangle.Height - 4); + + dc.DrawRectangle (SystemPens.ControlDark, rectangle.X, rectangle.Y, rectangle.Width - 1, rectangle.Height - 1); + } else + if ((state & ButtonState.Flat) == ButtonState.Flat) { + dc.DrawRectangle (SystemPens.ControlDark, rectangle.X, rectangle.Y, rectangle.Width - 1, rectangle.Height - 1); + } else + if ((state & ButtonState.Checked) == ButtonState.Checked) { + dc.FillRectangle (ResPool.GetHatchBrush (HatchStyle.Percent50, ColorControlLight, ColorControl), rectangle.X + 2, rectangle.Y + 2, rectangle.Width - 4, rectangle.Height - 4); + + Pen pen = DarkPen; + dc.DrawLine (pen, rectangle.X, rectangle.Y, rectangle.X, rectangle.Bottom - 2); + dc.DrawLine (pen, rectangle.X + 1, rectangle.Y, rectangle.Right - 2, rectangle.Y); + + pen = NormalPen; + dc.DrawLine (pen, rectangle.X + 1, rectangle.Y + 1, rectangle.X + 1, rectangle.Bottom - 3); + dc.DrawLine (pen, rectangle.X + 2, rectangle.Y + 1, rectangle.Right - 3, rectangle.Y + 1); + + pen = LightPen; + dc.DrawLine (pen, rectangle.X, rectangle.Bottom - 1, rectangle.Right - 2, rectangle.Bottom - 1); + dc.DrawLine (pen, rectangle.Right - 1, rectangle.Y, rectangle.Right - 1, rectangle.Bottom - 1); + } else + if (((state & ButtonState.Pushed) == ButtonState.Pushed) && ((state & ButtonState.Normal) == ButtonState.Normal)) { + Pen pen = DarkPen; + dc.DrawLine (pen, rectangle.X, rectangle.Y, rectangle.X, rectangle.Bottom - 2); + dc.DrawLine (pen, rectangle.X + 1, rectangle.Y, rectangle.Right - 2, rectangle.Y); + + pen = NormalPen; + dc.DrawLine (pen, rectangle.X + 1, rectangle.Y + 1, rectangle.X + 1, rectangle.Bottom - 3); + dc.DrawLine (pen, rectangle.X + 2, rectangle.Y + 1, rectangle.Right - 3, rectangle.Y + 1); + + pen = LightPen; + dc.DrawLine (pen, rectangle.X, rectangle.Bottom - 1, rectangle.Right - 2, rectangle.Bottom - 1); + dc.DrawLine (pen, rectangle.Right - 1, rectangle.Y, rectangle.Right - 1, rectangle.Bottom - 1); + } else + if (((state & ButtonState.Inactive) == ButtonState.Inactive) || ((state & ButtonState.Normal) == ButtonState.Normal)) { + Pen pen = LightPen; + dc.DrawLine (pen, rectangle.X, rectangle.Y, rectangle.Right - 2, rectangle.Y); + dc.DrawLine (pen, rectangle.X, rectangle.Y, rectangle.X, rectangle.Bottom - 2); + + pen = NormalPen; + dc.DrawLine (pen, rectangle.X + 1, rectangle.Bottom - 2, rectangle.Right - 2, rectangle.Bottom - 2); + dc.DrawLine (pen, rectangle.Right - 2, rectangle.Y + 1, rectangle.Right - 2, rectangle.Bottom - 3); + + pen = DarkPen; + dc.DrawLine (pen, rectangle.X, rectangle.Bottom - 1, rectangle.Right - 1, rectangle.Bottom - 1); + dc.DrawLine (pen, rectangle.Right - 1, rectangle.Y, rectangle.Right - 1, rectangle.Bottom - 2); + } + } + + + public override void CPDrawCaptionButton (Graphics graphics, Rectangle rectangle, CaptionButton button, ButtonState state) { + Rectangle captionRect; + int lineWidth; + + CPDrawButtonInternal (graphics, rectangle, state, SystemPens.ControlDarkDark, SystemPens.ControlDark, SystemPens.ControlLightLight); + + if (rectangle.Width cb_rect.Width) ? cb_rect.Width : cb_rect.Height; + + int x_pos = Math.Max (0, cb_rect.X + (cb_rect.Width / 2) - check_box_visible_size / 2); + int y_pos = Math.Max (0, cb_rect.Y + (cb_rect.Height / 2) - check_box_visible_size / 2); + + Rectangle rect = new Rectangle (x_pos, y_pos, check_box_visible_size, check_box_visible_size); + + if (((state & ButtonState.Pushed) == ButtonState.Pushed) || ((state & ButtonState.Inactive) == ButtonState.Inactive)) { + dc.FillRectangle (ResPool.GetHatchBrush (HatchStyle.Percent50, + Color.FromArgb (Clamp (ColorControl.R + 3, 0, 255), + ColorControl.G, ColorControl.B), + ColorControl), rect.X + 2, rect.Y + 2, rect.Width - 3, rect.Height - 3); + } else + dc.FillRectangle (SystemBrushes.ControlLightLight, rect.X + 2, rect.Y + 2, rect.Width - 3, rect.Height - 3); + + Pen pen = SystemPens.ControlDark; + dc.DrawLine (pen, rect.X, rect.Y, rect.X, rect.Bottom - 1); + dc.DrawLine (pen, rect.X + 1, rect.Y, rect.Right - 1, rect.Y); + + pen = SystemPens.ControlDarkDark; + dc.DrawLine (pen, rect.X + 1, rect.Y + 1, rect.X + 1, rect.Bottom - 2); + dc.DrawLine (pen, rect.X + 2, rect.Y + 1, rect.Right - 2, rect.Y + 1); + + pen = SystemPens.ControlLightLight; + dc.DrawLine (pen, rect.Right, rect.Y, rect.Right, rect.Bottom); + dc.DrawLine (pen, rect.X, rect.Bottom, rect.Right, rect.Bottom); + + // oh boy, matching ms is like fighting against windmills + using (Pen h_pen = new Pen (ResPool.GetHatchBrush (HatchStyle.Percent50, + Color.FromArgb (Clamp (ColorControl.R + 3, 0, 255), + ColorControl.G, ColorControl.B), ColorControl))) { + dc.DrawLine (h_pen, rect.X + 1, rect.Bottom - 1, rect.Right - 1, rect.Bottom - 1); + dc.DrawLine (h_pen, rect.Right - 1, rect.Y + 1, rect.Right - 1, rect.Bottom - 1); + } + + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + check_pen = SystemPens.ControlDark; + } + + if ((state & ButtonState.Checked) == ButtonState.Checked) { + int check_size = (cb_rect.Height > cb_rect.Width) ? cb_rect.Width / 2: cb_rect.Height / 2; + + if (check_size < 7) { + int lineWidth = Math.Max (3, check_size / 3); + int Scale = Math.Max (1, check_size / 9); + + Rectangle rect = new Rectangle (cb_rect.X + (cb_rect.Width / 2) - (int)Math.Ceiling ((float)check_size / 2) - 1, cb_rect.Y + (cb_rect.Height / 2) - (check_size / 2) - 1, + check_size, check_size); + + for (int i = 0; i < lineWidth; i++) { + dc.DrawLine (check_pen, rect.Left + lineWidth / 2, rect.Top + lineWidth + i, rect.Left + lineWidth / 2 + 2 * Scale, rect.Top + lineWidth + 2 * Scale + i); + dc.DrawLine (check_pen, rect.Left + lineWidth / 2 + 2 * Scale, rect.Top + lineWidth + 2 * Scale + i, rect.Left + lineWidth / 2 + 6 * Scale, rect.Top + lineWidth - 2 * Scale + i); + } + } else { + int lineWidth = Math.Max (3, check_size / 3) + 1; + + int x_half = cb_rect.Width / 2; + int y_half = cb_rect.Height / 2; + + Rectangle rect = new Rectangle (cb_rect.X + x_half - (check_size / 2) - 1, cb_rect.Y + y_half - (check_size / 2), + check_size, check_size); + + int gradient_left = check_size / 3; + int gradient_right = check_size - gradient_left - 1; + + + for (int i = 0; i < lineWidth; i++) { + dc.DrawLine (check_pen, rect.X, rect.Bottom - 1 - gradient_left - i, rect.X + gradient_left, rect.Bottom - 1 - i); + dc.DrawLine (check_pen, rect.X + gradient_left, rect.Bottom - 1 - i, rect.Right - 1, rect.Bottom - i - 1 - gradient_right); + } + } + } + } + + public override void CPDrawComboButton (Graphics graphics, Rectangle rectangle, ButtonState state) { + Point[] arrow = new Point[3]; + Point P1; + Point P2; + Point P3; + int centerX; + int centerY; + int shiftX; + int shiftY; + Rectangle rect; + + if ((state & ButtonState.Checked)!=0) { + graphics.FillRectangle(ResPool.GetHatchBrush (HatchStyle.Percent50, ColorControlLightLight, ColorControlLight),rectangle); + } + + if ((state & ButtonState.Flat)!=0) { + WidgetPaint.DrawBorder(graphics, rectangle, ColorControlDark, ButtonBorderStyle.Solid); + } else { + if ((state & (ButtonState.Pushed | ButtonState.Checked))!=0) { + // this needs to render like a pushed button - jba + // CPDrawBorder3D(graphics, rectangle, Border3DStyle.Sunken, Border3DSide.Left | Border3DSide.Top | Border3DSide.Right | Border3DSide.Bottom, ColorControl); + Rectangle trace_rectangle = new Rectangle(rectangle.X, rectangle.Y, Math.Max (rectangle.Width-1, 0), Math.Max (rectangle.Height-1, 0)); + graphics.DrawRectangle (SystemPens.ControlDark, trace_rectangle); + } else { + CPDrawBorder3D(graphics, rectangle, Border3DStyle.Raised, Border3DSide.Left | Border3DSide.Top | Border3DSide.Right | Border3DSide.Bottom, ColorControl); + } + } + + rect=new Rectangle(rectangle.X+rectangle.Width/4, rectangle.Y+rectangle.Height/4, rectangle.Width/2, rectangle.Height/2); + centerX=rect.Left+rect.Width/2; + centerY=rect.Top+rect.Height/2; + shiftX=Math.Max(1, rect.Width/8); + shiftY=Math.Max(1, rect.Height/8); + + if ((state & ButtonState.Pushed)!=0) { + shiftX++; + shiftY++; + } + + rect.Y-=shiftY; + centerY-=shiftY; + P1=new Point(rect.Left, centerY); + P2=new Point(rect.Right, centerY); + P3=new Point(centerX, rect.Bottom); + + arrow[0]=P1; + arrow[1]=P2; + arrow[2]=P3; + + /* Draw the arrow */ + if ((state & ButtonState.Inactive)!=0) { + /* Move away from the shadow */ + arrow[0].X += 1; arrow[0].Y += 1; + arrow[1].X += 1; arrow[1].Y += 1; + arrow[2].X += 1; arrow[2].Y += 1; + + graphics.FillPolygon(SystemBrushes.ControlLightLight, arrow, FillMode.Winding); + + arrow[0]=P1; + arrow[1]=P2; + arrow[2]=P3; + + graphics.FillPolygon(SystemBrushes.ControlDark, arrow, FillMode.Winding); + } else { + graphics.FillPolygon(SystemBrushes.ControlText, arrow, FillMode.Winding); + } + } + + public override void CPDrawContainerGrabHandle (Graphics graphics, Rectangle bounds) + { + Pen pen = Pens.Black; + Rectangle rect = new Rectangle (bounds.X, bounds.Y, bounds.Width - 1, bounds.Height - 1); // Dunno why, but MS does it that way, too + int X; + int Y; + + graphics.FillRectangle (SystemBrushes.ControlLightLight, rect); + graphics.DrawRectangle (pen, rect); + + X = rect.X + rect.Width / 2; + Y = rect.Y + rect.Height / 2; + + /* Draw the cross */ + graphics.DrawLine (pen, X, rect.Y + 2, X, rect.Bottom - 2); + graphics.DrawLine (pen, rect.X + 2, Y, rect.Right - 2, Y); + + /* Draw 'arrows' for vertical lines */ + graphics.DrawLine (pen, X - 1, rect.Y + 3, X + 1, rect.Y + 3); + graphics.DrawLine (pen, X - 1, rect.Bottom - 3, X + 1, rect.Bottom - 3); + + /* Draw 'arrows' for horizontal lines */ + graphics.DrawLine (pen, rect.X + 3, Y - 1, rect.X + 3, Y + 1); + graphics.DrawLine (pen, rect.Right - 3, Y - 1, rect.Right - 3, Y + 1); + } + + public virtual void DrawFlatStyleFocusRectangle (Graphics graphics, Rectangle rectangle, ButtonBase button, Color foreColor, Color backColor) { + // make a rectange to trace around border of the button + Rectangle trace_rectangle = new Rectangle(rectangle.X, rectangle.Y, Math.Max (rectangle.Width-1, 0), Math.Max (rectangle.Height-1, 0)); + + Color outerColor = foreColor; + // adjust focus color according to the flatstyle + if (button.FlatStyle == FlatStyle.Popup && !button.is_pressed) { + outerColor = (backColor.ToArgb () == ColorControl.ToArgb ()) ? WidgetPaint.Dark(ColorControl) : ColorControlText; + } + + // draw the outer rectangle + graphics.DrawRectangle (ResPool.GetPen (outerColor), trace_rectangle); + + // draw the inner rectangle + if (button.FlatStyle == FlatStyle.Popup) { + DrawInnerFocusRectangle (graphics, Rectangle.Inflate (rectangle, -4, -4), backColor); + } else { + // draw a flat inner rectangle + Pen pen = ResPool.GetPen (WidgetPaint.LightLight (backColor)); + graphics.DrawRectangle(pen, Rectangle.Inflate (trace_rectangle, -4, -4)); + } + } + + public virtual void DrawInnerFocusRectangle(Graphics graphics, Rectangle rectangle, Color backColor) + { + // make a rectange to trace around border of the button + Rectangle trace_rectangle = new Rectangle(rectangle.X, rectangle.Y, Math.Max (rectangle.Width-1, 0), Math.Max (rectangle.Height-1, 0)); + +#if NotUntilCairoIsFixed + Color colorBackInverted = Color.FromArgb (Math.Abs (backColor.R-255), Math.Abs (backColor.G-255), Math.Abs (backColor.B-255)); + DashStyle oldStyle; // used for caching old penstyle + Pen pen = ResPool.GetPen (colorBackInverted); + + oldStyle = pen.DashStyle; + pen.DashStyle = DashStyle.Dot; + + graphics.DrawRectangle (pen, trace_rectangle); + pen.DashStyle = oldStyle; +#else + CPDrawFocusRectangle(graphics, trace_rectangle, Color.Wheat, backColor); +#endif + } + + + public override void CPDrawFocusRectangle (Graphics graphics, Rectangle rectangle, Color foreColor, Color backColor) + { + Rectangle rect = rectangle; + Pen pen; + HatchBrush brush; + + if (backColor.GetBrightness () >= 0.5) { + foreColor = Color.Transparent; + backColor = Color.Black; + + } else { + backColor = Color.FromArgb (Math.Abs (backColor.R-255), Math.Abs (backColor.G-255), Math.Abs (backColor.B-255)); + foreColor = Color.Black; + } + + brush = ResPool.GetHatchBrush (HatchStyle.Percent50, backColor, foreColor); + pen = new Pen (brush, 1); + + rect.Width--; + rect.Height--; + + graphics.DrawRectangle (pen, rect); + pen.Dispose (); + } + + public override void CPDrawGrabHandle (Graphics graphics, Rectangle rectangle, bool primary, bool enabled) + { + Brush sb; + Pen pen; + + if (primary == true) { + pen = Pens.Black; + if (enabled == true) { + sb = Brushes.White; + } else { + sb = SystemBrushes.Control; + } + } else { + pen = Pens.White; + if (enabled == true) { + sb = Brushes.Black; + } else { + sb = SystemBrushes.Control; + } + } + graphics.FillRectangle (sb, rectangle); + graphics.DrawRectangle (pen, rectangle); + } + + + public override void CPDrawGrid (Graphics graphics, Rectangle area, Size pixelsBetweenDots, Color backColor) { + Color foreColor; + int h; + int b; + int s; + + WidgetPaint.Color2HBS(backColor, out h, out b, out s); + + if (b>127) { + foreColor=Color.Black; + } else { + foreColor=Color.White; + } + + // still not perfect. it seems that ms calculates the position of the first dot or line + + using (Pen pen = new Pen (foreColor)) { + pen.DashPattern = new float [] {1.0f, pixelsBetweenDots.Width - 1}; + + for (int y = area.Top; y < area.Bottom; y += pixelsBetweenDots.Height) + graphics.DrawLine (pen, area.X, y, area.Right - 1, y); + } + } + + public override void CPDrawImageDisabled (Graphics graphics, Image image, int x, int y, Color background) { + /* + Microsoft seems to ignore the background and simply make + the image grayscale. At least when having > 256 colors on + the display. + */ + + if (imagedisabled_attributes == null) { + imagedisabled_attributes = new ImageAttributes (); + ColorMatrix colorMatrix=new ColorMatrix(new float[][] { + // This table would create a perfect grayscale image, based on luminance + // new float[]{0.3f,0.3f,0.3f,0,0}, + // new float[]{0.59f,0.59f,0.59f,0,0}, + // new float[]{0.11f,0.11f,0.11f,0,0}, + // new float[]{0,0,0,1,0,0}, + // new float[]{0,0,0,0,1,0}, + // new float[]{0,0,0,0,0,1} + + // This table generates a image that is grayscaled and then + // brightened up. Seems to match MS close enough. + new float[]{0.2f,0.2f,0.2f,0,0}, + new float[]{0.41f,0.41f,0.41f,0,0}, + new float[]{0.11f,0.11f,0.11f,0,0}, + new float[]{0.15f,0.15f,0.15f,1,0,0}, + new float[]{0.15f,0.15f,0.15f,0,1,0}, + new float[]{0.15f,0.15f,0.15f,0,0,1} + }); + + imagedisabled_attributes.SetColorMatrix (colorMatrix); + } + + graphics.DrawImage(image, new Rectangle(x, y, image.Width, image.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, imagedisabled_attributes); + + } + + + public override void CPDrawLockedFrame (Graphics graphics, Rectangle rectangle, bool primary) { + Pen penBorder; + Pen penInside; + + if (primary) { + penBorder = ResPool.GetSizedPen (Color.White, 2); + penInside = ResPool.GetPen (Color.Black); + } else { + penBorder = ResPool.GetSizedPen (Color.Black, 2); + penInside = ResPool.GetPen (Color.White); + } + penBorder.Alignment=PenAlignment.Inset; + penInside.Alignment=PenAlignment.Inset; + + graphics.DrawRectangle(penBorder, rectangle); + graphics.DrawRectangle(penInside, rectangle.X+2, rectangle.Y+2, rectangle.Width-5, rectangle.Height-5); + } + + + public override void CPDrawMenuGlyph (Graphics graphics, Rectangle rectangle, MenuGlyph glyph, Color color, Color backColor) { + Rectangle rect; + int lineWidth; + + if (backColor != Color.Empty) + graphics.FillRectangle (ResPool.GetSolidBrush (backColor), rectangle); + + Brush brush = ResPool.GetSolidBrush (color); + + switch(glyph) { + case MenuGlyph.Arrow: { + float height = rectangle.Height * 0.7f; + float width = height / 2.0f; + + PointF ddCenter = new PointF (rectangle.X + ((rectangle.Width-width) / 2.0f), rectangle.Y + (rectangle.Height / 2.0f)); + + PointF [] vertices = new PointF [3]; + vertices [0].X = ddCenter.X; + vertices [0].Y = ddCenter.Y - (height / 2.0f); + vertices [1].X = ddCenter.X; + vertices [1].Y = ddCenter.Y + (height / 2.0f); + vertices [2].X = ddCenter.X + width + 0.1f; + vertices [2].Y = ddCenter.Y; + + graphics.FillPolygon (brush, vertices); + + return; + } + + case MenuGlyph.Bullet: { + + lineWidth=Math.Max(2, rectangle.Width/3); + rect=new Rectangle(rectangle.X+lineWidth, rectangle.Y+lineWidth, rectangle.Width-lineWidth*2, rectangle.Height-lineWidth*2); + + graphics.FillEllipse(brush, rect); + + return; + } + + case MenuGlyph.Checkmark: { + + Pen pen = ResPool.GetPen (color); + lineWidth = Math.Max (2, rectangle.Width / 6); + rect = new Rectangle(rectangle.X + lineWidth, rectangle.Y + lineWidth, rectangle.Width - lineWidth * 2, rectangle.Height- lineWidth * 2); + + int Scale = Math.Max (1, rectangle.Width / 12); + int top = (rect.Y + lineWidth + ((rect.Height - ((2 * Scale) + lineWidth)) / 2)); + + for (int i=0; i rectangle.Height) ? (int)(rectangle.Height * 0.9f) : (int)(rectangle.Width * 0.9f); + int radius = ellipse_diameter / 2; + + Rectangle rb_rect = new Rectangle (rectangle.X + (rectangle.Width / 2) - radius, rectangle.Y + (rectangle.Height / 2) - radius, ellipse_diameter, ellipse_diameter); + + Brush brush = null; + + if ((state & ButtonState.All) == ButtonState.All) { + brush = ResPool.GetHatchBrush (HatchStyle.Percent50, Color.FromArgb (Clamp (ColorControl.R + 3, 0, 255), + ColorControl.G, ColorControl.B), ColorControl); + dot_color = cpcolor.Dark; + } else + if ((state & ButtonState.Flat) == ButtonState.Flat) { + if (((state & ButtonState.Inactive) == ButtonState.Inactive) || ((state & ButtonState.Pushed) == ButtonState.Pushed)) + brush = ResPool.GetHatchBrush (HatchStyle.Percent50, Color.FromArgb (Clamp (ColorControl.R + 3, 0, 255), ColorControl.G, ColorControl.B), ColorControl); + else + brush = SystemBrushes.ControlLightLight; + } else { + if (((state & ButtonState.Inactive) == ButtonState.Inactive) || ((state & ButtonState.Pushed) == ButtonState.Pushed)) + brush = ResPool.GetHatchBrush (HatchStyle.Percent50, Color.FromArgb (Clamp (ColorControl.R + 3, 0, 255), ColorControl.G, ColorControl.B), ColorControl); + else + brush = SystemBrushes.ControlLightLight; + + top_left_outer = cpcolor.Dark; + top_left_inner = cpcolor.DarkDark; + bottom_right_outer = cpcolor.Light; + bottom_right_inner = Color.Transparent; + + if ((state & ButtonState.Inactive) == ButtonState.Inactive) + dot_color = cpcolor.Dark; + } + + dc.FillEllipse (brush, rb_rect.X + 1, rb_rect.Y + 1, ellipse_diameter - 1, ellipse_diameter - 1); + + int line_width = Math.Max (1, (int)(ellipse_diameter * 0.08f)); + + dc.DrawArc (ResPool.GetSizedPen (top_left_outer, line_width), rb_rect, 135.0f, 180.0f); + dc.DrawArc (ResPool.GetSizedPen (top_left_inner, line_width), Rectangle.Inflate (rb_rect, -line_width, -line_width), 135.0f, 180.0f); + dc.DrawArc (ResPool.GetSizedPen (bottom_right_outer, line_width), rb_rect, 315.0f, 180.0f); + + if (bottom_right_inner != Color.Transparent) + dc.DrawArc (ResPool.GetSizedPen (bottom_right_inner, line_width), Rectangle.Inflate (rb_rect, -line_width, -line_width), 315.0f, 180.0f); + else + using (Pen h_pen = new Pen (ResPool.GetHatchBrush (HatchStyle.Percent50, Color.FromArgb (Clamp (ColorControl.R + 3, 0, 255), ColorControl.G, ColorControl.B), ColorControl), line_width)) { + dc.DrawArc (h_pen, Rectangle.Inflate (rb_rect, -line_width, -line_width), 315.0f, 180.0f); + } + + if ((state & ButtonState.Checked) == ButtonState.Checked) { + int inflate = line_width * 4; + Rectangle tmp = Rectangle.Inflate (rb_rect, -inflate, -inflate); + if (rectangle.Height > 13) { + tmp.X += 1; + tmp.Y += 1; + tmp.Height -= 1; + dc.FillEllipse (ResPool.GetSolidBrush (dot_color), tmp); + } else { + Pen pen = ResPool.GetPen (dot_color); + dc.DrawLine (pen, tmp.X, tmp.Y + (tmp.Height / 2), tmp.Right, tmp.Y + (tmp.Height / 2)); + dc.DrawLine (pen, tmp.X, tmp.Y + (tmp.Height / 2) + 1, tmp.Right, tmp.Y + (tmp.Height / 2) + 1); + + dc.DrawLine (pen, tmp.X + (tmp.Width / 2), tmp.Y, tmp.X + (tmp.Width / 2), tmp.Bottom); + dc.DrawLine (pen, tmp.X + (tmp.Width / 2) + 1, tmp.Y, tmp.X + (tmp.Width / 2) + 1, tmp.Bottom); + } + } + } + + public override void CPDrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style) { + + } + + + public override void CPDrawReversibleLine (Point start, Point end, Color backColor) { + + } + + + /* Scroll button: regular button + direction arrow */ + public override void CPDrawScrollButton (Graphics dc, Rectangle area, ScrollButton type, ButtonState state) + { + DrawScrollButtonPrimitive (dc, area, state); + + bool fill_rect = true; + int offset = 0; + + if ((state & ButtonState.Pushed) != 0) + offset = 1; + + // skip the border + Rectangle rect = new Rectangle (area.X + 2 + offset, area.Y + 2 + offset, area.Width - 4, area.Height - 4); + + Point [] arrow = new Point [3]; + for (int i = 0; i < 3; i++) + arrow [i] = new Point (); + + Pen pen = SystemPens.ControlText; + + if ((state & ButtonState.Inactive) != 0) { + pen = SystemPens.ControlDark; + } + + switch (type) { + default: + case ScrollButton.Down: + int x_middle = (int)Math.Round (rect.Width / 2.0f) - 1; + int y_middle = (int)Math.Round (rect.Height / 2.0f) - 1; + if (x_middle == 1) + x_middle = 2; + + int triangle_height; + + if (rect.Height < 8) { + triangle_height = 2; + fill_rect = false; + } else if (rect.Height == 11) { + triangle_height = 3; + } else { + triangle_height = (int)Math.Round (rect.Height / 3.0f); + } + + arrow [0].X = rect.X + x_middle; + arrow [0].Y = rect.Y + y_middle + triangle_height / 2; + + arrow [1].X = arrow [0].X + triangle_height - 1; + arrow [1].Y = arrow [0].Y - triangle_height + 1; + arrow [2].X = arrow [0].X - triangle_height + 1; + arrow [2].Y = arrow [1].Y; + + dc.DrawPolygon (pen, arrow); + + if ((state & ButtonState.Inactive) != 0) { + dc.DrawLine (SystemPens.ControlLightLight, arrow [1].X + 1, arrow [1].Y + 1, arrow [0].X + 1, arrow [0].Y + 1); + dc.DrawLine (SystemPens.ControlLightLight, arrow [1].X, arrow [1].Y + 1, arrow [0].X + 1, arrow [0].Y); + } + + if (fill_rect) { + for (int i = 0; i < arrow [0].Y - arrow [1].Y; i++) { + dc.DrawLine (pen, arrow [1].X, arrow [1].Y + i, arrow [2].X, arrow [1].Y + i); + arrow [1].X -= 1; + arrow [2].X += 1; + } + } + break; + + case ScrollButton.Up: + x_middle = (int)Math.Round (rect.Width / 2.0f) - 1; + y_middle = (int)Math.Round (rect.Height / 2.0f); + if (x_middle == 1) + x_middle = 2; + + if (y_middle == 1) + y_middle = 2; + + if (rect.Height < 8) { + triangle_height = 2; + fill_rect = false; + } else if (rect.Height == 11) { + triangle_height = 3; + } else { + triangle_height = (int)Math.Round (rect.Height / 3.0f); + } + + arrow [0].X = rect.X + x_middle; + arrow [0].Y = rect.Y + y_middle - triangle_height / 2; + + arrow [1].X = arrow [0].X + triangle_height - 1; + arrow [1].Y = arrow [0].Y + triangle_height - 1; + arrow [2].X = arrow [0].X - triangle_height + 1; + arrow [2].Y = arrow [1].Y; + + dc.DrawPolygon (pen, arrow); + + if ((state & ButtonState.Inactive) != 0) { + dc.DrawLine (SystemPens.ControlLightLight, arrow [1].X + 1, arrow [1].Y + 1, arrow [2].X + 1, arrow [1].Y + 1); + } + + if (fill_rect) { + for (int i = 0; i < arrow [1].Y - arrow [0].Y; i++) { + dc.DrawLine (pen, arrow [2].X, arrow [1].Y - i, arrow [1].X, arrow [1].Y - i); + arrow [1].X -= 1; + arrow [2].X += 1; + } + } + break; + + case ScrollButton.Left: + y_middle = (int)Math.Round (rect.Height / 2.0f) - 1; + if (y_middle == 1) + y_middle = 2; + + int triangle_width; + + if (rect.Width < 8) { + triangle_width = 2; + fill_rect = false; + } else if (rect.Width == 11) { + triangle_width = 3; + } else { + triangle_width = (int)Math.Round (rect.Width / 3.0f); + } + + arrow [0].X = rect.Left + triangle_width - 1; + arrow [0].Y = rect.Y + y_middle; + + if (arrow [0].X - 1 == rect.X) + arrow [0].X += 1; + + arrow [1].X = arrow [0].X + triangle_width - 1; + arrow [1].Y = arrow [0].Y - triangle_width + 1; + arrow [2].X = arrow [1].X; + arrow [2].Y = arrow [0].Y + triangle_width - 1; + + dc.DrawPolygon (pen, arrow); + + if ((state & ButtonState.Inactive) != 0) { + dc.DrawLine (SystemPens.ControlLightLight, arrow [1].X + 1, arrow [1].Y + 1, arrow [2].X + 1, arrow [2].Y + 1); + } + + if (fill_rect) { + for (int i = 0; i < arrow [2].X - arrow [0].X; i++) { + dc.DrawLine (pen, arrow [2].X - i, arrow [1].Y, arrow [2].X - i, arrow [2].Y); + arrow [1].Y += 1; + arrow [2].Y -= 1; + } + } + break; + + case ScrollButton.Right: + y_middle = (int)Math.Round (rect.Height / 2.0f) - 1; + if (y_middle == 1) + y_middle = 2; + + if (rect.Width < 8) { + triangle_width = 2; + fill_rect = false; + } else if (rect.Width == 11) { + triangle_width = 3; + } else { + triangle_width = (int)Math.Round (rect.Width / 3.0f); + } + + arrow [0].X = rect.Right - triangle_width - 1; + arrow [0].Y = rect.Y + y_middle; + + if (arrow [0].X - 1 == rect.X) + arrow [0].X += 1; + + arrow [1].X = arrow [0].X - triangle_width + 1; + arrow [1].Y = arrow [0].Y - triangle_width + 1; + arrow [2].X = arrow [1].X; + arrow [2].Y = arrow [0].Y + triangle_width - 1; + + dc.DrawPolygon (pen, arrow); + + if ((state & ButtonState.Inactive) != 0) { + dc.DrawLine (SystemPens.ControlLightLight, arrow [0].X + 1, arrow [0].Y + 1, arrow [2].X + 1, arrow [2].Y + 1); + dc.DrawLine (SystemPens.ControlLightLight, arrow [0].X, arrow [0].Y + 1, arrow [2].X + 1, arrow [2].Y); + } + + if (fill_rect) { + for (int i = 0; i < arrow [0].X - arrow [1].X; i++) { + dc.DrawLine (pen, arrow [2].X + i, arrow [1].Y, arrow [2].X + i, arrow [2].Y); + arrow [1].Y += 1; + arrow [2].Y -= 1; + } + } + break; + } + } + + public override void CPDrawSelectionFrame (Graphics graphics, bool active, Rectangle outsideRect, Rectangle insideRect, + Color backColor) { + + } + + + public override void CPDrawSizeGrip (Graphics dc, Color backColor, Rectangle bounds) + { + Pen pen_dark = ResPool.GetPen(WidgetPaint.Dark(backColor)); + Pen pen_light_light = ResPool.GetPen(WidgetPaint.LightLight(backColor)); + + for (int i = 2; i < bounds.Width - 2; i += 4) { + dc.DrawLine (pen_light_light, bounds.X + i, bounds.Bottom - 2, bounds.Right - 1, bounds.Y + i - 1); + dc.DrawLine (pen_dark, bounds.X + i + 1, bounds.Bottom - 2, bounds.Right - 1, bounds.Y + i); + dc.DrawLine (pen_dark, bounds.X + i + 2, bounds.Bottom - 2, bounds.Right - 1, bounds.Y + i + 1); + } + } + + private void DrawStringDisabled20 (Graphics g, string s, Font font, Rectangle layoutRectangle, Color color, TextFormatFlags flags, bool useDrawString) + { + CPColor cpcolor = ResPool.GetCPColor (color); + + layoutRectangle.Offset (1, 1); + TextRenderer.DrawTextInternal (g, s, font, layoutRectangle, cpcolor.LightLight, flags, useDrawString); + + layoutRectangle.Offset (-1, -1); + TextRenderer.DrawTextInternal (g, s, font, layoutRectangle, cpcolor.Dark, flags, useDrawString); + } + + public override void CPDrawStringDisabled (Graphics dc, string s, Font font, Color color, RectangleF layoutRectangle, StringFormat format) + { + CPColor cpcolor = ResPool.GetCPColor (color); + + dc.DrawString (s, font, ResPool.GetSolidBrush(cpcolor.LightLight), + new RectangleF(layoutRectangle.X + 1, layoutRectangle.Y + 1, layoutRectangle.Width, layoutRectangle.Height), + format); + dc.DrawString (s, font, ResPool.GetSolidBrush (cpcolor.Dark), layoutRectangle, format); + } + + public override void CPDrawStringDisabled (IDeviceContext dc, string s, Font font, Color color, Rectangle layoutRectangle, TextFormatFlags format) + { + CPColor cpcolor = ResPool.GetCPColor (color); + + layoutRectangle.Offset (1, 1); + TextRenderer.DrawText (dc, s, font, layoutRectangle, cpcolor.LightLight, format); + + layoutRectangle.Offset (-1, -1); + TextRenderer.DrawText (dc, s, font, layoutRectangle, cpcolor.Dark, format); + } + + public override void CPDrawVisualStyleBorder (Graphics graphics, Rectangle bounds) + { + graphics.DrawRectangle (SystemPens.ControlDarkDark, bounds); + } + + private static void DrawBorderInternal (Graphics graphics, int startX, int startY, int endX, int endY, + int width, Color color, ButtonBorderStyle style, Border3DSide side) + { + DrawBorderInternal (graphics, (float) startX, (float) startY, (float) endX, (float) endY, + width, color, style, side); + } + + private static void DrawBorderInternal (Graphics graphics, float startX, float startY, float endX, float endY, + int width, Color color, ButtonBorderStyle style, Border3DSide side) { + + Pen pen = null; + + switch (style) { + case ButtonBorderStyle.Solid: + case ButtonBorderStyle.Inset: + case ButtonBorderStyle.Outset: + pen = ThemeEngine.Current.ResPool.GetDashPen (color, DashStyle.Solid); + break; + case ButtonBorderStyle.Dashed: + pen = ThemeEngine.Current.ResPool.GetDashPen (color, DashStyle.Dash); + break; + case ButtonBorderStyle.Dotted: + pen = ThemeEngine.Current.ResPool.GetDashPen (color, DashStyle.Dot); + break; + default: + case ButtonBorderStyle.None: + return; + } + + switch(style) { + case ButtonBorderStyle.Outset: { + Color colorGrade; + int hue, brightness, saturation; + int brightnessSteps; + int brightnessDownSteps; + + WidgetPaint.Color2HBS(color, out hue, out brightness, out saturation); + + brightnessDownSteps=brightness/width; + if (brightness>127) { + brightnessSteps=Math.Max(6, (160-brightness)/width); + } else { + brightnessSteps=(127-brightness)/width; + } + + for (int i=0; i127) { + brightnessSteps=Math.Max(6, (160-brightness)/width); + } else { + brightnessSteps=(127-brightness)/width; + } + + for (int i=0; i= 0 && page.ImageIndex < tab.ImageList.Images.Count) { + int image_y = bounds.Y + (bounds.Height - tab.ImageList.ImageSize.Height) / 2; + tab.ImageList.Draw (dc, new Point (bounds.X, image_y), page.ImageIndex); + int image_occupied_space = tab.ImageList.ImageSize.Width + 2; + text_area.X += image_occupied_space; + text_area.Width -= image_occupied_space; + } + if (page.Text != null) + dc.DrawString (page.Text, tab.Font, SystemBrushes.ControlText, text_area, DefaultFormatting); + if (tab.Focused && is_selected && tab.ShowFocusCues) + WidgetPaint.DrawFocusRectangle (dc, bounds); + return 0; + } + static VisualStyleElement GetVisualStyleElement (TabWidget tabControl, TabPage tabPage, bool selected) + { + bool top_edge = tabPage.Row == tabControl.RowCount; + int tab_page_index = tabControl.TabPages.IndexOf (tabPage); + bool left_edge = true; + int index; + for (index = tabControl.SliderPos; index < tab_page_index; index++) + if (tabControl.TabPages [index].Row == tabPage.Row) { + left_edge = false; + break; + } + bool right_edge = true; + for (index = tab_page_index; index < tabControl.TabCount; index++) + if (tabControl.TabPages [index].Row == tabPage.Row) { + right_edge = false; + break; + } + if (!tabPage.Enabled) + #region Disabled + if (top_edge) + if (left_edge) + if (right_edge) + return VisualStyleElement.Tab.TopTabItem.Disabled; + else + return VisualStyleElement.Tab.TopTabItemLeftEdge.Disabled; + else + if (right_edge) + return VisualStyleElement.Tab.TopTabItemRightEdge.Disabled; + else + return VisualStyleElement.Tab.TopTabItem.Disabled; + else + if (left_edge) + if (right_edge) + return VisualStyleElement.Tab.TabItem.Disabled; + else + return VisualStyleElement.Tab.TabItemLeftEdge.Disabled; + else + if (right_edge) + return VisualStyleElement.Tab.TabItemRightEdge.Disabled; + else + return VisualStyleElement.Tab.TabItem.Disabled; + #endregion + else if (selected) + #region Pressed + if (top_edge) + if (left_edge) + if (right_edge) + return VisualStyleElement.Tab.TopTabItem.Pressed; + else + return VisualStyleElement.Tab.TopTabItemLeftEdge.Pressed; + else + if (right_edge) + return VisualStyleElement.Tab.TopTabItemRightEdge.Pressed; + else + return VisualStyleElement.Tab.TopTabItem.Pressed; + else + if (left_edge) + if (right_edge) + return VisualStyleElement.Tab.TabItem.Pressed; + else + return VisualStyleElement.Tab.TabItemLeftEdge.Pressed; + else + if (right_edge) + return VisualStyleElement.Tab.TabItemRightEdge.Pressed; + else + return VisualStyleElement.Tab.TabItem.Pressed; + #endregion + else if (tabControl.EnteredTabPage == tabPage) + #region Hot + if (top_edge) + if (left_edge) + if (right_edge) + return VisualStyleElement.Tab.TopTabItem.Hot; + else + return VisualStyleElement.Tab.TopTabItemLeftEdge.Hot; + else + if (right_edge) + return VisualStyleElement.Tab.TopTabItemRightEdge.Hot; + else + return VisualStyleElement.Tab.TopTabItem.Hot; + else + if (left_edge) + if (right_edge) + return VisualStyleElement.Tab.TabItem.Hot; + else + return VisualStyleElement.Tab.TabItemLeftEdge.Hot; + else + if (right_edge) + return VisualStyleElement.Tab.TabItemRightEdge.Hot; + else + return VisualStyleElement.Tab.TabItem.Hot; + #endregion + else + #region Normal + if (top_edge) + if (left_edge) + if (right_edge) + return VisualStyleElement.Tab.TopTabItemBothEdges.Normal; + else + return VisualStyleElement.Tab.TopTabItemLeftEdge.Normal; + else + if (right_edge) + return VisualStyleElement.Tab.TopTabItemRightEdge.Normal; + else + return VisualStyleElement.Tab.TopTabItem.Normal; + else + if (left_edge) + if (right_edge) + return VisualStyleElement.Tab.TabItemBothEdges.Normal; + else + return VisualStyleElement.Tab.TabItemLeftEdge.Normal; + else + if (right_edge) + return VisualStyleElement.Tab.TabItemRightEdge.Normal; + else + return VisualStyleElement.Tab.TabItem.Normal; + #endregion + } + public override bool HasHotElementStyles (TabWidget tabControl) + { + if (!ShouldPaint (tabControl)) + return base.HasHotElementStyles (tabControl); + return true; + } + protected override void DrawScrollButton (Graphics dc, Rectangle bounds, Rectangle clippingArea, ScrollButton button, PushButtonState state) + { + if (!ThemeVisualStyles.RenderClientAreas) { + base.DrawScrollButton (dc, bounds, clippingArea, button, state); + return; + } + VisualStyleElement element; + if (button == ScrollButton.Left) + switch (state) { + case PushButtonState.Hot: + element = VisualStyleElement.Spin.DownHorizontal.Hot; + break; + case PushButtonState.Pressed: + element = VisualStyleElement.Spin.DownHorizontal.Pressed; + break; + default: + element = VisualStyleElement.Spin.DownHorizontal.Normal; + break; + } + else + switch (state) { + case PushButtonState.Hot: + element = VisualStyleElement.Spin.UpHorizontal.Hot; + break; + case PushButtonState.Pressed: + element = VisualStyleElement.Spin.UpHorizontal.Pressed; + break; + default: + element = VisualStyleElement.Spin.UpHorizontal.Normal; + break; + } + if (!VisualStyleRenderer.IsElementDefined (element)) { + if (button == ScrollButton.Left) + switch (state) { + case PushButtonState.Hot: + element = VisualStyleElement.ScrollBar.ArrowButton.LeftHot; + break; + case PushButtonState.Pressed: + element = VisualStyleElement.ScrollBar.ArrowButton.LeftPressed; + break; + default: + element = VisualStyleElement.ScrollBar.ArrowButton.LeftNormal; + break; + } + else + switch (state) { + case PushButtonState.Hot: + element = VisualStyleElement.ScrollBar.ArrowButton.RightHot; + break; + case PushButtonState.Pressed: + element = VisualStyleElement.ScrollBar.ArrowButton.RightPressed; + break; + default: + element = VisualStyleElement.ScrollBar.ArrowButton.RightNormal; + break; + } + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.DrawScrollButton (dc, bounds, clippingArea, button, state); + return; + } + } + new VisualStyleRenderer (element).DrawBackground (dc, bounds, clippingArea); + } + } +} diff --git a/source/ShiftUI/Theming/VisualStyles/ToolStripPainter.cs b/source/ShiftUI/Theming/VisualStyles/ToolStripPainter.cs new file mode 100644 index 0000000..3ee1c1a --- /dev/null +++ b/source/ShiftUI/Theming/VisualStyles/ToolStripPainter.cs @@ -0,0 +1,213 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2008 George Giolfan +// +// Authors: +// George Giolfan (georgegiolfan@yahoo.com) + +using System.Drawing; +using ShiftUI.VisualStyles; +namespace ShiftUI.Theming.VisualStyles +{ + class ToolStripPainter : Default.ToolStripPainter + { + static bool IsDisabled (ToolStripItem toolStripItem) + { + return !toolStripItem.Enabled; + } + static bool IsPressed (ToolStripItem toolStripItem) + { + return toolStripItem.Pressed; + } + static bool IsChecked (ToolStripItem toolStripItem) + { + ToolStripButton tool_strip_button = toolStripItem as ToolStripButton; + if (tool_strip_button == null) + return false; + return tool_strip_button.Checked; + } + static bool IsHot (ToolStripItem toolStripItem) + { + return toolStripItem.Selected; + } + public override void OnRenderButtonBackground (ToolStripItemRenderEventArgs e) + { + if (!ThemeVisualStyles.RenderClientAreas) { + base.OnRenderButtonBackground (e); + return; + } + VisualStyleElement element; + if (IsDisabled (e.Item)) + element = VisualStyleElement.ToolBar.Button.Disabled; + else if (IsPressed (e.Item)) + element = VisualStyleElement.ToolBar.Button.Pressed; + else if (IsChecked (e.Item)) + if (IsHot (e.Item)) + element = VisualStyleElement.ToolBar.Button.HotChecked; + else + element = VisualStyleElement.ToolBar.Button.Checked; + else if (IsHot (e.Item)) + element = VisualStyleElement.ToolBar.Button.Hot; + else + element = VisualStyleElement.ToolBar.Button.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.OnRenderButtonBackground (e); + return; + } + new VisualStyleRenderer (element).DrawBackground (e.Graphics, e.Item.Bounds); + } + public override void OnRenderDropDownButtonBackground (ToolStripItemRenderEventArgs e) + { + if (!ThemeVisualStyles.RenderClientAreas) { + base.OnRenderDropDownButtonBackground (e); + return; + } + VisualStyleElement element; + if (IsDisabled (e.Item)) + element = VisualStyleElement.ToolBar.DropDownButton.Disabled; + else if (IsPressed (e.Item)) + element = VisualStyleElement.ToolBar.DropDownButton.Pressed; + else if (IsChecked (e.Item)) + if (IsHot (e.Item)) + element = VisualStyleElement.ToolBar.DropDownButton.HotChecked; + else + element = VisualStyleElement.ToolBar.DropDownButton.Checked; + else if (IsHot (e.Item)) + element = VisualStyleElement.ToolBar.DropDownButton.Hot; + else + element = VisualStyleElement.ToolBar.DropDownButton.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.OnRenderDropDownButtonBackground (e); + return; + } + new VisualStyleRenderer (element).DrawBackground (e.Graphics, e.Item.Bounds); + } + public override void OnRenderGrip (ToolStripGripRenderEventArgs e) + { + if (!ThemeVisualStyles.RenderClientAreas) { + base.OnRenderGrip (e); + return; + } + if (e.GripStyle == ToolStripGripStyle.Hidden) + return; + VisualStyleElement element = e.GripDisplayStyle == ToolStripGripDisplayStyle.Vertical ? + VisualStyleElement.Rebar.Gripper.Normal : + VisualStyleElement.Rebar.GripperVertical.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.OnRenderGrip (e); + return; + } + new VisualStyleRenderer (element).DrawBackground (e.Graphics, e.GripDisplayStyle == ToolStripGripDisplayStyle.Vertical ? + // GetPartSize seems to return useless values. + new Rectangle (2, 0, 5, 20) : + new Rectangle (0, 2, 20, 5)); + } + public override void OnRenderOverflowButtonBackground (ToolStripItemRenderEventArgs e) + { + if (!ThemeVisualStyles.RenderClientAreas) { + base.OnRenderOverflowButtonBackground (e); + return; + } + VisualStyleElement element = e.ToolStrip.Orientation == Orientation.Horizontal ? + VisualStyleElement.Rebar.Chevron.Normal : + VisualStyleElement.Rebar.ChevronVertical.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.OnRenderOverflowButtonBackground (e); + return; + } + OnRenderButtonBackground (e); + new VisualStyleRenderer (element).DrawBackground (e.Graphics, e.Item.Bounds); + } + public override void OnRenderSeparator (ToolStripSeparatorRenderEventArgs e) + { + if (!ThemeVisualStyles.RenderClientAreas) { + base.OnRenderSeparator (e); + return; + } + VisualStyleElement element = e.ToolStrip.Orientation == Orientation.Horizontal ? + VisualStyleElement.ToolBar.SeparatorHorizontal.Normal : + VisualStyleElement.ToolBar.SeparatorVertical.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.OnRenderSeparator (e); + return; + } + new VisualStyleRenderer (element).DrawBackground (e.Graphics, e.Item.Bounds); + } + public override void OnRenderSplitButtonBackground (ToolStripItemRenderEventArgs e) + { + if (!ThemeVisualStyles.RenderClientAreas) { + base.OnRenderSplitButtonBackground (e); + return; + } + VisualStyleElement element, drop_down_element; + if (IsDisabled (e.Item)) { + element = VisualStyleElement.ToolBar.SplitButton.Disabled; + drop_down_element = VisualStyleElement.ToolBar.SplitButtonDropDown.Disabled;; + } else if (IsPressed (e.Item)) { + element = VisualStyleElement.ToolBar.SplitButton.Pressed; + drop_down_element = VisualStyleElement.ToolBar.SplitButtonDropDown.Pressed; + } else if (IsChecked (e.Item)) + if (IsHot (e.Item)) { + element = VisualStyleElement.ToolBar.SplitButton.HotChecked; + drop_down_element = VisualStyleElement.ToolBar.SplitButtonDropDown.HotChecked; + } else { + element = VisualStyleElement.ToolBar.Button.Checked; + drop_down_element = VisualStyleElement.ToolBar.SplitButtonDropDown.Checked; + } + else if (IsHot (e.Item)) { + element = VisualStyleElement.ToolBar.SplitButton.Hot; + drop_down_element = VisualStyleElement.ToolBar.SplitButtonDropDown.Hot; + } else { + element = VisualStyleElement.ToolBar.SplitButton.Normal; + drop_down_element = VisualStyleElement.ToolBar.SplitButtonDropDown.Normal; + } + if (!VisualStyleRenderer.IsElementDefined (element) || + !VisualStyleRenderer.IsElementDefined (drop_down_element)) { + base.OnRenderSplitButtonBackground (e); + return; + } + ToolStripSplitButton tool_strip_split_button = (ToolStripSplitButton)e.Item; + VisualStyleRenderer renderer = new VisualStyleRenderer (element); + renderer.DrawBackground (e.Graphics, tool_strip_split_button.ButtonBounds); + renderer.SetParameters (drop_down_element); + renderer.DrawBackground (e.Graphics, tool_strip_split_button.DropDownButtonBounds); + } + public override void OnRenderToolStripBackground (ToolStripRenderEventArgs e) + { + if (e.ToolStrip.BackgroundImage != null) + return; + + if (!ThemeVisualStyles.RenderClientAreas) { + base.OnRenderToolStripBackground (e); + return; + } + VisualStyleElement element; + if (e.ToolStrip is StatusStrip) + element = VisualStyleElement.Status.Bar.Normal; + else + element = VisualStyleElement.Rebar.Band.Normal; + if (!VisualStyleRenderer.IsElementDefined (element)) { + base.OnRenderToolStripBackground (e); + return; + } + new VisualStyleRenderer (element).DrawBackground (e.Graphics, e.ToolStrip.Bounds, e.AffectedBounds); + } + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStrip.cs b/source/ShiftUI/ToolStrip/ToolStrip.cs new file mode 100644 index 0000000..b784458 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStrip.cs @@ -0,0 +1,1778 @@ +// +// ToolStrip.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Runtime.InteropServices; +using System.ComponentModel; +using System.Drawing; +using ShiftUI.Layout; +using System.Collections.Generic; +using System.ComponentModel.Design.Serialization; + +namespace ShiftUI +{ + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [DefaultEvent ("ItemClicked")] + [DefaultProperty ("Items")] + public class ToolStrip : ScrollableWidget, IComponent, IDisposable, IToolStripData + { + #region Private Variables + private bool allow_item_reorder; + private bool allow_merge; + private Color back_color; + private bool can_overflow; + private ToolStrip currently_merged_with; + private ToolStripDropDownDirection default_drop_down_direction; + internal ToolStripItemCollection displayed_items; + private Color fore_color; + private Padding grip_margin; + private ToolStripGripStyle grip_style; + private List hidden_merged_items; + private ImageList image_list; + private Size image_scaling_size; + private bool is_currently_merged; + private ToolStripItemCollection items; + private bool keyboard_active; + private LayoutEngine layout_engine; + private LayoutSettings layout_settings; + private ToolStripLayoutStyle layout_style; + private Orientation orientation; + private ToolStripOverflowButton overflow_button; + private List pre_merge_items; + private ToolStripRenderer renderer; + private ToolStripRenderMode render_mode; + private ToolStripTextDirection text_direction; + private Timer tooltip_timer; + private ToolTip tooltip_window; + private bool show_item_tool_tips; + private bool stretch; + + private ToolStripItem mouse_currently_over; + internal bool menu_selected; + private ToolStripItem tooltip_currently_showing; + private ToolTip.TipState tooltip_state; + + const int InitialToolTipDelay = 500; + const int ToolTipDelay = 5000; + #endregion + + #region Public Constructors + public ToolStrip () : this (null) + { + } + + public ToolStrip (params ToolStripItem[] items) : base () + { + SetStyle (Widgetstyles.AllPaintingInWmPaint, true); + SetStyle (Widgetstyles.OptimizedDoubleBuffer, true); + SetStyle (Widgetstyles.Selectable, false); + SetStyle (Widgetstyles.SupportsTransparentBackColor, true); + + this.SuspendLayout (); + + this.items = new ToolStripItemCollection (this, items, true); + this.allow_merge = true; + base.AutoSize = true; + this.SetAutoSizeMode (AutoSizeMode.GrowAndShrink); + this.back_color = Widget.DefaultBackColor; + this.can_overflow = true; + base.CausesValidation = false; + this.default_drop_down_direction = ToolStripDropDownDirection.BelowRight; + this.displayed_items = new ToolStripItemCollection (this, null, true); + this.Dock = this.DefaultDock; + base.Font = new Font ("Tahoma", 8.25f); + this.fore_color = Widget.DefaultForeColor; + this.grip_margin = this.DefaultGripMargin; + this.grip_style = ToolStripGripStyle.Visible; + this.image_scaling_size = new Size (16, 16); + this.layout_style = ToolStripLayoutStyle.HorizontalStackWithOverflow; + this.orientation = Orientation.Horizontal; + if (!(this is ToolStripDropDown)) + this.overflow_button = new ToolStripOverflowButton (this); + this.renderer = null; + this.render_mode = ToolStripRenderMode.ManagerRenderMode; + this.show_item_tool_tips = this.DefaultShowItemToolTips; + base.TabStop = false; + this.text_direction = ToolStripTextDirection.Horizontal; + this.ResumeLayout (); + + // Register with the ToolStripManager + ToolStripManager.AddToolStrip (this); + } + #endregion + + #region Public Properties + [MonoTODO ("Stub, does nothing")] + public override bool AllowDrop { + get { return base.AllowDrop; } + set { base.AllowDrop = value; } + } + + [MonoTODO ("Stub, does nothing")] + [DefaultValue (false)] + public bool AllowItemReorder { + get { return this.allow_item_reorder; } + set { this.allow_item_reorder = value; } + } + + [DefaultValue (true)] + public bool AllowMerge { + get { return this.allow_merge; } + set { this.allow_merge = value; } + } + + public override AnchorStyles Anchor { + get { return base.Anchor; } + set { base.Anchor = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override bool AutoScroll { + get { return base.AutoScroll; } + set { base.AutoScroll = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Size AutoScrollMargin { + get { return base.AutoScrollMargin; } + set { base.AutoScrollMargin = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Size AutoScrollMinSize { + get { return base.AutoScrollMinSize; } + set { base.AutoScrollMinSize = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Point AutoScrollPosition { + get { return base.AutoScrollPosition; } + set { base.AutoScrollPosition = value; } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)] + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + [DefaultValue (true)] + public override bool AutoSize { + get { return base.AutoSize; } + set { base.AutoSize = value; } + } + + new public Color BackColor { + get { return this.back_color; } + set { this.back_color = value; } + } + + public override BindingContext BindingContext { + get { return base.BindingContext; } + set { base.BindingContext = value; } + } + + [DefaultValue (true)] + public bool CanOverflow { + get { return this.can_overflow; } + set { this.can_overflow = value; } + } + + [Browsable (false)] + [DefaultValue (false)] + public new bool CausesValidation { + get { return base.CausesValidation; } + set { base.CausesValidation = value; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new WidgetCollection Widgets { + get { return base.Widgets; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override Cursor Cursor { + get { return base.Cursor; } + set { base.Cursor = value; } + } + + [Browsable (false)] + public virtual ToolStripDropDownDirection DefaultDropDownDirection { + get { return this.default_drop_down_direction; } + set { + if (!Enum.IsDefined (typeof (ToolStripDropDownDirection), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripDropDownDirection", value)); + + this.default_drop_down_direction = value; + } + } + + public override Rectangle DisplayRectangle { + get { + if (this.orientation == Orientation.Horizontal) + if (this.grip_style == ToolStripGripStyle.Hidden || this.layout_style == ToolStripLayoutStyle.Flow || this.layout_style == ToolStripLayoutStyle.Table) + return new Rectangle (this.Padding.Left, this.Padding.Top, this.Width - this.Padding.Horizontal, this.Height - this.Padding.Vertical); + else + return new Rectangle (this.GripRectangle.Right + this.GripMargin.Right, this.Padding.Top, this.Width - this.Padding.Horizontal - this.GripRectangle.Right - this.GripMargin.Right, this.Height - this.Padding.Vertical); + else + if (this.grip_style == ToolStripGripStyle.Hidden || this.layout_style == ToolStripLayoutStyle.Flow || this.layout_style == ToolStripLayoutStyle.Table) + return new Rectangle (this.Padding.Left, this.Padding.Top, this.Width - this.Padding.Horizontal, this.Height - this.Padding.Vertical); + else + return new Rectangle (this.Padding.Left, this.GripRectangle.Bottom + this.GripMargin.Bottom + this.Padding.Top, this.Width - this.Padding.Horizontal, this.Height - this.Padding.Vertical - this.GripRectangle.Bottom - this.GripMargin.Bottom); + } + } + + [DefaultValue (DockStyle.Top)] + public override DockStyle Dock { + get { return base.Dock; } + set { + if (base.Dock != value) { + base.Dock = value; + + switch (value) { + case DockStyle.Top: + case DockStyle.Bottom: + case DockStyle.None: + this.LayoutStyle = ToolStripLayoutStyle.HorizontalStackWithOverflow; + break; + case DockStyle.Left: + case DockStyle.Right: + this.LayoutStyle = ToolStripLayoutStyle.VerticalStackWithOverflow; + break; + } + } + } + } + + public override Font Font { + get { return base.Font; } + set { + if (base.Font != value) { + base.Font = value; + + foreach (ToolStripItem tsi in this.Items) + tsi.OnOwnerFontChanged (EventArgs.Empty); + } + } + } + + [Browsable (false)] + public new Color ForeColor { + get { return this.fore_color; } + set { + if (this.fore_color != value) { + this.fore_color = value; + this.OnForeColorChanged (EventArgs.Empty); + } + } + } + + [Browsable (false)] + public ToolStripGripDisplayStyle GripDisplayStyle { + get { return this.orientation == Orientation.Vertical ? ToolStripGripDisplayStyle.Horizontal : ToolStripGripDisplayStyle.Vertical; } + } + + public Padding GripMargin { + get { return this.grip_margin; } + set { + if (this.grip_margin != value) { + this.grip_margin = value; + this.PerformLayout (); + } + } + } + + [Browsable (false)] + public Rectangle GripRectangle { + get { + if (this.grip_style == ToolStripGripStyle.Hidden) + return Rectangle.Empty; + + if (this.orientation == Orientation.Horizontal) + return new Rectangle (this.grip_margin.Left + this.Padding.Left, this.Padding.Top, 3, this.Height); + else + return new Rectangle (this.Padding.Left, this.grip_margin.Top + this.Padding.Top, this.Width, 3); + } + } + + [DefaultValue (ToolStripGripStyle.Visible)] + public ToolStripGripStyle GripStyle { + get { return this.grip_style; } + set { + if (this.grip_style != value) { + if (!Enum.IsDefined (typeof (ToolStripGripStyle), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripGripStyle", value)); + this.grip_style = value; + this.PerformLayout (this, "GripStyle"); + } + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new bool HasChildren { + get { return base.HasChildren; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new HScrollProperties HorizontalScroll { + get { return base.HorizontalScroll; } + } + + [Browsable (false)] + [DefaultValue (null)] + public ImageList ImageList { + get { return this.image_list; } + set { this.image_list = value; } + } + + [DefaultValue ("{Width=16, Height=16}")] + public Size ImageScalingSize { + get { return this.image_scaling_size; } + set { this.image_scaling_size = value; } + } + + [MonoTODO ("Always returns false, dragging not implemented yet.")] + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public bool IsCurrentlyDragging { + get { return false; } + } + + [Browsable (false)] + public bool IsDropDown { + get { + if (this is ToolStripDropDown) + return true; + + return false; + } + } + + [MergableProperty (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + public virtual ToolStripItemCollection Items { + get { return this.items; } + } + + public override LayoutEngine LayoutEngine { + get { + if (layout_engine == null) + this.layout_engine = new ToolStripSplitStackLayout (); + + return this.layout_engine; + } + } + + [Browsable (false)] + [DefaultValue (null)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public LayoutSettings LayoutSettings { + get { return this.layout_settings; } + set { + if (this.layout_settings != value) { + this.layout_settings = value; + PerformLayout (this, "LayoutSettings"); + } + } + } + + [AmbientValue (ToolStripLayoutStyle.StackWithOverflow)] + public ToolStripLayoutStyle LayoutStyle { + get { return layout_style; } + set { + if (this.layout_style != value) { + if (!Enum.IsDefined (typeof (ToolStripLayoutStyle), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripLayoutStyle", value)); + + this.layout_style = value; + + if (this.layout_style == ToolStripLayoutStyle.Flow) + this.layout_engine = new FlowLayout (); + else + this.layout_engine = new ToolStripSplitStackLayout (); + + if (this.layout_style == ToolStripLayoutStyle.StackWithOverflow) { + if (this.Dock == DockStyle.Left || this.Dock == DockStyle.Right) + this.layout_style = ToolStripLayoutStyle.VerticalStackWithOverflow; + else + this.layout_style = ToolStripLayoutStyle.HorizontalStackWithOverflow; + } + + if (this.layout_style == ToolStripLayoutStyle.HorizontalStackWithOverflow) + this.orientation = Orientation.Horizontal; + else if (this.layout_style == ToolStripLayoutStyle.VerticalStackWithOverflow) + this.orientation = Orientation.Vertical; + + this.layout_settings = this.CreateLayoutSettings (value); + + this.PerformLayout (this, "LayoutStyle"); + this.OnLayoutStyleChanged (EventArgs.Empty); + } + } + } + + [Browsable (false)] + public Orientation Orientation { + get { return this.orientation; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public ToolStripOverflowButton OverflowButton { + get { return this.overflow_button; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public ToolStripRenderer Renderer { + get { + if (this.render_mode == ToolStripRenderMode.ManagerRenderMode) + return ToolStripManager.Renderer; + + return this.renderer; + } + set { + if (this.renderer != value) { + this.renderer = value; + this.render_mode = ToolStripRenderMode.Custom; + this.PerformLayout (this, "Renderer"); + this.OnRendererChanged (EventArgs.Empty); + } + } + } + + public ToolStripRenderMode RenderMode { + get { return this.render_mode; } + set { + if (!Enum.IsDefined (typeof (ToolStripRenderMode), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripRenderMode", value)); + + if (value == ToolStripRenderMode.Custom && this.renderer == null) + throw new NotSupportedException ("Must set Renderer property before setting RenderMode to Custom"); + else if (value == ToolStripRenderMode.Professional) + this.Renderer = new ToolStripProfessionalRenderer (); + else if (value == ToolStripRenderMode.System) + this.Renderer = new ToolStripSystemRenderer (); + + this.render_mode = value; + } + } + + [DefaultValue (true)] + public bool ShowItemToolTips { + get { return this.show_item_tool_tips; } + set { this.show_item_tool_tips = value; } + } + + [DefaultValue (false)] + public bool Stretch { + get { return this.stretch; } + set { this.stretch = value; } + } + + [DefaultValue (false)] + [DispId(-516)] + public new bool TabStop { + get { return base.TabStop; } + set { + base.TabStop = value; + SetStyle (Widgetstyles.Selectable, value); + } + } + + [DefaultValue (ToolStripTextDirection.Horizontal)] + public virtual ToolStripTextDirection TextDirection { + get { return this.text_direction; } + set { + if (!Enum.IsDefined (typeof (ToolStripTextDirection), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripTextDirection", value)); + + if (this.text_direction != value) { + this.text_direction = value; + + this.PerformLayout (this, "TextDirection"); + + this.Invalidate (); + } + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new VScrollProperties VerticalScroll { + get { return base.VerticalScroll; } + } + #endregion + + #region Protected Properties + protected virtual DockStyle DefaultDock { get { return DockStyle.Top; } } + protected virtual Padding DefaultGripMargin { get { return new Padding (2); } } + protected override Padding DefaultMargin { get { return Padding.Empty; } } + protected override Padding DefaultPadding { get { return new Padding (0, 0, 1, 0); } } + protected virtual bool DefaultShowItemToolTips { get { return true; } } + protected override Size DefaultSize { get { return new Size (100, 25); } } + protected internal virtual ToolStripItemCollection DisplayedItems { get { return this.displayed_items; } } + protected internal virtual Size MaxItemSize { + get { return new Size (Width - (GripStyle == ToolStripGripStyle.Hidden ? 1 : 8), Height); } + } + #endregion + + #region Public Methods + //[EditorBrowsable (EditorBrowsableState.Never)] + public new Widget GetChildAtPoint (Point point) + { + return base.GetChildAtPoint (point); + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public new Widget GetChildAtPoint (Point pt, GetChildAtPointSkip skipValue) + { + return base.GetChildAtPoint (pt, skipValue); + } + + public ToolStripItem GetItemAt (Point point) + { + foreach (ToolStripItem tsi in this.displayed_items) + if (tsi.Visible && tsi.Bounds.Contains (point)) + return tsi; + + return null; + } + + public ToolStripItem GetItemAt (int x, int y) + { + return GetItemAt (new Point (x, y)); + } + + public virtual ToolStripItem GetNextItem (ToolStripItem start, ArrowDirection direction) + { + if (!Enum.IsDefined (typeof (ArrowDirection), direction)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ArrowDirection", direction)); + + ToolStripItem current_best = null; + int current_best_point; + + switch (direction) { + case ArrowDirection.Right: + current_best_point = int.MaxValue; + + if (start != null) + foreach (ToolStripItem loop_tsi in this.DisplayedItems) + if (loop_tsi.Left >= start.Right && loop_tsi.Left < current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) { + current_best = loop_tsi; + current_best_point = loop_tsi.Left; + } + + if (current_best == null) + foreach (ToolStripItem loop_tsi in this.DisplayedItems) + if (loop_tsi.Left < current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) { + current_best = loop_tsi; + current_best_point = loop_tsi.Left; + } + + break; + case ArrowDirection.Up: + current_best_point = int.MinValue; + + if (start != null) + foreach (ToolStripItem loop_tsi in this.DisplayedItems) + if (loop_tsi.Bottom <= start.Top && loop_tsi.Top > current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) { + current_best = loop_tsi; + current_best_point = loop_tsi.Top; + } + + if (current_best == null) + foreach (ToolStripItem loop_tsi in this.DisplayedItems) + if (loop_tsi.Top > current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) { + current_best = loop_tsi; + current_best_point = loop_tsi.Top; + } + + break; + case ArrowDirection.Left: + current_best_point = int.MinValue; + + if (start != null) + foreach (ToolStripItem loop_tsi in this.DisplayedItems) + if (loop_tsi.Right <= start.Left && loop_tsi.Left > current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) { + current_best = loop_tsi; + current_best_point = loop_tsi.Left; + } + + if (current_best == null) + foreach (ToolStripItem loop_tsi in this.DisplayedItems) + if (loop_tsi.Left > current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) { + current_best = loop_tsi; + current_best_point = loop_tsi.Left; + } + + break; + case ArrowDirection.Down: + current_best_point = int.MaxValue; + + if (start != null) + foreach (ToolStripItem loop_tsi in this.DisplayedItems) + if (loop_tsi.Top >= start.Bottom && loop_tsi.Bottom < current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) { + current_best = loop_tsi; + current_best_point = loop_tsi.Top; + } + + if (current_best == null) + foreach (ToolStripItem loop_tsi in this.DisplayedItems) + if (loop_tsi.Top < current_best_point && loop_tsi.Visible && loop_tsi.CanSelect) { + current_best = loop_tsi; + current_best_point = loop_tsi.Top; + } + + break; + } + + return current_best; + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public void ResetMinimumSize () + { + this.MinimumSize = new Size (-1, -1); + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public new void SetAutoScrollMargin (int x, int y) + { + base.SetAutoScrollMargin (x, y); + } + + public override string ToString () + { + return String.Format ("{0}, Name: {1}, Items: {2}", base.ToString(), this.Name, this.items.Count.ToString ()); + } + #endregion + + #region Protected Methods + protected override AccessibleObject CreateAccessibilityInstance () + { + return new ToolStripAccessibleObject (this); + } + + protected override WidgetCollection CreateWidgetsInstance () + { + return base.CreateWidgetsInstance (); + } + + protected internal virtual ToolStripItem CreateDefaultItem (string text, Image image, EventHandler onClick) + { + if (text == "-") + return new ToolStripSeparator (); + + if (this is ToolStripDropDown) + return new ToolStripMenuItem (text, image, onClick); + + return new ToolStripButton (text, image, onClick); + } + + protected virtual LayoutSettings CreateLayoutSettings (ToolStripLayoutStyle layoutStyle) + { + switch (layoutStyle) { + case ToolStripLayoutStyle.Flow: + return new FlowLayoutSettings (this); + case ToolStripLayoutStyle.Table: + //return new TableLayoutSettings (); + case ToolStripLayoutStyle.StackWithOverflow: + case ToolStripLayoutStyle.HorizontalStackWithOverflow: + case ToolStripLayoutStyle.VerticalStackWithOverflow: + default: + return null; + } + } + + protected override void Dispose (bool disposing) + { + if (!IsDisposed) { + + if(disposing) { + // Event Handler must be stopped before disposing Items. + Events.Dispose(); + + CloseToolTip (null); + // ToolStripItem.Dispose modifes the collection, + // so we iterate it in reverse order + for (int i = Items.Count - 1; i >= 0; i--) + Items [i].Dispose (); + + if (this.overflow_button != null && this.overflow_button.drop_down != null) + this.overflow_button.drop_down.Dispose (); + + ToolStripManager.RemoveToolStrip (this); + } + base.Dispose (disposing); + } + } + + [MonoTODO ("Stub, never called")] + protected virtual void OnBeginDrag (EventArgs e) + { + EventHandler eh = (EventHandler)(Events[BeginDragEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnDockChanged (EventArgs e) + { + base.OnDockChanged (e); + } + + [MonoTODO ("Stub, never called")] + protected virtual void OnEndDrag (EventArgs e) + { + EventHandler eh = (EventHandler)(Events[EndDragEvent]); + if (eh != null) + eh (this, e); + } + + protected override bool IsInputChar (char charCode) + { + return base.IsInputChar (charCode); + } + + protected override bool IsInputKey (Keys keyData) + { + return base.IsInputKey (keyData); + } + + protected override void OnEnabledChanged (EventArgs e) + { + base.OnEnabledChanged (e); + + foreach (ToolStripItem tsi in this.Items) + tsi.OnParentEnabledChanged (EventArgs.Empty); + } + + protected override void OnFontChanged (EventArgs e) + { + base.OnFontChanged (e); + } + + protected override void OnHandleCreated (EventArgs e) + { + base.OnHandleCreated (e); + } + + protected override void OnHandleDestroyed (EventArgs e) + { + base.OnHandleDestroyed (e); + } + + protected override void OnInvalidated (InvalidateEventArgs e) + { + base.OnInvalidated (e); + } + + protected internal virtual void OnItemAdded (ToolStripItemEventArgs e) + { + if (e.Item.InternalVisible) + e.Item.Available = true; + + e.Item.SetPlacement (ToolStripItemPlacement.Main); + + if (this.Created) + this.PerformLayout (); + + ToolStripItemEventHandler eh = (ToolStripItemEventHandler)(Events [ItemAddedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnItemClicked (ToolStripItemClickedEventArgs e) + { + if (this.KeyboardActive) + ToolStripManager.SetActiveToolStrip (null, false); + + ToolStripItemClickedEventHandler eh = (ToolStripItemClickedEventHandler)(Events [ItemClickedEvent]); + if (eh != null) + eh (this, e); + } + + protected internal virtual void OnItemRemoved (ToolStripItemEventArgs e) + { + ToolStripItemEventHandler eh = (ToolStripItemEventHandler)(Events [ItemRemovedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnLayout (LayoutEventArgs e) + { + base.OnLayout (e); + + this.SetDisplayedItems (); + this.OnLayoutCompleted (EventArgs.Empty); + this.Invalidate (); + } + + protected virtual void OnLayoutCompleted (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [LayoutCompletedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnLayoutStyleChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events[LayoutStyleChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnLeave (EventArgs e) + { + base.OnLeave (e); + } + + protected override void OnLostFocus (EventArgs e) + { + base.OnLostFocus (e); + } + + protected override void OnMouseCaptureChanged (EventArgs e) + { + base.OnMouseCaptureChanged (e); + } + + protected override void OnMouseDown (MouseEventArgs mea) + { + if (mouse_currently_over != null) + { + ToolStripItem focused = GetCurrentlyFocusedItem (); + + if (focused != null && focused != mouse_currently_over) + this.FocusInternal (true); + + if (this is MenuStrip && !menu_selected) { + (this as MenuStrip).FireMenuActivate (); + menu_selected = true; + } + + mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseDown); + + if (this is MenuStrip && mouse_currently_over is ToolStripMenuItem && !(mouse_currently_over as ToolStripMenuItem).HasDropDownItems) + return; + } else { + this.Dismiss (ToolStripDropDownCloseReason.AppClicked); + } + + if (this is MenuStrip) + this.Capture = false; + + base.OnMouseDown (mea); + } + + protected override void OnMouseLeave (EventArgs e) + { + if (mouse_currently_over != null) { + MouseLeftItem (mouse_currently_over); + mouse_currently_over.FireEvent (e, ToolStripItemEventType.MouseLeave); + mouse_currently_over = null; + } + + base.OnMouseLeave (e); + } + + protected override void OnMouseMove (MouseEventArgs mea) + { + ToolStripItem tsi; + // Find the item we are now + if (this.overflow_button != null && this.overflow_button.Visible && this.overflow_button.Bounds.Contains (mea.Location)) + tsi = this.overflow_button; + else + tsi = this.GetItemAt (mea.X, mea.Y); + + if (tsi != null) { + // If we were already hovering on this item, just send a mouse move + if (tsi == mouse_currently_over) + tsi.FireEvent (mea, ToolStripItemEventType.MouseMove); + else { + // If we were over a different item, fire a mouse leave on it + if (mouse_currently_over != null) { + MouseLeftItem (tsi); + mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseLeave); + } + + // Set the new item we are currently over + mouse_currently_over = tsi; + + // Fire mouse enter and mouse move + tsi.FireEvent (mea, ToolStripItemEventType.MouseEnter); + MouseEnteredItem (tsi); + tsi.FireEvent (mea, ToolStripItemEventType.MouseMove); + + // If we're over something with a drop down, show it + if (menu_selected && mouse_currently_over.Enabled && mouse_currently_over is ToolStripDropDownItem && (mouse_currently_over as ToolStripDropDownItem).HasDropDownItems) + (mouse_currently_over as ToolStripDropDownItem).ShowDropDown (); + } + } else { + // We're not over anything now, just fire the mouse leave on what we used to be over + if (mouse_currently_over != null) { + MouseLeftItem (tsi); + mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseLeave); + mouse_currently_over = null; + } + } + + base.OnMouseMove (mea); + } + + protected override void OnMouseUp (MouseEventArgs mea) + { + // If we're currently over an item (set in MouseMove) + if (mouse_currently_over != null && !(mouse_currently_over is ToolStripWidgetHost) && mouse_currently_over.Enabled) { + // Fire our ItemClicked event, but only for a left mouse click. + if (mea.Button == MouseButtons.Left) + OnItemClicked (new ToolStripItemClickedEventArgs (mouse_currently_over)); + + // Fire the item's MouseUp event + if (mouse_currently_over != null) + mouse_currently_over.FireEvent (mea, ToolStripItemEventType.MouseUp); + + // The event handler may have blocked until the mouse moved off of the ToolStripItem + if (mouse_currently_over == null) + return; + } + + base.OnMouseUp (mea); + } + + protected override void OnPaint (PaintEventArgs e) + { + base.OnPaint (e); + + // Draw the grip + this.OnPaintGrip (e); + + // Make each item draw itself + for (int i = 0; i < displayed_items.Count; i++) { + ToolStripItem tsi = displayed_items[i]; + + if (tsi.Visible) { + e.Graphics.TranslateTransform (tsi.Bounds.Left, tsi.Bounds.Top); + tsi.FireEvent (e, ToolStripItemEventType.Paint); + e.Graphics.ResetTransform (); + } + } + + // Paint the Overflow button if it's visible + if (this.overflow_button != null && this.overflow_button.Visible) { + e.Graphics.TranslateTransform (this.overflow_button.Bounds.Left, this.overflow_button.Bounds.Top); + this.overflow_button.FireEvent (e, ToolStripItemEventType.Paint); + e.Graphics.ResetTransform (); + } + + Rectangle affected_bounds = new Rectangle (Point.Empty, this.Size); + + ToolStripRenderEventArgs pevent = new ToolStripRenderEventArgs (e.Graphics, this, affected_bounds, Color.Empty); + pevent.InternalConnectedArea = CalculateConnectedArea (); + + this.Renderer.DrawToolStripBorder (pevent); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void OnPaintBackground (PaintEventArgs e) + { + base.OnPaintBackground (e); + + Rectangle affected_bounds = new Rectangle (Point.Empty, this.Size); + ToolStripRenderEventArgs tsrea = new ToolStripRenderEventArgs (e.Graphics, this, affected_bounds, SystemColors.Control); + + this.Renderer.DrawToolStripBackground (tsrea); + } + + protected internal virtual void OnPaintGrip (PaintEventArgs e) + { + // Never draw a grip with these two layouts + if (this.layout_style == ToolStripLayoutStyle.Flow || this.layout_style == ToolStripLayoutStyle.Table) + return; + + PaintEventHandler eh = (PaintEventHandler)(Events [PaintGripEvent]); + if (eh != null) + eh (this, e); + + if (!(this is MenuStrip)) { + if (this.orientation == Orientation.Horizontal) + e.Graphics.TranslateTransform (2, 0); + else + e.Graphics.TranslateTransform (0, 2); + } + + this.Renderer.DrawGrip (new ToolStripGripRenderEventArgs (e.Graphics, this, this.GripRectangle, this.GripDisplayStyle, this.grip_style)); + e.Graphics.ResetTransform (); + } + + protected virtual void OnRendererChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [RendererChangedEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void OnRightToLeftChanged (EventArgs e) + { + base.OnRightToLeftChanged (e); + + foreach (ToolStripItem tsi in this.Items) + tsi.OnParentRightToLeftChanged (e); + } + + protected override void OnScroll (ScrollEventArgs se) + { + base.OnScroll (se); + } + + protected override void OnTabStopChanged (EventArgs e) + { + base.OnTabStopChanged (e); + } + + protected override void OnVisibleChanged (EventArgs e) + { + if (!Visible) + CloseToolTip (null); + + base.OnVisibleChanged (e); + } + + protected override bool ProcessCmdKey (ref Message m, Keys keyData) + { + return base.ProcessCmdKey (ref m, keyData); + } + + protected override bool ProcessDialogKey (Keys keyData) + { + if (!this.KeyboardActive) + return false; + + // Give each item a chance to handle the key + foreach (ToolStripItem tsi in this.Items) + if (tsi.ProcessDialogKey (keyData)) + return true; + + // See if I want to handle it + if (this.ProcessArrowKey (keyData)) + return true; + + ToolStrip ts = null; + + switch (keyData) { + case Keys.Escape: + this.Dismiss (ToolStripDropDownCloseReason.Keyboard); + return true; + + case Keys.Widget | Keys.Tab: + ts = ToolStripManager.GetNextToolStrip (this, true); + + if (ts != null) { + foreach (ToolStripItem tsi in this.Items) + tsi.Dismiss (ToolStripDropDownCloseReason.Keyboard); + + ToolStripManager.SetActiveToolStrip (ts, true); + ts.SelectNextToolStripItem (null, true); + } + + return true; + case Keys.Widget | Keys.Shift | Keys.Tab: + ts = ToolStripManager.GetNextToolStrip (this, false); + + if (ts != null) { + foreach (ToolStripItem tsi in this.Items) + tsi.Dismiss (ToolStripDropDownCloseReason.Keyboard); + + ToolStripManager.SetActiveToolStrip (ts, true); + ts.SelectNextToolStripItem (null, true); + } + + return true; + case Keys.Down: + case Keys.Up: + case Keys.Left: + case Keys.Right: + if (GetCurrentlySelectedItem () is ToolStripWidgetHost) + return false; + break; + } + + return base.ProcessDialogKey (keyData); + } + + protected override bool ProcessMnemonic (char charCode) + { + // If any item has an explicit mnemonic, it gets the message + foreach (ToolStripItem tsi in this.Items) + if (tsi.Enabled && tsi.Visible && !string.IsNullOrEmpty (tsi.Text) && Widget.IsMnemonic (charCode, tsi.Text)) + return tsi.ProcessMnemonic (charCode); + + // Do not try to match any further here. See Xamarin bug 23532. + + return base.ProcessMnemonic (charCode); + } + + [MonoTODO ("Stub, does nothing")] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void RestoreFocus () + { + } + + protected override void Select (bool directed, bool forward) + { + foreach (ToolStripItem tsi in this.DisplayedItems) + if (tsi.CanSelect) { + tsi.Select (); + break; + } + } + + protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified) + { + base.SetBoundsCore (x, y, width, height, specified); + } + + protected virtual void SetDisplayedItems () + { + this.displayed_items.ClearInternal (); + + foreach (ToolStripItem tsi in this.items) + if (tsi.Placement == ToolStripItemPlacement.Main && tsi.Available) { + this.displayed_items.AddNoOwnerOrLayout (tsi); + tsi.Parent = this; + } + else if (tsi.Placement == ToolStripItemPlacement.Overflow) + tsi.Parent = this.OverflowButton.DropDown; + + if (this.OverflowButton != null) + this.OverflowButton.DropDown.SetDisplayedItems (); + } + + protected internal void SetItemLocation (ToolStripItem item, Point location) + { + if (item == null) + throw new ArgumentNullException ("item"); + + if (item.Owner != this) + throw new NotSupportedException ("The item is not owned by this ToolStrip"); + + item.SetBounds (new Rectangle (location, item.Size)); + } + + protected internal static void SetItemParent (ToolStripItem item, ToolStrip parent) + { + if (item.Owner != null) { + item.Owner.Items.RemoveNoOwnerOrLayout (item); + + if (item.Owner is ToolStripOverflow) + (item.Owner as ToolStripOverflow).ParentToolStrip.Items.RemoveNoOwnerOrLayout (item); + } + + parent.Items.AddNoOwnerOrLayout (item); + item.Parent = parent; + } + + protected override void SetVisibleCore (bool visible) + { + base.SetVisibleCore (visible); + } + + protected override void WndProc (ref Message m) + { + base.WndProc (ref m); + } + #endregion + + #region Public Events + static object BeginDragEvent = new object (); + static object EndDragEvent = new object (); + static object ItemAddedEvent = new object (); + static object ItemClickedEvent = new object (); + static object ItemRemovedEvent = new object (); + static object LayoutCompletedEvent = new object (); + static object LayoutStyleChangedEvent = new object (); + static object PaintGripEvent = new object (); + static object RendererChangedEvent = new object (); + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler AutoSizeChanged { + add { base.AutoSizeChanged += value; } + remove { base.AutoSizeChanged -= value; } + } + + [MonoTODO ("Event never raised")] + public event EventHandler BeginDrag { + add { Events.AddHandler (BeginDragEvent, value); } + remove { Events.RemoveHandler (BeginDragEvent, value); } + } + + [Browsable (false)] + public new event EventHandler CausesValidationChanged { + add { base.CausesValidationChanged += value; } + remove { base.CausesValidationChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event WidgetEventHandler WidgetAdded { + add { base.WidgetAdded += value; } + remove { base.WidgetAdded -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event WidgetEventHandler WidgetRemoved { + add { base.WidgetRemoved += value; } + remove { base.WidgetRemoved -= value; } + } + + [Browsable (false)] + public new event EventHandler CursorChanged { + add { base.CursorChanged += value; } + remove { base.CursorChanged -= value; } + } + + [MonoTODO ("Event never raised")] + public event EventHandler EndDrag { + add { Events.AddHandler (EndDragEvent, value); } + remove { Events.RemoveHandler (EndDragEvent, value); } + } + + [Browsable (false)] + public new event EventHandler ForeColorChanged { + add { base.ForeColorChanged += value; } + remove { base.ForeColorChanged -= value; } + } + + public event ToolStripItemEventHandler ItemAdded { + add { Events.AddHandler (ItemAddedEvent, value); } + remove { Events.RemoveHandler (ItemAddedEvent, value); } + } + + public event ToolStripItemClickedEventHandler ItemClicked { + add { Events.AddHandler (ItemClickedEvent, value); } + remove { Events.RemoveHandler (ItemClickedEvent, value); } + } + + public event ToolStripItemEventHandler ItemRemoved { + add { Events.AddHandler (ItemRemovedEvent, value); } + remove { Events.RemoveHandler (ItemRemovedEvent, value); } + } + + public event EventHandler LayoutCompleted { + add { Events.AddHandler (LayoutCompletedEvent, value); } + remove { Events.RemoveHandler (LayoutCompletedEvent, value); } + } + + public event EventHandler LayoutStyleChanged { + add { Events.AddHandler (LayoutStyleChangedEvent, value); } + remove { Events.RemoveHandler (LayoutStyleChangedEvent, value); } + } + + public event PaintEventHandler PaintGrip { + add { Events.AddHandler (PaintGripEvent, value); } + remove { Events.RemoveHandler (PaintGripEvent, value); } + } + + public event EventHandler RendererChanged { + add { Events.AddHandler (RendererChangedEvent, value); } + remove { Events.RemoveHandler (RendererChangedEvent, value); } + } + #endregion + + #region Internal Properties + internal virtual bool KeyboardActive + { + get { return this.keyboard_active; } + set { + if (this.keyboard_active != value) { + this.keyboard_active = value; + + if (value) + Application.KeyboardCapture = this; + else if (Application.KeyboardCapture == this) { + Application.KeyboardCapture = null; + ToolStripManager.ActivatedByKeyboard = false; + } + + // Redraw for mnemonic underlines + this.Invalidate (); + } + } + } + #endregion + + #region Private Methods + internal virtual Rectangle CalculateConnectedArea () + { + return Rectangle.Empty; + } + + internal void ChangeSelection (ToolStripItem nextItem) + { + if (Application.KeyboardCapture != this) + ToolStripManager.SetActiveToolStrip (this, ToolStripManager.ActivatedByKeyboard); + + foreach (ToolStripItem tsi in this.Items) + if (tsi != nextItem) + tsi.Dismiss (ToolStripDropDownCloseReason.Keyboard); + + ToolStripItem current = GetCurrentlySelectedItem (); + + if (current != null && !(current is ToolStripWidgetHost)) + this.FocusInternal (true); + + if (nextItem is ToolStripWidgetHost) + (nextItem as ToolStripWidgetHost).Focus (); + + nextItem.Select (); + + if (nextItem.Parent is MenuStrip && (nextItem.Parent as MenuStrip).MenuDroppedDown) + (nextItem as ToolStripMenuItem).HandleAutoExpansion (); + } + + internal virtual void Dismiss () + { + this.Dismiss (ToolStripDropDownCloseReason.AppClicked); + } + + internal virtual void Dismiss (ToolStripDropDownCloseReason reason) + { + // Release our stranglehold on the keyboard + this.KeyboardActive = false; + + // Set our drop down flag to false; + this.menu_selected = false; + + // Make sure all of our items are deselected and repainted + foreach (ToolStripItem tsi in this.Items) + tsi.Dismiss (reason); + + // We probably need to redraw for mnemonic underlines + this.Invalidate (); + } + + internal ToolStripItem GetCurrentlySelectedItem () + { + foreach (ToolStripItem tsi in this.DisplayedItems) + if (tsi.Selected) + return tsi; + + return null; + } + + internal ToolStripItem GetCurrentlyFocusedItem () + { + foreach (ToolStripItem tsi in this.DisplayedItems) + if ((tsi is ToolStripWidgetHost) && (tsi as ToolStripWidgetHost).Widget.Focused) + return tsi; + + return null; + } + + internal override Size GetPreferredSizeCore (Size proposedSize) + { + return GetToolStripPreferredSize (proposedSize); + } + + internal virtual Size GetToolStripPreferredSize (Size proposedSize) + { + Size new_size = Size.Empty; + + // TODO: This is total duct tape. We really have to call into the correct + // layout engine, do a dry run of the layout, and find out our true + // preferred dimensions. + if (this.LayoutStyle == ToolStripLayoutStyle.Flow) { + Point currentLocation = Point.Empty; + int tallest = 0; + + foreach (ToolStripItem tsi in items) + if (tsi.Available) { + Size tsi_preferred = tsi.GetPreferredSize (Size.Empty); + + if ((DisplayRectangle.Width - currentLocation.X) < (tsi_preferred.Width + tsi.Margin.Horizontal)) { + + currentLocation.Y += tallest; + tallest = 0; + + currentLocation.X = DisplayRectangle.Left; + } + + // Offset the left margin and set the Widget to our point + currentLocation.Offset (tsi.Margin.Left, 0); + tallest = Math.Max (tallest, tsi_preferred.Height + tsi.Margin.Vertical); + + // Update our location pointer + currentLocation.X += tsi_preferred.Width + tsi.Margin.Right; + } + + currentLocation.Y += tallest; + return new Size (currentLocation.X + this.Padding.Horizontal, currentLocation.Y + this.Padding.Vertical); + } + + if (this.orientation == Orientation.Vertical) { + foreach (ToolStripItem tsi in this.items) + if (tsi.Available) { + Size tsi_preferred = tsi.GetPreferredSize (Size.Empty); + new_size.Height += tsi_preferred.Height + tsi.Margin.Top + tsi.Margin.Bottom; + + if (new_size.Width < (this.Padding.Horizontal + tsi_preferred.Width + tsi.Margin.Horizontal)) + new_size.Width = (this.Padding.Horizontal + tsi_preferred.Width + tsi.Margin.Horizontal); + } + + new_size.Height += (this.GripRectangle.Height + this.GripMargin.Vertical + this.Padding.Vertical + 4); + + if (new_size.Width == 0) + new_size.Width = ExplicitBounds.Width; + + return new_size; + } else { + foreach (ToolStripItem tsi in this.items) + if (tsi.Available) { + Size tsi_preferred = tsi.GetPreferredSize (Size.Empty); + new_size.Width += tsi_preferred.Width + tsi.Margin.Left + tsi.Margin.Right; + + if (new_size.Height < (this.Padding.Vertical + tsi_preferred.Height + tsi.Margin.Vertical)) + new_size.Height = (this.Padding.Vertical + tsi_preferred.Height + tsi.Margin.Vertical); + } + + new_size.Width += (this.GripRectangle.Width + this.GripMargin.Horizontal + this.Padding.Horizontal + 4); + + if (new_size.Height == 0) + new_size.Height = ExplicitBounds.Height; + + if (this is StatusStrip) + new_size.Height = Math.Max (new_size.Height, 22); + + return new_size; + } + } + + internal virtual ToolStrip GetTopLevelToolStrip () + { + return this; + } + + internal virtual void HandleItemClick (ToolStripItem dismissingItem) + { + this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.ItemClicked); + } + + internal void NotifySelectedChanged (ToolStripItem tsi) + { + foreach (ToolStripItem tsi2 in this.DisplayedItems) + if (tsi != tsi2) + if (tsi2 is ToolStripDropDownItem) + (tsi2 as ToolStripDropDownItem).HideDropDown (ToolStripDropDownCloseReason.Keyboard); + + if (this.OverflowButton != null) { + ToolStripItemCollection tsic = this.OverflowButton.DropDown.DisplayedItems; + + foreach (ToolStripItem tsi2 in tsic) + if (tsi != tsi2) + if (tsi2 is ToolStripDropDownItem) + (tsi2 as ToolStripDropDownItem).HideDropDown (ToolStripDropDownCloseReason.Keyboard); + + this.OverflowButton.HideDropDown (); + } + + foreach (ToolStripItem tsi2 in this.Items) + if (tsi != tsi2) + tsi2.Dismiss (ToolStripDropDownCloseReason.Keyboard); + } + + internal virtual bool OnMenuKey () + { + return false; + } + + internal virtual bool ProcessArrowKey (Keys keyData) + { + ToolStripItem tsi; + + switch (keyData) { + case Keys.Right: + tsi = this.GetCurrentlySelectedItem (); + + if (tsi is ToolStripWidgetHost) + return false; + + tsi = this.SelectNextToolStripItem (tsi, true); + + if (tsi is ToolStripWidgetHost) + (tsi as ToolStripWidgetHost).Focus (); + + return true; + case Keys.Tab: + tsi = this.GetCurrentlySelectedItem (); + + tsi = this.SelectNextToolStripItem (tsi, true); + + if (tsi is ToolStripWidgetHost) + (tsi as ToolStripWidgetHost).Focus (); + + return true; + case Keys.Left: + tsi = this.GetCurrentlySelectedItem (); + + if (tsi is ToolStripWidgetHost) + return false; + + tsi = this.SelectNextToolStripItem (tsi, false); + + if (tsi is ToolStripWidgetHost) + (tsi as ToolStripWidgetHost).Focus (); + + return true; + case Keys.Shift | Keys.Tab: + tsi = this.GetCurrentlySelectedItem (); + + tsi = this.SelectNextToolStripItem (tsi, false); + + if (tsi is ToolStripWidgetHost) + (tsi as ToolStripWidgetHost).Focus (); + + return true; + } + + return false; + } + + internal virtual ToolStripItem SelectNextToolStripItem (ToolStripItem start, bool forward) + { + ToolStripItem next_item = this.GetNextItem (start, forward ? ArrowDirection.Right : ArrowDirection.Left); + + if (next_item == null) + return next_item; + + this.ChangeSelection (next_item); + + if (next_item is ToolStripWidgetHost) + (next_item as ToolStripWidgetHost).Focus (); + + return next_item; + } + + #region Stuff for ToolTips + private void MouseEnteredItem (ToolStripItem item) + { + if (this.show_item_tool_tips && !(item is ToolStripTextBox)) { + ToolTipTimer.Interval = InitialToolTipDelay; + tooltip_state = ToolTip.TipState.Initial; + tooltip_currently_showing = item; + ToolTipTimer.Start (); + } + } + + private void CloseToolTip (ToolStripItem item) + { + ToolTipTimer.Stop (); + ToolTipWindow.Hide (this); + tooltip_currently_showing = null; + tooltip_state = ToolTip.TipState.Down; + } + + private void MouseLeftItem (ToolStripItem item) + { + CloseToolTip (item); + } + + private Timer ToolTipTimer { + get { + if (tooltip_timer == null) { + tooltip_timer = new Timer (); + tooltip_timer.Enabled = false; + tooltip_timer.Interval = InitialToolTipDelay; + tooltip_timer.Tick += new EventHandler (ToolTipTimer_Tick); + } + + return tooltip_timer; + } + } + + private ToolTip ToolTipWindow { + get { + if (tooltip_window == null) + tooltip_window = new ToolTip (); + + return tooltip_window; + } + } + + private void ShowToolTip () + { + string tooltip = tooltip_currently_showing.GetToolTip (); + + if (!string.IsNullOrEmpty (tooltip)) { + ToolTipWindow.Present (this, tooltip); + ToolTipTimer.Interval = ToolTipDelay; + ToolTipTimer.Start (); + tooltip_state = ToolTip.TipState.Show; + } + + tooltip_currently_showing.FireEvent (EventArgs.Empty, ToolStripItemEventType.MouseHover); + } + + private void ToolTipTimer_Tick (object o, EventArgs args) + { + ToolTipTimer.Stop (); + + switch (tooltip_state) { + case ToolTip.TipState.Initial: + ShowToolTip (); + break; + case ToolTip.TipState.Show: + CloseToolTip (null); + break; + } + } + #endregion + + #region Stuff for Merging + internal ToolStrip CurrentlyMergedWith { + get { return this.currently_merged_with; } + set { this.currently_merged_with = value; } + } + + internal List HiddenMergedItems { + get { + if (this.hidden_merged_items == null) + this.hidden_merged_items = new List (); + + return this.hidden_merged_items; + } + } + + internal bool IsCurrentlyMerged { + get { return this.is_currently_merged; } + set { + this.is_currently_merged = value; + + if (!value && this is MenuStrip) + foreach (ToolStripMenuItem tsmi in this.Items) + tsmi.DropDown.IsCurrentlyMerged = value; + } + } + + internal void BeginMerge () + { + if (!IsCurrentlyMerged) { + IsCurrentlyMerged = true; + + if (this.pre_merge_items == null) { + this.pre_merge_items = new List (); + + foreach (ToolStripItem tsi in this.Items) + this.pre_merge_items.Add (tsi); + } + } + } + + internal void RevertMergeItem (ToolStripItem item) + { + int index = 0; + + // Remove it from it's current Parent + if (item.Parent != null && item.Parent != this) { + if (item.Parent is ToolStripOverflow) + (item.Parent as ToolStripOverflow).ParentToolStrip.Items.RemoveNoOwnerOrLayout (item); + else + item.Parent.Items.RemoveNoOwnerOrLayout (item); + + item.Parent = item.Owner; + } + + // Find where the item was before the merge + index = item.Owner.pre_merge_items.IndexOf (item); + + // Find the first pre-merge item that was after this item, that + // is currently in the Items collection. Insert our item before + // that one. + for (int i = index; i < this.pre_merge_items.Count; i++) { + if (this.Items.Contains (this.pre_merge_items[i])) { + item.Owner.Items.InsertNoOwnerOrLayout (this.Items.IndexOf (this.pre_merge_items[i]), item); + return; + } + } + + // There aren't any items that are supposed to be after this item, + // so just append it to the end. + item.Owner.Items.AddNoOwnerOrLayout (item); + } + #endregion + #endregion + + #region ToolStripAccessibleObject + [ComVisible (true)] + public class ToolStripAccessibleObject : WidgetAccessibleObject + { + #region Public Constructor + public ToolStripAccessibleObject (ToolStrip owner) : base (owner) + { + } + #endregion + + #region Public Properties + public override AccessibleRole Role { + get { return AccessibleRole.ToolBar; } + } + #endregion + + #region Public Methods + public override AccessibleObject GetChild (int index) + { + return base.GetChild (index); + } + + public override int GetChildCount () + { + return (owner as ToolStrip).Items.Count; + } + + public override AccessibleObject HitTest (int x, int y) + { + return base.HitTest (x, y); + } + #endregion + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripArrowRenderEventArgs.cs b/source/ShiftUI/ToolStrip/ToolStripArrowRenderEventArgs.cs new file mode 100644 index 0000000..f11b44f --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripArrowRenderEventArgs.cs @@ -0,0 +1,79 @@ +// +// ToolStripArrowRenderEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System; + +namespace ShiftUI +{ + public class ToolStripArrowRenderEventArgs : EventArgs + { + private Color arrow_color; + private Rectangle arrow_rectangle; + private ArrowDirection arrow_direction; + private Graphics graphics; + private ToolStripItem tool_strip_item; + + #region Public Constructors + public ToolStripArrowRenderEventArgs (Graphics g, ToolStripItem toolStripItem, Rectangle arrowRectangle, Color arrowColor, ArrowDirection arrowDirection) + : base () + { + this.graphics = g; + this.tool_strip_item = toolStripItem; + this.arrow_rectangle = arrowRectangle; + this.arrow_color = arrowColor; + this.arrow_direction = arrowDirection; + } + #endregion // Public Constructors + + #region Public Instance Properties + public Color ArrowColor { + get { return this.arrow_color; } + set { this.arrow_color = value; } + } + + public Rectangle ArrowRectangle { + get { return this.arrow_rectangle; } + set { this.arrow_rectangle = value; } + } + + public ArrowDirection Direction { + get { return this.arrow_direction; } + set { this.arrow_direction = value; } + } + + public Graphics Graphics { + get { return this.graphics; } + } + + public ToolStripItem Item { + get { return this.tool_strip_item; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripArrowRenderEventHandler.cs b/source/ShiftUI/ToolStrip/ToolStripArrowRenderEventHandler.cs new file mode 100644 index 0000000..1e6e139 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripArrowRenderEventHandler.cs @@ -0,0 +1,32 @@ +// +// ToolStripArrowRenderEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ToolStripArrowRenderEventHandler (object sender, ToolStripArrowRenderEventArgs e); +} diff --git a/source/ShiftUI/ToolStrip/ToolStripButton.cs b/source/ShiftUI/ToolStrip/ToolStripButton.cs new file mode 100644 index 0000000..939ba5b --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripButton.cs @@ -0,0 +1,250 @@ +// +// ToolStripButton.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Drawing; +using System.ComponentModel; +using ShiftUI.Design; + +namespace ShiftUI +{ + [ToolStripItemDesignerAvailability (ToolStripItemDesignerAvailability.ToolStrip)] + public class ToolStripButton : ToolStripItem + { + private CheckState checked_state; + private bool check_on_click; + + #region Public Constructors + public ToolStripButton () + : this (null, null, null, String.Empty) + { + } + + public ToolStripButton (Image image) + : this (null, image, null, String.Empty) + { + } + + public ToolStripButton (string text) + : this (text, null, null, String.Empty) + { + } + + public ToolStripButton (string text, Image image) + : this (text, image, null, String.Empty) + { + } + + public ToolStripButton (string text, Image image, EventHandler onClick) + : this (text, image, onClick, String.Empty) + { + } + + public ToolStripButton (string text, Image image, EventHandler onClick, string name) + : base (text, image, onClick, name) + { + this.checked_state = CheckState.Unchecked; + this.ToolTipText = String.Empty; + } + #endregion + + #region Public Properties + [DefaultValue (true)] + public new bool AutoToolTip { + get { return base.AutoToolTip; } + set { base.AutoToolTip = value; } + } + + public override bool CanSelect { + get { return true; } + } + + [DefaultValue (false)] + public bool Checked { + get { + switch (this.checked_state) { + case CheckState.Unchecked: + default: + return false; + case CheckState.Checked: + case CheckState.Indeterminate: + return true; + } + } + set { + if (this.checked_state != (value ? CheckState.Checked : CheckState.Unchecked)) { + this.checked_state = value ? CheckState.Checked : CheckState.Unchecked; + this.OnCheckedChanged (EventArgs.Empty); + this.OnCheckStateChanged (EventArgs.Empty); + this.Invalidate (); + } + } + } + + [DefaultValue (false)] + public bool CheckOnClick { + get { return this.check_on_click; } + set { + if (this.check_on_click != value) { + this.check_on_click = value; + OnUIACheckOnClickChangedEvent (EventArgs.Empty); + } + } + } + + [DefaultValue (CheckState.Unchecked)] + public CheckState CheckState { + get { return this.checked_state; } + set { + if (this.checked_state != value) { + if (!Enum.IsDefined (typeof (CheckState), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for CheckState", value)); + + this.checked_state = value; + this.OnCheckedChanged (EventArgs.Empty); + this.OnCheckStateChanged (EventArgs.Empty); + this.Invalidate (); + } + } + } + #endregion + + #region Protected Properties + protected override bool DefaultAutoToolTip { get { return true; } } + #endregion + + #region Public Methods + public override Size GetPreferredSize (Size constrainingSize) + { + Size retval = base.GetPreferredSize (constrainingSize); + + if (retval.Width < 23) + retval.Width = 23; + + return retval; + } + #endregion + + #region Protected Methods + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override AccessibleObject CreateAccessibilityInstance () + { + ToolStripItemAccessibleObject ao = new ToolStripItemAccessibleObject (this); + + ao.default_action = "Press"; + ao.role = AccessibleRole.PushButton; + ao.state = AccessibleStates.Focusable; + + return ao; + } + + protected virtual void OnCheckedChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [CheckedChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnCheckStateChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [CheckStateChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnClick (EventArgs e) + { + if (this.check_on_click) + this.Checked = !this.Checked; + + base.OnClick (e); + + ToolStrip ts = this.GetTopLevelToolStrip (); + + if (ts != null) + ts.Dismiss (ToolStripDropDownCloseReason.ItemClicked); + } + + protected override void OnPaint (ShiftUI.PaintEventArgs e) + { + base.OnPaint (e); + + if (this.Owner != null) { + Color font_color = this.Enabled ? this.ForeColor : SystemColors.GrayText; + Image draw_image = this.Enabled ? this.Image : ToolStripRenderer.CreateDisabledImage (this.Image); + + this.Owner.Renderer.DrawButtonBackground (new ShiftUI.ToolStripItemRenderEventArgs (e.Graphics, this)); + + Rectangle text_layout_rect; + Rectangle image_layout_rect; + + this.CalculateTextAndImageRectangles (out text_layout_rect, out image_layout_rect); + + if (text_layout_rect != Rectangle.Empty) + this.Owner.Renderer.DrawItemText (new ShiftUI.ToolStripItemTextRenderEventArgs (e.Graphics, this, this.Text, text_layout_rect, font_color, this.Font, this.TextAlign)); + if (image_layout_rect != Rectangle.Empty) + this.Owner.Renderer.DrawItemImage (new ShiftUI.ToolStripItemImageRenderEventArgs (e.Graphics, this, draw_image, image_layout_rect)); + + return; + } + } + #endregion + + #region Public Events + static object CheckedChangedEvent = new object (); + static object CheckStateChangedEvent = new object (); + + public event EventHandler CheckedChanged { + add { Events.AddHandler (CheckedChangedEvent, value); } + remove { Events.RemoveHandler (CheckedChangedEvent, value); } + } + + public event EventHandler CheckStateChanged { + add { Events.AddHandler (CheckStateChangedEvent, value); } + remove { Events.RemoveHandler (CheckStateChangedEvent, value); } + } + #endregion + + #region UIA Framework Events + static object UIACheckOnClickChangedEvent = new object (); + + internal event EventHandler UIACheckOnClickChanged { + add { Events.AddHandler (UIACheckOnClickChangedEvent, value); } + remove { Events.RemoveHandler (UIACheckOnClickChangedEvent, value); } + } + + internal void OnUIACheckOnClickChangedEvent (EventArgs args) + { + EventHandler eh + = (EventHandler) Events [UIACheckOnClickChangedEvent]; + if (eh != null) + eh (this, args); + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripComboBox.cs b/source/ShiftUI/ToolStrip/ToolStripComboBox.cs new file mode 100644 index 0000000..617253a --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripComboBox.cs @@ -0,0 +1,421 @@ +// +// ToolStripComboBox.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System.ComponentModel; +using ShiftUI.Design; +using System; + +namespace ShiftUI +{ + [DefaultProperty ("Items")] + [ToolStripItemDesignerAvailability (ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.MenuStrip | ToolStripItemDesignerAvailability.ContextMenuStrip)] + public class ToolStripComboBox : ToolStripWidgetHost + { + #region Public Constructors + public ToolStripComboBox () : base (new ToolStripComboBoxWidget ()) + { + // The default size of a new ToolStripComboBox doesn't seem + // to be DefaultSize. + Size = new Size (121, 21); + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public ToolStripComboBox (Widget c) : base (c) + { + throw new NotSupportedException (); + } + + public ToolStripComboBox (string name) : this () + { + base.Name = name; + } + #endregion + + #region Public Properties + [Browsable (true)] + [Localizable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + //[Editor ("ShiftUI.Design.ListWidgetStringCollectionEditor, " + Consts.AssemblySystem_Design, + // //"System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)] + public AutoCompleteStringCollection AutoCompleteCustomSource { + get { return ComboBox.AutoCompleteCustomSource; } + set { ComboBox.AutoCompleteCustomSource = value; } + } + + [Browsable (true)] + [DefaultValue (AutoCompleteMode.None)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public AutoCompleteMode AutoCompleteMode { + get { return ComboBox.AutoCompleteMode; } + set { ComboBox.AutoCompleteMode = value; } + } + + [Browsable (true)] + [DefaultValue (AutoCompleteSource.None)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public AutoCompleteSource AutoCompleteSource { + get { return ComboBox.AutoCompleteSource; } + set { ComboBox.AutoCompleteSource = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override Image BackgroundImage { + get { return base.BackgroundImage; } + set { base.BackgroundImage = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public ComboBox ComboBox { + get { return (ComboBox)base.Widget; } + } + + [Browsable (true)] + [DefaultValue (106)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public int DropDownHeight { + get { return this.ComboBox.DropDownHeight; } + set { this.ComboBox.DropDownHeight = value; } + } + + [DefaultValue (ComboBoxStyle.DropDown)] + [RefreshProperties (RefreshProperties.Repaint)] + public ComboBoxStyle DropDownStyle { + get { return this.ComboBox.DropDownStyle; } + set { this.ComboBox.DropDownStyle = value; } + } + + public int DropDownWidth { + get { return this.ComboBox.DropDownWidth; } + set { this.ComboBox.DropDownWidth = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public bool DroppedDown { + get { return this.ComboBox.DroppedDown; } + set { this.ComboBox.DroppedDown = value; } + } + + [LocalizableAttribute (true)] + [DefaultValue (FlatStyle.Popup)] + public FlatStyle FlatStyle { + get { return ComboBox.FlatStyle; } + set { ComboBox.FlatStyle = value; } + } + + [Localizable (true)] + [DefaultValue (true)] + public bool IntegralHeight { + get { return this.ComboBox.IntegralHeight; } + set { this.ComboBox.IntegralHeight = value; } + } + + [Localizable (true)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + //[Editor ("ShiftUI.Design.ListWidgetStringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + public ComboBox.ObjectCollection Items { + get { return this.ComboBox.Items; } + } + + [Localizable (true)] + [DefaultValue (8)] + public int MaxDropDownItems { + get { return this.ComboBox.MaxDropDownItems; } + set { this.ComboBox.MaxDropDownItems = value; } + } + + [Localizable (true)] + [DefaultValue (0)] + public int MaxLength { + get { return this.ComboBox.MaxLength; } + set { this.ComboBox.MaxLength = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public int SelectedIndex { + get { return this.ComboBox.SelectedIndex; } + set { + this.ComboBox.SelectedIndex = value; + + if (this.ComboBox.SelectedIndex >= 0) + Text = Items [value].ToString (); + } + } + + [Bindable (true)] + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public Object SelectedItem { + get { return this.ComboBox.SelectedItem; } + set { this.ComboBox.SelectedItem = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public string SelectedText { + get { return this.ComboBox.SelectedText; } + set { this.ComboBox.SelectedText = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public int SelectionLength { + get { return this.ComboBox.SelectionLength; } + set { this.ComboBox.SelectionLength = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public int SelectionStart { + get { return this.ComboBox.SelectionStart; } + set { this.ComboBox.SelectionStart = value; } + } + + [DefaultValue (false)] + public bool Sorted { + get { return this.ComboBox.Sorted; } + set { this.ComboBox.Sorted = value; } + } + #endregion + + #region Protected Properties + protected internal override Padding DefaultMargin { get { return new Padding (1, 0, 1, 0); } } + protected override Size DefaultSize { get { return new Size (100, 22); } } + #endregion + + #region Public Methods + public void BeginUpdate () + { + this.ComboBox.BeginUpdate (); + } + + public void EndUpdate () + { + this.ComboBox.EndUpdate (); + } + + public int FindString (string s) + { + return this.ComboBox.FindString (s); + } + + public int FindString (string s, int startIndex) + { + return this.ComboBox.FindString (s, startIndex); + } + + public int FindStringExact (string s) + { + return this.ComboBox.FindStringExact (s); + } + + public int FindStringExact (string s, int startIndex) + { + return this.ComboBox.FindStringExact (s, startIndex); + } + + public int GetItemHeight (int index) + { + return this.ComboBox.GetItemHeight (index); + } + + public override Size GetPreferredSize (Size constrainingSize) + { + return base.GetPreferredSize (constrainingSize); + } + + public void Select (int start, int length) + { + this.ComboBox.Select (start, length); + } + + public void SelectAll () + { + this.ComboBox.SelectAll (); + } + + public override string ToString () + { + return this.ComboBox.ToString (); + } + #endregion + + #region Protected Methods + protected virtual void OnDropDown (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [DropDownEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnDropDownClosed (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [DropDownClosedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnDropDownStyleChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [DropDownStyleChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnSelectedIndexChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnSelectionChangeCommitted (EventArgs e) + { + } + + protected override void OnSubscribeWidgetEvents (Widget Widget) + { + base.OnSubscribeWidgetEvents (Widget); + + this.ComboBox.DropDown += new EventHandler (HandleDropDown); + this.ComboBox.DropDownClosed += new EventHandler(HandleDropDownClosed); + this.ComboBox.DropDownStyleChanged += new EventHandler (HandleDropDownStyleChanged); + this.ComboBox.SelectedIndexChanged += new EventHandler (HandleSelectedIndexChanged); + this.ComboBox.TextChanged += new EventHandler (HandleTextChanged); + this.ComboBox.TextUpdate += new EventHandler (HandleTextUpdate); + } + + protected virtual void OnTextUpdate (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [TextUpdateEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnUnsubscribeWidgetEvents (Widget Widget) + { + base.OnUnsubscribeWidgetEvents (Widget); + } + #endregion + + #region Public Events + static object DropDownEvent = new object (); + static object DropDownClosedEvent = new object (); + static object DropDownStyleChangedEvent = new object (); + static object SelectedIndexChangedEvent = new object (); + static object TextUpdateEvent = new object (); + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler DoubleClick { + add { base.DoubleClick += value; } + remove { base.DoubleClick -= value; } + } + + public event EventHandler DropDown { + add { Events.AddHandler (DropDownEvent, value); } + remove { Events.RemoveHandler (DropDownEvent, value); } + } + + public event EventHandler DropDownClosed { + add { Events.AddHandler (DropDownClosedEvent, value); } + remove { Events.RemoveHandler (DropDownClosedEvent, value); } + } + + public event EventHandler DropDownStyleChanged { + add { Events.AddHandler (DropDownStyleChangedEvent, value); } + remove { Events.RemoveHandler (DropDownStyleChangedEvent, value); } + } + + public event EventHandler SelectedIndexChanged { + add { Events.AddHandler (SelectedIndexChangedEvent, value); } + remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); } + } + + public event EventHandler TextUpdate { + add { Events.AddHandler (TextUpdateEvent, value); } + remove { Events.RemoveHandler (TextUpdateEvent, value); } + } + #endregion + + #region Private Methods + private void HandleDropDown (object sender, EventArgs e) + { + OnDropDown (e); + } + + private void HandleDropDownClosed (object sender, EventArgs e) + { + OnDropDownClosed (e); + } + + private void HandleDropDownStyleChanged (object sender, EventArgs e) + { + OnDropDownStyleChanged (e); + } + + private void HandleSelectedIndexChanged (object sender, EventArgs e) + { + OnSelectedIndexChanged (e); + } + + private void HandleTextChanged (object sender, EventArgs e) + { + OnTextChanged (e); + } + + private void HandleTextUpdate (object sender, EventArgs e) + { + OnTextUpdate (e); + } + #endregion + + private class ToolStripComboBoxWidget : ComboBox + { + public ToolStripComboBoxWidget () : base () + { + this.border_style = BorderStyle.None; + this.FlatStyle = FlatStyle.Popup; + } + } + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripContainer.cs b/source/ShiftUI/ToolStrip/ToolStripContainer.cs new file mode 100644 index 0000000..09e0373 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripContainer.cs @@ -0,0 +1,310 @@ +// +// ToolStripContainer.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Drawing; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + //[Designer ("ShiftUI.Design.ToolStripContainerDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + public class ToolStripContainer : ContainerWidget + { + private ToolStripPanel bottom_panel; + private ToolStripContentPanel content_panel; + private ToolStripPanel left_panel; + private ToolStripPanel right_panel; + private ToolStripPanel top_panel; + + #region Public Constructors + public ToolStripContainer () : base () + { + SetStyle (Widgetstyles.SupportsTransparentBackColor, true); + SetStyle (Widgetstyles.ResizeRedraw, true); + + content_panel = new ToolStripContentPanel (); + content_panel.Dock = DockStyle.Fill; + this.Widgets.Add (content_panel); + + this.top_panel = new ToolStripPanel (); + this.top_panel.Dock = DockStyle.Top; + this.top_panel.Height = 0; + this.Widgets.Add (top_panel); + + this.bottom_panel = new ToolStripPanel (); + this.bottom_panel.Dock = DockStyle.Bottom; + this.bottom_panel.Height = 0; + this.Widgets.Add (bottom_panel); + + this.left_panel = new ToolStripPanel (); + this.left_panel.Dock = DockStyle.Left; + this.left_panel.Width = 0; + this.Widgets.Add (left_panel); + + this.right_panel = new ToolStripPanel (); + this.right_panel.Dock = DockStyle.Right; + this.right_panel.Width = 0; + this.Widgets.Add (right_panel); + } + #endregion + + #region Public Properties + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override bool AutoScroll { + get { return base.AutoScroll; } + set { base.AutoScroll = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Size AutoScrollMargin { + get { return base.AutoScrollMargin; } + set { base.AutoScrollMargin = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Size AutoScrollMinSize { + get { return base.AutoScrollMinSize; } + set { base.AutoScrollMinSize = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Color BackColor { + get { return base.BackColor; } + set { base.BackColor = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Image BackgroundImage { + get { return base.BackgroundImage; } + set { base.BackgroundImage = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + [Localizable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + public ToolStripPanel BottomToolStripPanel { + get { return this.bottom_panel; } + } + + [DefaultValue (true)] + public bool BottomToolStripPanelVisible { + get { return this.bottom_panel.Visible; } + set { this.bottom_panel.Visible = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new bool CausesValidation { + get { return base.CausesValidation; } + set { base.CausesValidation = value; } + } + + [Localizable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + public ToolStripContentPanel ContentPanel { + get { return this.content_panel; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new ContextMenuStrip ContextMenuStrip { + get { return base.ContextMenuStrip; } + set { base.ContextMenuStrip = value; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new WidgetCollection Widgets { + get { return base.Widgets; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override Cursor Cursor { + get { return base.Cursor; } + set { base.Cursor = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Color ForeColor { + get { return base.ForeColor; } + set { base.ForeColor = value; } + } + + [Localizable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + public ToolStripPanel LeftToolStripPanel { + get { return this.left_panel; } + } + + [DefaultValue (true)] + public bool LeftToolStripPanelVisible { + get { return this.left_panel.Visible; } + set { this.left_panel.Visible = value; } + } + + [Localizable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + public ToolStripPanel RightToolStripPanel { + get { return this.right_panel; } + } + + [DefaultValue (true)] + public bool RightToolStripPanelVisible { + get { return this.right_panel.Visible; } + set { this.right_panel.Visible = value; } + } + + [Localizable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + public ToolStripPanel TopToolStripPanel { + get { return this.top_panel; } + } + + [DefaultValue (true)] + public bool TopToolStripPanelVisible { + get { return this.top_panel.Visible; } + set { this.top_panel.Visible = value; } + } + #endregion + + #region Protected Properties + protected override Size DefaultSize { + get { return new Size (150, 175); } + } + #endregion + + #region Protected Methods + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override WidgetCollection CreateWidgetsInstance () + { + return new ToolStripContainerTypedWidgetCollection (this); + } + + protected override void OnRightToLeftChanged (EventArgs e) + { + base.OnRightToLeftChanged (e); + } + + protected override void OnSizeChanged (EventArgs e) + { + base.OnSizeChanged (e); + } + #endregion + + #region Public Events + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new event EventHandler BackColorChanged { + add { base.BackColorChanged += value; } + remove { base.BackColorChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new event EventHandler BackgroundImageChanged { + add { base.BackgroundImageChanged += value; } + remove { base.BackgroundImageChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new event EventHandler BackgroundImageLayoutChanged { + add { base.BackgroundImageLayoutChanged += value; } + remove { base.BackgroundImageLayoutChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler CausesValidationChanged { + add { base.CausesValidationChanged += value; } + remove { base.CausesValidationChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler ContextMenuStripChanged { + add { base.ContextMenuStripChanged += value; } + remove { base.ContextMenuStripChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new event EventHandler CursorChanged { + add { base.CursorChanged += value; } + remove { base.CursorChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new event EventHandler ForeColorChanged { + add { base.ForeColorChanged += value; } + remove { base.ForeColorChanged -= value; } + } + #endregion + + #region Private Class : ToolStripContainerTypedWidgetCollection + private class ToolStripContainerTypedWidgetCollection : WidgetCollection + { + public ToolStripContainerTypedWidgetCollection (Widget owner) : base (owner) + { + } + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripContentPanel.cs b/source/ShiftUI/ToolStrip/ToolStripContentPanel.cs new file mode 100644 index 0000000..8719922 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripContentPanel.cs @@ -0,0 +1,304 @@ +// +// ToolStripContentPanel.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System.Runtime.InteropServices; +using ShiftUI.Layout; +using System.ComponentModel; +using System; + +namespace ShiftUI +{ + [ComVisible(true)] + [ClassInterface(ClassInterfaceType.AutoDispatch)] + [DefaultEvent ("Load")] + [ToolboxItem (false)] + [Docking (DockingBehavior.Never)] + [InitializationEvent ("Load")] + //[Designer ("ShiftUI.Design.ToolStripContentPanelDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + public class ToolStripContentPanel : Panel + { + private ToolStripRenderMode render_mode; + private ToolStripRenderer renderer; + + #region Public Constructors + public ToolStripContentPanel () : base () + { + this.RenderMode = ToolStripRenderMode.System; + } + #endregion + + #region Public Properties + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override AnchorStyles Anchor { + get { return base.Anchor; } + set { base.Anchor = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override bool AutoScroll { + get { return base.AutoScroll; } + set { base.AutoScroll = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Size AutoScrollMargin { + get { return base.AutoScrollMargin; } + set { base.AutoScrollMargin = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Size AutoScrollMinSize { + get { return base.AutoScrollMinSize; } + set { base.AutoScrollMinSize = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override bool AutoSize { + get { return base.AutoSize; } + set { base.AutoSize = value; } + } + + [Browsable (false)] + [Localizable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override AutoSizeMode AutoSizeMode { + get { return base.AutoSizeMode; } + set { base.AutoSizeMode = value; } + } + + public override Color BackColor { + get { return base.BackColor; } + set { base.BackColor = value; + + if (this.Parent != null) + this.Parent.BackColor = value; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new bool CausesValidation { + get { return base.CausesValidation; } + set { base.CausesValidation = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override DockStyle Dock { + get { return base.Dock; } + set { base.Dock = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Point Location { + get { return base.Location; } + set { base.Location = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override Size MaximumSize { + get { return base.MaximumSize; } + set { base.MaximumSize = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override Size MinimumSize { + get { return base.MinimumSize; } + set { base.MinimumSize = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new string Name { + get { return base.Name; } + set { base.Name = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public ToolStripRenderer Renderer { + get { + if (this.render_mode == ToolStripRenderMode.ManagerRenderMode) + return ToolStripManager.Renderer; + + return this.renderer; + } + set { + if (this.renderer != value) { + this.renderer = value; + this.render_mode = ToolStripRenderMode.Custom; + this.OnRendererChanged (EventArgs.Empty); + } + } + } + + public ToolStripRenderMode RenderMode { + get { return this.render_mode; } + set { + if (!Enum.IsDefined (typeof (ToolStripRenderMode), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripRenderMode", value)); + + if (value == ToolStripRenderMode.Custom && this.renderer == null) + throw new NotSupportedException ("Must set Renderer property before setting RenderMode to Custom"); + else if (value == ToolStripRenderMode.Professional) + this.renderer = new ToolStripProfessionalRenderer (); + else if (value == ToolStripRenderMode.System) + this.renderer = new ToolStripSystemRenderer (); + + this.render_mode = value; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new int TabIndex { + get { return base.TabIndex; } + set { base.TabIndex = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new bool TabStop { + get { return base.TabStop; } + set { base.TabStop = value; } + } + #endregion + + #region Protected Methods + protected override void OnHandleCreated (EventArgs e) + { + base.OnHandleCreated (e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnLoad (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [LoadEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void OnPaintBackground (PaintEventArgs e) + { + base.OnPaintBackground (e); + + this.Renderer.DrawToolStripContentPanelBackground (new ToolStripContentPanelRenderEventArgs (e.Graphics, this)); + } + + protected virtual void OnRendererChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [RendererChangedEvent]); + if (eh != null) + eh (this, e); + } + #endregion + + #region Public Events + static object LoadEvent = new object (); + static object RendererChangedEvent = new object (); + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new event EventHandler AutoSizeChanged { + add { base.AutoSizeChanged += value; } + remove { base.AutoSizeChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler CausesValidationChanged { + add { base.CausesValidationChanged += value; } + remove { base.CausesValidationChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new event EventHandler DockChanged { + add { base.DockChanged += value; } + remove { base.DockChanged -= value; } + } + + public event EventHandler Load { + add { Events.AddHandler (LoadEvent, value); } + remove { Events.RemoveHandler (LoadEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new event EventHandler LocationChanged { + add { base.LocationChanged += value; } + remove { base.LocationChanged -= value; } + } + + public event EventHandler RendererChanged { + add { Events.AddHandler (RendererChangedEvent, value); } + remove { Events.RemoveHandler (RendererChangedEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TabIndexChanged { + add { base.TabIndexChanged += value; } + remove { base.TabIndexChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TabStopChanged { + add { base.TabStopChanged += value; } + remove { base.TabStopChanged -= value; } + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripContentPanelRenderEventArgs.cs b/source/ShiftUI/ToolStrip/ToolStripContentPanelRenderEventArgs.cs new file mode 100644 index 0000000..313e0e5 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripContentPanelRenderEventArgs.cs @@ -0,0 +1,62 @@ +// +// ToolStripContentPanelRenderEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System; + +namespace ShiftUI +{ + public class ToolStripContentPanelRenderEventArgs : EventArgs + { + private Graphics graphics; + private bool handled; + private ToolStripContentPanel tool_strip_content_panel; + + public ToolStripContentPanelRenderEventArgs (Graphics g, ToolStripContentPanel contentPanel) : base () + { + this.graphics = g; + this.tool_strip_content_panel = contentPanel; + this.handled = false; + } + + #region Public Properties + public Graphics Graphics { + get { return this.graphics; } + } + + public bool Handled { + get { return this.handled; } + set { this.handled = value; } + } + + public ToolStripContentPanel ToolStripContentPanel { + get { return this.tool_strip_content_panel; } + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripContentPanelRenderEventHandler.cs b/source/ShiftUI/ToolStrip/ToolStripContentPanelRenderEventHandler.cs new file mode 100644 index 0000000..4901230 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripContentPanelRenderEventHandler.cs @@ -0,0 +1,32 @@ +// +// ToolStripContentPanelRenderEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ToolStripContentPanelRenderEventHandler (object sender, ToolStripContentPanelRenderEventArgs e); +} diff --git a/source/ShiftUI/ToolStrip/ToolStripControlHost.cs b/source/ShiftUI/ToolStrip/ToolStripControlHost.cs new file mode 100644 index 0000000..cf2aeb1 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripControlHost.cs @@ -0,0 +1,577 @@ +// +// ToolStripWidgetHost.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System.ComponentModel; +using System; + +namespace ShiftUI +{ + public class ToolStripWidgetHost : ToolStripItem + { + private Widget _Widget; + private ContentAlignment Widget_align; + private bool double_click_enabled; + + #region Public Constructors + public ToolStripWidgetHost (Widget c) : base () + { + if (c == null) + throw new ArgumentNullException ("c"); + + this.RightToLeft = RightToLeft.No; + this._Widget = c; + this._Widget.Alignment = ContentAlignment.MiddleCenter; + this._Widget.TabStop = false; + this._Widget.Resize += WidgetResizeHandler; + this.Size = DefaultSize; + this.OnSubscribeWidgetEvents (this.Widget); + } + + public ToolStripWidgetHost (Widget c, string name) : this (c) + { + base.Name = name; + } + #endregion + + #region Public Properties + public override Color BackColor { + get { return Widget.BackColor; } + set { Widget.BackColor = value; + } + } + + [Localizable (true)] + [DefaultValue (null)] + public override Image BackgroundImage { + get { return base.BackgroundImage; } + set { base.BackgroundImage = value; } + } + + [Localizable (true)] + [DefaultValue (ImageLayout.Tile)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + public override bool CanSelect { + get { return Widget.CanSelect; } + } + + [DefaultValue (true)] + public bool CausesValidation { + get { return Widget.CausesValidation; } + set { Widget.CausesValidation = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public Widget Widget { + get { return this._Widget; } + } + + [Browsable (false)] + [DefaultValue (ContentAlignment.MiddleCenter)] + public ContentAlignment WidgetAlign { + get { return this.Widget_align; } + set { + if (Widget_align != value) { + if (!Enum.IsDefined (typeof (ContentAlignment), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ContentAlignment", value)); + + this.Widget_align = value; + + if (Widget != null) + Widget.Bounds = AlignInRectangle (this.Bounds, Widget.Size, this.Widget_align); + } + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new ToolStripItemDisplayStyle DisplayStyle { + get { return base.DisplayStyle; } + set { base.DisplayStyle = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + [DefaultValue (false)] + public new bool DoubleClickEnabled { + get { return this.double_click_enabled; } + set { this.double_click_enabled = value; } + } + + public override bool Enabled { + get { return base.Enabled; } + set { + base.Enabled = value; + Widget.Enabled = value; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public virtual bool Focused { + get { return Widget.Focused; } + } + + public override Font Font { + get { return Widget.Font; } + set { Widget.Font = value; } + } + + public override Color ForeColor { + get { return Widget.ForeColor; } + set { Widget.ForeColor = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override Image Image { + get { return base.Image; } + set { base.Image = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new ContentAlignment ImageAlign { + get { return base.ImageAlign; } + set { base.ImageAlign = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new ToolStripItemImageScaling ImageScaling { + get { return base.ImageScaling; } + set { base.ImageScaling = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Color ImageTransparentColor { + get { return base.ImageTransparentColor; } + set { base.ImageTransparentColor = value; } + } + + public override RightToLeft RightToLeft { + get { return base.RightToLeft; } + set { base.RightToLeft = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new bool RightToLeftAutoMirrorImage { + get { return base.RightToLeftAutoMirrorImage; } + set { base.RightToLeftAutoMirrorImage = value; } + } + + public override bool Selected { + get { return base.Selected; } + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public override ISite Site { + get { return Widget.Site; } + set { Widget.Site = value; + } + } + + public override Size Size { + get { return base.Size; } + set { Widget.Size = value; base.Size = value; if (this.Owner != null) this.Owner.PerformLayout (); } + } + + [DefaultValue ("")] + public override string Text { + get { return Widget.Text; } + set { + base.Text = value; + Widget.Text = value; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new ContentAlignment TextAlign { + get { return base.TextAlign; } + set { base.TextAlign = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + [DefaultValue (ToolStripTextDirection.Horizontal)] + public override ToolStripTextDirection TextDirection { + get { return base.TextDirection; } + set { base.TextDirection = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new TextImageRelation TextImageRelation { + get { return base.TextImageRelation; } + set { base.TextImageRelation = value; } + } + #endregion + + #region Protected Properties + protected override Size DefaultSize { + get { + if (Widget == null) + return new Size (23, 23); + + return Widget.Size; + } + } + #endregion + + #region Public Methods + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public void Focus () + { + Widget.Focus (); + } + + public override Size GetPreferredSize (Size constrainingSize) + { + return Widget.GetPreferredSize (constrainingSize); + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public override void ResetBackColor () + { + base.ResetBackColor (); + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public override void ResetForeColor () + { + base.ResetForeColor (); + } + #endregion + + #region Protected Methods + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override AccessibleObject CreateAccessibilityInstance () + { + return Widget.AccessibilityObject; + } + + protected override void Dispose (bool disposing) + { + base.Dispose (disposing); + + if (Widget.Created && !Widget.IsDisposed) + Widget.Dispose (); + } + + protected override void OnBoundsChanged () + { + if (Widget != null) + Widget.Bounds = AlignInRectangle (this.Bounds, Widget.Size, this.Widget_align); + + base.OnBoundsChanged (); + } + + protected virtual void OnEnter (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [EnterEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnGotFocus (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [GotFocusEvent]); + if (eh != null) + eh (this, e); + } + + void WidgetResizeHandler (object obj, EventArgs args) + { + OnHostedWidgetResize (args); + } + + protected virtual void OnHostedWidgetResize (EventArgs e) + { + // Since the Widget size has been just adjusted, only update the location + if (Widget != null) + Widget.Location = AlignInRectangle (this.Bounds, Widget.Size, this.Widget_align).Location; + } + + protected virtual void OnKeyDown (KeyEventArgs e) + { + KeyEventHandler eh = (KeyEventHandler)(Events [KeyDownEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnKeyPress (KeyPressEventArgs e) + { + KeyPressEventHandler eh = (KeyPressEventHandler)(Events [KeyPressEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnKeyUp (KeyEventArgs e) + { + KeyEventHandler eh = (KeyEventHandler)(Events [KeyUpEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnLayout (LayoutEventArgs e) + { + base.OnLayout (e); + + if (Widget != null) + Widget.Bounds = AlignInRectangle (this.Bounds, Widget.Size, this.Widget_align); + } + + protected virtual void OnLeave (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [LeaveEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnLostFocus (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [LostFocusEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnPaint (PaintEventArgs e) + { + base.OnPaint (e); + } + + protected override void OnParentChanged (ToolStrip oldParent, ToolStrip newParent) + { + base.OnParentChanged (oldParent, newParent); + + if (oldParent != null) + oldParent.Widgets.Remove (Widget); + + if (newParent != null) + newParent.Widgets.Add (Widget); + } + + protected virtual void OnSubscribeWidgetEvents (Widget Widget) + { + this.Widget.Enter += new EventHandler (HandleEnter); + this.Widget.GotFocus += new EventHandler (HandleGotFocus); + this.Widget.KeyDown += new KeyEventHandler (HandleKeyDown); + this.Widget.KeyPress += new KeyPressEventHandler (HandleKeyPress); + this.Widget.KeyUp += new KeyEventHandler (HandleKeyUp); + this.Widget.Leave += new EventHandler (HandleLeave); + this.Widget.LostFocus += new EventHandler (HandleLostFocus); + this.Widget.Validated += new EventHandler (HandleValidated); + this.Widget.Validating += new CancelEventHandler (HandleValidating); + } + + protected virtual void OnUnsubscribeWidgetEvents (Widget Widget) + { + } + + protected virtual void OnValidated (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [ValidatedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnValidating (CancelEventArgs e) + { + CancelEventHandler eh = (CancelEventHandler)(Events [ValidatingEvent]); + if (eh != null) + eh (this, e); + } + + protected internal override bool ProcessCmdKey (ref Message m, Keys keyData) + { + return base.ProcessCmdKey (ref m, keyData); + } + + protected internal override bool ProcessDialogKey (Keys keyData) + { + return base.ProcessDialogKey (keyData); + } + + protected override void SetVisibleCore (bool visible) + { + base.SetVisibleCore (visible); + this.Widget.Visible = visible; + + if (Widget != null) + Widget.Bounds = AlignInRectangle (this.Bounds, Widget.Size, this.Widget_align); + } + #endregion + + #region Public Events + static object EnterEvent = new object (); + static object GotFocusEvent = new object (); + static object KeyDownEvent = new object (); + static object KeyPressEvent = new object (); + static object KeyUpEvent = new object (); + static object LeaveEvent = new object (); + static object LostFocusEvent = new object (); + static object ValidatedEvent = new object (); + static object ValidatingEvent = new object (); + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler DisplayStyleChanged { + add { base.DisplayStyleChanged += value; } + remove { base.DisplayStyleChanged -= value; } + } + + public event EventHandler Enter { + add { Events.AddHandler (EnterEvent, value); } + remove { Events.RemoveHandler (EnterEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public event EventHandler GotFocus { + add { Events.AddHandler (GotFocusEvent, value); } + remove { Events.RemoveHandler (GotFocusEvent, value); } + } + + public event KeyEventHandler KeyDown { + add { Events.AddHandler (KeyDownEvent, value); } + remove { Events.RemoveHandler (KeyDownEvent, value); } + } + + public event KeyPressEventHandler KeyPress { + add { Events.AddHandler (KeyPressEvent, value); } + remove { Events.RemoveHandler (KeyPressEvent, value); } + } + + public event KeyEventHandler KeyUp { + add { Events.AddHandler (KeyUpEvent, value); } + remove { Events.RemoveHandler (KeyUpEvent, value); } + } + + public event EventHandler Leave { + add { Events.AddHandler (LeaveEvent, value); } + remove { Events.RemoveHandler (LeaveEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public event EventHandler LostFocus { + add { Events.AddHandler (LostFocusEvent, value); } + remove { Events.RemoveHandler (LostFocusEvent, value); } + } + + public event EventHandler Validated { + add { Events.AddHandler (ValidatedEvent, value); } + remove { Events.RemoveHandler (ValidatedEvent, value); } + } + + public event CancelEventHandler Validating { + add { Events.AddHandler (ValidatingEvent, value); } + remove { Events.RemoveHandler (ValidatingEvent, value); } + } + #endregion + + #region Private Methods + internal override ToolStripTextDirection DefaultTextDirection { get { return ToolStripTextDirection.Horizontal; } } + + internal override void Dismiss (ToolStripDropDownCloseReason reason) + { + if (this.Selected) + this.Parent.Focus (); + + base.Dismiss (reason); + } + + private void HandleEnter (object sender, EventArgs e) + { + this.OnEnter (e); + } + + private void HandleGotFocus (object sender, EventArgs e) + { + this.OnGotFocus (e); + } + + private void HandleKeyDown (object sender, KeyEventArgs e) + { + this.OnKeyDown (e); + } + + private void HandleKeyPress (object sender, KeyPressEventArgs e) + { + this.OnKeyPress (e); + } + + private void HandleKeyUp (object sender, KeyEventArgs e) + { + this.OnKeyUp (e); + } + + private void HandleLeave (object sender, EventArgs e) + { + this.OnLeave (e); + } + + private void HandleLostFocus (object sender, EventArgs e) + { + this.OnLostFocus (e); + } + + private void HandleValidated (object sender, EventArgs e) + { + this.OnValidated (e); + } + + private void HandleValidating (object sender, CancelEventArgs e) + { + this.OnValidating (e); + } + + internal override bool InternalVisible { + get { return base.InternalVisible; } + set { + Widget.Visible = value; + base.InternalVisible = value; + } + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripDropDown.cs b/source/ShiftUI/ToolStrip/ToolStripDropDown.cs new file mode 100644 index 0000000..443684e --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripDropDown.cs @@ -0,0 +1,1051 @@ +// +// ToolStripDropDown.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System.Runtime.InteropServices; +using System.ComponentModel; +using System; + +namespace ShiftUI +{ + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + //[Designer ("ShiftUI.Design.ToolStripDropDownDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + public class ToolStripDropDown : ToolStrip + { + private bool allow_transparency; + private bool auto_close; + private bool can_overflow; + private bool drop_shadow_enabled = true; + private double opacity = 1D; + private ToolStripItem owner_item; + + #region Public Constructor + public ToolStripDropDown () : base () + { + SetStyle (Widgetstyles.UserPaint | Widgetstyles.AllPaintingInWmPaint, true); + SetStyle (Widgetstyles.ResizeRedraw, true); + + this.auto_close = true; + is_visible = false; + this.DefaultDropDownDirection = ToolStripDropDownDirection.Right; + this.GripStyle = ToolStripGripStyle.Hidden; + this.is_toplevel = true; + } + #endregion + + #region Public Properties + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new bool AllowItemReorder { + get { return base.AllowItemReorder; } + set { base.AllowItemReorder = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public bool AllowTransparency { + get { return allow_transparency; } + set { + if (value == allow_transparency) + return; + + if ((XplatUI.SupportsTransparency () & TransparencySupport.Set) != 0) { + allow_transparency = value; + + if (this.IsHandleCreated) { + if (value) + XplatUI.SetWindowTransparency (Handle, Opacity, Color.Empty); + else + UpdateStyles (); // Remove the WS_EX_LAYERED style + } + } + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override AnchorStyles Anchor { + get { return base.Anchor; } + set { base.Anchor = value; } + } + + [DefaultValue (true)] + public bool AutoClose + { + get { return this.auto_close; } + set { this.auto_close = value; } + } + + [DefaultValue (true)] + public override bool AutoSize { + get { return base.AutoSize; } + set { base.AutoSize = value; } + } + + [Browsable (false)] + [DefaultValue (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new bool CanOverflow { + get { return this.can_overflow; } + set { this.can_overflow = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new ContextMenuStrip ContextMenuStrip { + get { return null; } + set { } + } + + public override ToolStripDropDownDirection DefaultDropDownDirection { + get { return base.DefaultDropDownDirection; } + set { base.DefaultDropDownDirection = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + [DefaultValue (DockStyle.None)] + public override DockStyle Dock { + get { return base.Dock; } + set { base.Dock = value; } + } + + public bool DropShadowEnabled { + get { return this.drop_shadow_enabled; } + set { + if (this.drop_shadow_enabled == value) + return; + + this.drop_shadow_enabled = value; + UpdateStyles (); // Re-CreateParams + } + } + + public override Font Font { + get { return base.Font; } + set { base.Font = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new ToolStripGripDisplayStyle GripDisplayStyle { + get { return ToolStripGripDisplayStyle.Vertical; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Padding GripMargin { + get { return Padding.Empty; } + set { } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new Rectangle GripRectangle { + get { return Rectangle.Empty; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + [DefaultValue (ToolStripGripStyle.Hidden)] + public new ToolStripGripStyle GripStyle { + get { return base.GripStyle; } + set { base.GripStyle = value; } + } + + [Browsable (false)] + public bool IsAutoGenerated { + get { return this is ToolStripOverflow; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Point Location { + get { return base.Location; } + set { base.Location = value; } + } + + [DefaultValue (1D)] + [TypeConverter (typeof (OpacityConverter))] + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public double Opacity { + get { return this.opacity; } + set { + if (this.opacity == value) + return; + + this.opacity = value; + this.allow_transparency = true; + + if (this.IsHandleCreated) { + UpdateStyles (); + XplatUI.SetWindowTransparency (Handle, opacity, Color.Empty); + } + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new ToolStripOverflowButton OverflowButton { + get { return base.OverflowButton; } + } + + [Browsable (false)] + [DefaultValue (null)] + public ToolStripItem OwnerItem { + get { return this.owner_item; } + set { this.owner_item = value; + + if (this.owner_item != null) { + if (this.owner_item.Owner != null && this.owner_item.Owner.RenderMode != ToolStripRenderMode.ManagerRenderMode) + this.Renderer = this.owner_item.Owner.Renderer; + + Font = owner_item.Font; + } + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new Region Region { + get { return base.Region; } + set { base.Region = value; } + } + + [Localizable (true)] + [AmbientValue (RightToLeft.Inherit)] + public override RightToLeft RightToLeft { + get { return base.RightToLeft; } + set { base.RightToLeft = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new bool Stretch { + get { return false; } + set { } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new int TabIndex { + get { return 0; } + set { } + } + + [Browsable (false)] + [DefaultValue (ToolStripTextDirection.Horizontal)] + public override ToolStripTextDirection TextDirection { + get { return base.TextDirection; } + set { base.TextDirection = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public bool TopLevel { + get { return GetTopLevel (); } + set { SetTopLevel (value); } + } + + [Browsable (false)] + [Localizable (true)] + [DefaultValue (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new bool Visible { + get { return base.Visible; } + set { base.Visible = value; } + } + #endregion + + #region Protected Properties + protected override CreateParams CreateParams { + get { + CreateParams cp = base.CreateParams; + + cp.Style = unchecked ((int)(WindowStyles.WS_POPUP | WindowStyles.WS_CLIPCHILDREN)); + cp.ClassStyle |= (int)XplatUIWin32.ClassStyle.CS_DROPSHADOW; + cp.ExStyle |= (int)(WindowExStyles.WS_EX_TOOLWINDOW | WindowExStyles.WS_EX_TOPMOST); + + if (Opacity < 1.0 && allow_transparency) + cp.ExStyle |= (int)WindowExStyles.WS_EX_LAYERED; + if (TopMost) + cp.ExStyle |= (int) WindowExStyles.WS_EX_TOPMOST; + + return cp; + } + } + + protected override DockStyle DefaultDock { + get { return DockStyle.None; } + } + + protected override Padding DefaultPadding { + get { return new Padding (1, 2, 1, 2); } + } + + protected override bool DefaultShowItemToolTips { + get { return true; } + } + + protected internal override Size MaxItemSize { + get { return new Size (Screen.PrimaryScreen.Bounds.Width - 2, Screen.PrimaryScreen.Bounds.Height - 34); } + } + + protected virtual bool TopMost { + get { return true; } + } + #endregion + + #region Public Methods + public void Close () + { + this.Close (ToolStripDropDownCloseReason.CloseCalled); + } + + public void Close (ToolStripDropDownCloseReason reason) + { + if (!this.Visible) + return; + + // Give users a chance to cancel the close + ToolStripDropDownClosingEventArgs e = new ToolStripDropDownClosingEventArgs (reason); + this.OnClosing (e); + + if (e.Cancel) + return; + + // Don't actually close if AutoClose == true unless explicitly called + if (!this.auto_close && reason != ToolStripDropDownCloseReason.CloseCalled) + return; + + // Detach from the tracker + ToolStripManager.AppClicked -= new EventHandler (ToolStripMenuTracker_AppClicked); ; + ToolStripManager.AppFocusChange -= new EventHandler (ToolStripMenuTracker_AppFocusChange); + + // Hide this dropdown + this.Hide (); + + // Owner MenuItem needs to be told to redraw (it's no longer selected) + if (owner_item != null) + owner_item.Invalidate (); + + // Recursive hide all child dropdowns + foreach (ToolStripItem tsi in this.Items) + tsi.Dismiss (reason); + + this.OnClosed (new ToolStripDropDownClosedEventArgs (reason)); + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new void Show () + { + Show (Location, DefaultDropDownDirection); + } + + public void Show (Point screenLocation) + { + Show (screenLocation, DefaultDropDownDirection); + } + + public void Show (Widget Widget, Point position) + { + if (Widget == null) + throw new ArgumentNullException ("Widget"); + + XplatUI.SetOwner (Handle, Widget.Handle); + Show (Widget.PointToScreen (position), DefaultDropDownDirection); + } + + public void Show (int x, int y) + { + Show (new Point (x, y), DefaultDropDownDirection); + } + + public void Show (Point position, ToolStripDropDownDirection direction) + { + this.PerformLayout (); + + Point show_point = position; + Point max_screen = new Point (SystemInformation.VirtualScreen.Width, SystemInformation.VirtualScreen.Height); + + if (this is ContextMenuStrip) { + // If we are going to go offscreen, adjust our direction so we don't... + // X direction + switch (direction) { + case ToolStripDropDownDirection.AboveLeft: + if (show_point.X - this.Width < 0) + direction = ToolStripDropDownDirection.AboveRight; + break; + case ToolStripDropDownDirection.BelowLeft: + if (show_point.X - this.Width < 0) + direction = ToolStripDropDownDirection.BelowRight; + break; + case ToolStripDropDownDirection.Left: + if (show_point.X - this.Width < 0) + direction = ToolStripDropDownDirection.Right; + break; + case ToolStripDropDownDirection.AboveRight: + if (show_point.X + this.Width > max_screen.X) + direction = ToolStripDropDownDirection.AboveLeft; + break; + case ToolStripDropDownDirection.BelowRight: + case ToolStripDropDownDirection.Default: + if (show_point.X + this.Width > max_screen.X) + direction = ToolStripDropDownDirection.BelowLeft; + break; + case ToolStripDropDownDirection.Right: + if (show_point.X + this.Width > max_screen.X) + direction = ToolStripDropDownDirection.Left; + break; + } + + // Y direction + switch (direction) { + case ToolStripDropDownDirection.AboveLeft: + if (show_point.Y - this.Height < 0) + direction = ToolStripDropDownDirection.BelowLeft; + break; + case ToolStripDropDownDirection.AboveRight: + if (show_point.Y - this.Height < 0) + direction = ToolStripDropDownDirection.BelowRight; + break; + case ToolStripDropDownDirection.BelowLeft: + if (show_point.Y + this.Height > max_screen.Y && show_point.Y - this.Height > 0) + direction = ToolStripDropDownDirection.AboveLeft; + break; + case ToolStripDropDownDirection.BelowRight: + case ToolStripDropDownDirection.Default: + if (show_point.Y + this.Height > max_screen.Y && show_point.Y - this.Height > 0) + direction = ToolStripDropDownDirection.AboveRight; + break; + case ToolStripDropDownDirection.Left: + if (show_point.Y + this.Height > max_screen.Y && show_point.Y - this.Height > 0) + direction = ToolStripDropDownDirection.AboveLeft; + break; + case ToolStripDropDownDirection.Right: + if (show_point.Y + this.Height > max_screen.Y && show_point.Y - this.Height > 0) + direction = ToolStripDropDownDirection.AboveRight; + break; + } + } + + switch (direction) { + case ToolStripDropDownDirection.AboveLeft: + show_point.Y -= this.Height; + show_point.X -= this.Width; + break; + case ToolStripDropDownDirection.AboveRight: + show_point.Y -= this.Height; + break; + case ToolStripDropDownDirection.BelowLeft: + show_point.X -= this.Width; + break; + case ToolStripDropDownDirection.Left: + show_point.X -= this.Width; + break; + case ToolStripDropDownDirection.Right: + break; + } + + // Fix offscreen horizontal positions + if ((show_point.X + this.Width) > max_screen.X) + show_point.X = max_screen.X - this.Width; + if (show_point.X < 0) + show_point.X = 0; + + // Fix offscreen vertical positions + if ((show_point.Y + this.Height) > max_screen.Y) + show_point.Y = max_screen.Y - this.Height; + if (show_point.Y < 0) + show_point.Y = 0; + + if (this.Location != show_point) + this.Location = show_point; + + CancelEventArgs e = new CancelEventArgs (); + this.OnOpening (e); + + if (e.Cancel) + return; + + // The tracker lets us know when the form is clicked or loses focus + ToolStripManager.AppClicked += new EventHandler (ToolStripMenuTracker_AppClicked); + ToolStripManager.AppFocusChange += new EventHandler (ToolStripMenuTracker_AppFocusChange); + + base.Show (); + + ToolStripManager.SetActiveToolStrip (this, ToolStripManager.ActivatedByKeyboard); + + this.OnOpened (EventArgs.Empty); + } + + public void Show (Widget Widget, int x, int y) + { + if (Widget == null) + throw new ArgumentNullException ("Widget"); + + Show (Widget, new Point (x, y)); + } + + public void Show (Widget Widget, Point position, ToolStripDropDownDirection direction) + { + if (Widget == null) + throw new ArgumentNullException ("Widget"); + + XplatUI.SetOwner (Handle, Widget.Handle); + Show (Widget.PointToScreen (position), direction); + } + #endregion + + #region Protected Methods + protected override AccessibleObject CreateAccessibilityInstance () + { + return new ToolStripDropDownAccessibleObject (this); + } + + protected override void CreateHandle () + { + base.CreateHandle (); + } + + protected override LayoutSettings CreateLayoutSettings (ToolStripLayoutStyle style) + { + return base.CreateLayoutSettings (style); + } + + protected override void Dispose (bool disposing) + { + base.Dispose (disposing); + } + + protected virtual void OnClosed (ToolStripDropDownClosedEventArgs e) + { + ToolStripDropDownClosedEventHandler eh = (ToolStripDropDownClosedEventHandler)(Events [ClosedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnClosing (ToolStripDropDownClosingEventArgs e) + { + ToolStripDropDownClosingEventHandler eh = (ToolStripDropDownClosingEventHandler)(Events [ClosingEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnHandleCreated (EventArgs e) + { + base.OnHandleCreated (e); + + if (Application.MWFThread.Current.Context != null && Application.MWFThread.Current.Context.MainForm != null) + XplatUI.SetOwner (this.Handle, Application.MWFThread.Current.Context.MainForm.Handle); + } + + protected override void OnItemClicked (ToolStripItemClickedEventArgs e) + { + base.OnItemClicked (e); + } + + protected override void OnLayout (LayoutEventArgs e) + { + // Find the widest menu item, so we know how wide to make our dropdown + int widest = 0; + + foreach (ToolStripItem tsi in this.Items) { + if (!tsi.Available) + continue; + + tsi.SetPlacement (ToolStripItemPlacement.Main); + + widest = Math.Max (widest, tsi.GetPreferredSize (Size.Empty).Width + tsi.Margin.Horizontal); + } + + // Add any padding our dropdown has set + widest += this.Padding.Horizontal; + + int x = this.Padding.Left; + int y = this.Padding.Top; + + foreach (ToolStripItem tsi in this.Items) { + if (!tsi.Available) + continue; + + y += tsi.Margin.Top; + + int height = 0; + + Size preferred_size = tsi.GetPreferredSize (Size.Empty); + + if (preferred_size.Height > 22) + height = preferred_size.Height; + else if (tsi is ToolStripSeparator) + height = 7; + else + height = 22; + + tsi.SetBounds (new Rectangle (x, y, preferred_size.Width, height)); + y += height + tsi.Margin.Bottom; + } + + this.Size = new Size (widest, y + this.Padding.Bottom); + this.SetDisplayedItems (); + this.OnLayoutCompleted (EventArgs.Empty); + this.Invalidate (); + } + + protected override void OnMouseUp (MouseEventArgs mea) + { + base.OnMouseUp (mea); + } + + protected virtual void OnOpened (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [OpenedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnOpening (CancelEventArgs e) + { + CancelEventHandler eh = (CancelEventHandler)(Events [OpeningEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnParentChanged (EventArgs e) + { + base.OnParentChanged (e); + + if (Parent is ToolStrip) + this.Renderer = (Parent as ToolStrip).Renderer; + } + + protected override void OnVisibleChanged (EventArgs e) + { + base.OnVisibleChanged (e); + + if (owner_item != null && owner_item is ToolStripDropDownItem) { + ToolStripDropDownItem dropdown_owner = (ToolStripDropDownItem)owner_item; + if (Visible) + dropdown_owner.OnDropDownOpened (EventArgs.Empty); + else + dropdown_owner.OnDropDownClosed (EventArgs.Empty); + } + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override bool ProcessDialogChar (char charCode) + { + return base.ProcessDialogChar (charCode); + } + + protected override bool ProcessDialogKey (Keys keyData) + { + // We don't want to let our base change the active ToolStrip + switch (keyData) { + case Keys.Widget | Keys.Tab: + case Keys.Widget | Keys.Shift | Keys.Tab: + return true; + } + + return base.ProcessDialogKey (keyData); + } + + protected override bool ProcessMnemonic (char charCode) + { + return base.ProcessMnemonic (charCode); + } + + protected override void ScaleWidget (SizeF factor, BoundsSpecified specified) + { + base.ScaleWidget (factor, specified); + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + protected override void ScaleCore (float dx, float dy) + { + base.ScaleCore (dx, dy); + } + + protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified) + { + base.SetBoundsCore (x, y, width, height, specified); + } + + protected override void SetVisibleCore (bool visible) + { + base.SetVisibleCore (visible); + } + + protected override void WndProc (ref Message m) + { + const int MA_NOACTIVATE = 0x0003; + + // Don't activate when the WM tells us to + if ((Msg)m.Msg == Msg.WM_MOUSEACTIVATE) { + m.Result = (IntPtr)MA_NOACTIVATE; + return; + } + + base.WndProc (ref m); + } + #endregion + + #region Public Events + static object ClosedEvent = new object (); + static object ClosingEvent = new object (); + static object OpenedEvent = new object (); + static object OpeningEvent = new object (); + static object ScrollEvent = new object (); + + [Browsable (false)] + public new event EventHandler BackgroundImageChanged { + add { base.BackgroundImageChanged += value; } + remove { base.BackgroundImageChanged -= value; } + } + + [Browsable (false)] + public new event EventHandler BackgroundImageLayoutChanged { + add { base.BackgroundImageLayoutChanged += value; } + remove { base.BackgroundImageLayoutChanged -= value; } + } + + [Browsable (false)] + public new event EventHandler BindingContextChanged { + add { base.BindingContextChanged += value; } + remove { base.BindingContextChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event UICuesEventHandler ChangeUICues { + add { base.ChangeUICues += value; } + remove { base.ChangeUICues -= value; } + } + + public event ToolStripDropDownClosedEventHandler Closed { + add { Events.AddHandler (ClosedEvent, value); } + remove { Events.RemoveHandler (ClosedEvent, value); } + } + + public event ToolStripDropDownClosingEventHandler Closing { + add { Events.AddHandler (ClosingEvent, value); } + remove { Events.RemoveHandler (ClosingEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler ContextMenuChanged { + add { base.ContextMenuChanged += value; } + remove { base.ContextMenuChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler ContextMenuStripChanged { + add { base.ContextMenuStripChanged += value; } + remove { base.ContextMenuStripChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler DockChanged { + add { base.DockChanged += value; } + remove { base.DockChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler Enter { + add { base.Enter += value; } + remove { base.Enter -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler FontChanged { + add { base.FontChanged += value; } + remove { base.FontChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler ForeColorChanged { + add { base.ForeColorChanged += value; } + remove { base.ForeColorChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event GiveFeedbackEventHandler GiveFeedback { + add { base.GiveFeedback += value; } + remove { base.GiveFeedback -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event HelpEventHandler HelpRequested { + add { base.HelpRequested += value; } + remove { base.HelpRequested -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler ImeModeChanged { + add { base.ImeModeChanged += value; } + remove { base.ImeModeChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event KeyEventHandler KeyDown { + add { base.KeyDown += value; } + remove { base.KeyDown -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event KeyPressEventHandler KeyPress { + add { base.KeyPress += value; } + remove { base.KeyPress -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event KeyEventHandler KeyUp { + add { base.KeyUp += value; } + remove { base.KeyUp -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler Leave { + add { base.Leave += value; } + remove { base.Leave -= value; } + } + + public event EventHandler Opened { + add { Events.AddHandler (OpenedEvent, value); } + remove { Events.RemoveHandler (OpenedEvent, value); } + } + + public event CancelEventHandler Opening { + add { Events.AddHandler (OpeningEvent, value); } + remove { Events.RemoveHandler (OpeningEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler RegionChanged { + add { base.RegionChanged += value; } + remove { base.RegionChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event ScrollEventHandler Scroll { + add { Events.AddHandler (ScrollEvent, value); } + remove { Events.RemoveHandler (ScrollEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler StyleChanged { + add { base.StyleChanged += value; } + remove { base.StyleChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TabIndexChanged { + add { base.TabIndexChanged += value; } + remove { base.TabIndexChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TabStopChanged { + add { base.TabStopChanged += value; } + remove { base.TabStopChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler Validated { + add { base.Validated += value; } + remove { base.Validated -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event CancelEventHandler Validating { + add { base.Validating += value; } + remove { base.Validating -= value; } + } + #endregion + + #region Private Methods + internal override void Dismiss (ToolStripDropDownCloseReason reason) + { + this.Close (reason); + base.Dismiss (reason); + + // ContextMenuStrip won't have a parent + if (this.OwnerItem == null) + return; + + // Ensure Submenu loes keyboard capture when closing. + ToolStripManager.SetActiveToolStrip (null, false); + } + + internal override ToolStrip GetTopLevelToolStrip () + { + if (this.OwnerItem == null) + return this; + + return this.OwnerItem.GetTopLevelToolStrip (); + } + + internal override bool ProcessArrowKey (Keys keyData) + { + switch (keyData) { + case Keys.Down: + case Keys.Tab: + this.SelectNextToolStripItem (this.GetCurrentlySelectedItem (), true); + return true; + case Keys.Up: + case Keys.Shift | Keys.Tab: + this.SelectNextToolStripItem (this.GetCurrentlySelectedItem (), false); + return true; + case Keys.Right: + this.GetTopLevelToolStrip ().SelectNextToolStripItem (this.TopLevelOwnerItem, true); + return true; + case Keys.Left: + case Keys.Escape: + this.Dismiss (ToolStripDropDownCloseReason.Keyboard); + + // ContextMenuStrip won't have a parent + if (this.OwnerItem == null) + return true; + + ToolStrip parent_strip = this.OwnerItem.Parent; + ToolStripManager.SetActiveToolStrip (parent_strip, true); + + if (parent_strip is MenuStrip && keyData == Keys.Left) { + parent_strip.SelectNextToolStripItem (this.TopLevelOwnerItem, false); + this.TopLevelOwnerItem.Invalidate (); + } else if (parent_strip is MenuStrip && keyData == Keys.Escape) { + (parent_strip as MenuStrip).MenuDroppedDown = false; + this.TopLevelOwnerItem.Select (); + } + return true; + } + + return false; + } + + internal override ToolStripItem SelectNextToolStripItem (ToolStripItem start, bool forward) + { + ToolStripItem next_item = this.GetNextItem (start, forward ? ArrowDirection.Down : ArrowDirection.Up); + + if (next_item != null) + this.ChangeSelection (next_item); + + return (next_item); + } + + private void ToolStripMenuTracker_AppFocusChange (object sender, EventArgs e) + { + this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppFocusChange); + } + + private void ToolStripMenuTracker_AppClicked (object sender, EventArgs e) + { + this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppClicked); + } + #endregion + + #region Internal Properties + internal override bool ActivateOnShow { get { return false; } } + + internal ToolStripItem TopLevelOwnerItem { + get { + ToolStripItem owner_item = this.OwnerItem; + ToolStrip ts = null; + + while (owner_item != null) { + ts = owner_item.Owner; + + if (ts != null && (ts is ToolStripDropDown)) + owner_item = (ts as ToolStripDropDown).OwnerItem; + else + return owner_item; + } + + return null; + } + } + #endregion + + #region ToolStripDropDownAccessibleObject + [ComVisible (true)] + public class ToolStripDropDownAccessibleObject : ToolStripAccessibleObject + { + #region Public Constructor + public ToolStripDropDownAccessibleObject (ToolStripDropDown owner) : base (owner) + { + } + #endregion + + #region Public Properties + public override string Name { + get { return base.Name; } + set { base.Name = value; } + } + + public override AccessibleRole Role { + get { return AccessibleRole.MenuPopup; } + } + #endregion + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripDropDownButton.cs b/source/ShiftUI/ToolStrip/ToolStripDropDownButton.cs new file mode 100644 index 0000000..2e8ecd8 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripDropDownButton.cs @@ -0,0 +1,185 @@ +// +// ToolStripDropDownButton.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System.Runtime.InteropServices; +using ShiftUI.Design; +using System.ComponentModel; +using System; + +namespace ShiftUI +{ + [ToolStripItemDesignerAvailability (ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.StatusStrip)] + public class ToolStripDropDownButton : ToolStripDropDownItem + { + private bool show_drop_down_arrow = true; + + #region Public Constructors + public ToolStripDropDownButton() + : this (string.Empty, null, null, string.Empty) + { + } + + public ToolStripDropDownButton (Image image) + : this (string.Empty, image, null, string.Empty) + { + } + + public ToolStripDropDownButton (string text) + : this (text, null, null, string.Empty) + { + } + + public ToolStripDropDownButton (string text, Image image) + : this (text, image, null, string.Empty) + { + } + + public ToolStripDropDownButton (string text, Image image, EventHandler onClick) + : this (text, image, onClick, string.Empty) + { + } + + public ToolStripDropDownButton (string text, Image image, params ToolStripItem[] dropDownItems) + : base (text, image, dropDownItems) + { + } + + public ToolStripDropDownButton (string text, Image image, EventHandler onClick, string name) + : base (text, image, onClick, name) + { + } + #endregion + + #region Public Properties + [DefaultValue (true)] + public new bool AutoToolTip { + get { return base.AutoToolTip; } + set { base.AutoToolTip = value; } + } + + [DefaultValue (true)] + public bool ShowDropDownArrow { + get { return this.show_drop_down_arrow; } + set { + if (this.show_drop_down_arrow != value) { + this.show_drop_down_arrow = value; + CalculateAutoSize (); + } + } + } + #endregion + + #region Protected Properties + protected override bool DefaultAutoToolTip { + get { return true; } + } + #endregion + + #region Protected Methods + protected override ToolStripDropDown CreateDefaultDropDown () + { + ToolStripDropDownMenu tsdd = new ToolStripDropDownMenu (); + tsdd.OwnerItem = this; + return tsdd; + } + + protected override void OnMouseDown (MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) { + if (this.DropDown.Visible) + this.HideDropDown (ToolStripDropDownCloseReason.ItemClicked); + else + this.ShowDropDown (); + } + + base.OnMouseDown (e); + } + + protected override void OnMouseLeave (EventArgs e) + { + base.OnMouseLeave (e); + } + + protected override void OnMouseUp (MouseEventArgs e) + { + base.OnMouseUp (e); + } + + protected override void OnPaint (PaintEventArgs e) + { + base.OnPaint (e); + + if (this.Owner != null) { + Color font_color = this.Enabled ? this.ForeColor : SystemColors.GrayText; + Image draw_image = this.Enabled ? this.Image : ToolStripRenderer.CreateDisabledImage (this.Image); + + this.Owner.Renderer.DrawDropDownButtonBackground (new ShiftUI.ToolStripItemRenderEventArgs (e.Graphics, this)); + + Rectangle text_layout_rect; + Rectangle image_layout_rect; + + this.CalculateTextAndImageRectangles (out text_layout_rect, out image_layout_rect); + + if (text_layout_rect != Rectangle.Empty) + this.Owner.Renderer.DrawItemText (new ShiftUI.ToolStripItemTextRenderEventArgs (e.Graphics, this, this.Text, text_layout_rect, font_color, this.Font, this.TextAlign)); + if (image_layout_rect != Rectangle.Empty) + this.Owner.Renderer.DrawItemImage (new ShiftUI.ToolStripItemImageRenderEventArgs (e.Graphics, this, draw_image, image_layout_rect)); + if (this.ShowDropDownArrow) + this.Owner.Renderer.DrawArrow (new ToolStripArrowRenderEventArgs (e.Graphics, this, new Rectangle (this.Width - 10, 0, 6, this.Height), Color.Black, ArrowDirection.Down)); + return; + } + } + + protected internal override bool ProcessMnemonic (char charCode) + { + if (!this.Selected) + this.Parent.ChangeSelection (this); + + if (this.HasDropDownItems) + this.ShowDropDown (); + else + this.PerformClick (); + + return true; + } + #endregion + + #region Internal Methods + internal override Size CalculatePreferredSize (Size constrainingSize) + { + Size preferred_size = base.CalculatePreferredSize (constrainingSize); + + if (this.ShowDropDownArrow) + preferred_size.Width += 9; + + return preferred_size; + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripDropDownCloseReason.cs b/source/ShiftUI/ToolStrip/ToolStripDropDownCloseReason.cs new file mode 100644 index 0000000..0d56a86 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripDropDownCloseReason.cs @@ -0,0 +1,40 @@ +// +// ToolStripDropDownCloseReason.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum ToolStripDropDownCloseReason + { + AppFocusChange = 0, + AppClicked = 1, + ItemClicked = 2, + Keyboard = 3, + CloseCalled = 4 + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripDropDownClosedEventArgs.cs b/source/ShiftUI/ToolStrip/ToolStripDropDownClosedEventArgs.cs new file mode 100644 index 0000000..d95fbe6 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripDropDownClosedEventArgs.cs @@ -0,0 +1,49 @@ +// +// ToolStripDropDownClosedEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + public class ToolStripDropDownClosedEventArgs : EventArgs + { + private ToolStripDropDownCloseReason close_reason; + + #region Public Constructors + public ToolStripDropDownClosedEventArgs (ToolStripDropDownCloseReason reason) : base () + { + this.close_reason = reason; + } + #endregion // Public Constructors + + #region Public Instance Properties + public ToolStripDropDownCloseReason CloseReason { + get { return this.close_reason; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripDropDownClosedEventHandler.cs b/source/ShiftUI/ToolStrip/ToolStripDropDownClosedEventHandler.cs new file mode 100644 index 0000000..01fea1d --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripDropDownClosedEventHandler.cs @@ -0,0 +1,32 @@ +// +// ToolStripDropDownClosedEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ToolStripDropDownClosedEventHandler (object sender, ToolStripDropDownClosedEventArgs e); +} diff --git a/source/ShiftUI/ToolStrip/ToolStripDropDownClosingEventArgs.cs b/source/ShiftUI/ToolStrip/ToolStripDropDownClosingEventArgs.cs new file mode 100644 index 0000000..8301df7 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripDropDownClosingEventArgs.cs @@ -0,0 +1,50 @@ +// +// ToolStripDropDownClosingEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.ComponentModel; + +namespace ShiftUI +{ + public class ToolStripDropDownClosingEventArgs : CancelEventArgs + { + private ToolStripDropDownCloseReason close_reason; + + #region Public Constructors + public ToolStripDropDownClosingEventArgs (ToolStripDropDownCloseReason reason) : base () + { + this.close_reason = reason; + } + #endregion // Public Constructors + + #region Public Instance Properties + public ToolStripDropDownCloseReason CloseReason { + get { return this.close_reason; } + } + #endregion // Public Instance Properties + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripDropDownClosingEventHandler.cs b/source/ShiftUI/ToolStrip/ToolStripDropDownClosingEventHandler.cs new file mode 100644 index 0000000..76ec5a8 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripDropDownClosingEventHandler.cs @@ -0,0 +1,32 @@ +// +// ToolStripDropDownClosingEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ToolStripDropDownClosingEventHandler (object sender, ToolStripDropDownClosingEventArgs e); +} diff --git a/source/ShiftUI/ToolStrip/ToolStripDropDownDirection.cs b/source/ShiftUI/ToolStrip/ToolStripDropDownDirection.cs new file mode 100644 index 0000000..2313ab4 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripDropDownDirection.cs @@ -0,0 +1,42 @@ +// +// ToolStripDropDownDirection.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum ToolStripDropDownDirection + { + AboveLeft = 0, + AboveRight = 1, + BelowLeft = 2, + BelowRight = 3, + Left = 4, + Right = 5, + Default = 7 + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripDropDownItem.cs b/source/ShiftUI/ToolStrip/ToolStripDropDownItem.cs new file mode 100644 index 0000000..b79c9aa --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripDropDownItem.cs @@ -0,0 +1,348 @@ +// +// ToolStripDropDownItem.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Drawing; +using System.ComponentModel; +using System.Threading; + +namespace ShiftUI +{ + [DefaultProperty ("DropDownItems")] + //[Designer ("ShiftUI.Design.ToolStripMenuItemDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + public abstract class ToolStripDropDownItem : ToolStripItem + { + internal ToolStripDropDown drop_down; + private ToolStripDropDownDirection drop_down_direction; + + #region Protected Constructors + protected ToolStripDropDownItem () : this (string.Empty, null, null, string.Empty) + { + } + + protected ToolStripDropDownItem (string text, Image image, EventHandler onClick) + : this (text, image, onClick, string.Empty) + { + } + + protected ToolStripDropDownItem (string text, Image image, params ToolStripItem[] dropDownItems) + : this (text, image, null, string.Empty) + { + } + + protected ToolStripDropDownItem (string text, Image image, EventHandler onClick, string name) + : base (text, image, onClick, name) + { + } + #endregion + + #region Public Properties + [TypeConverter (typeof (ReferenceConverter))] + public ToolStripDropDown DropDown { + get { + if (this.drop_down == null) { + this.drop_down = CreateDefaultDropDown (); + this.drop_down.ItemAdded += new ToolStripItemEventHandler (DropDown_ItemAdded); + } + + return this.drop_down; + } + set { + this.drop_down = value; + this.drop_down.OwnerItem = this; + } + } + + [Browsable (false)] + public ToolStripDropDownDirection DropDownDirection { + get { return this.drop_down_direction; } + set { + if (!Enum.IsDefined (typeof (ToolStripDropDownDirection), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripDropDownDirection", value)); + + this.drop_down_direction = value; + } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + public ToolStripItemCollection DropDownItems { + get { return this.DropDown.Items; } + } + + [Browsable (false)] + public virtual bool HasDropDownItems { + get { return this.drop_down != null && this.DropDown.Items.Count != 0; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override bool Pressed { + get { return base.Pressed || (this.drop_down != null && this.DropDown.Visible); } + } + #endregion + + #region Protected Properties + protected internal virtual Point DropDownLocation { + get { + Point p; + + if (this.IsOnDropDown) { + p = Parent.PointToScreen (new Point (this.Bounds.Left, this.Bounds.Top - 1)); + p.X += this.Bounds.Width; + p.Y += this.Bounds.Left; + return p; + } + else + p = new Point (this.Bounds.Left, this.Bounds.Bottom - 1); + + return Parent.PointToScreen (p); + } + } + #endregion + + #region Public Methods + public void HideDropDown () + { + if (this.drop_down == null || !this.DropDown.Visible) + return; + + // OnDropDownHide is called before actually closing DropDown + this.OnDropDownHide (EventArgs.Empty); + this.DropDown.Close (ToolStripDropDownCloseReason.CloseCalled); + this.is_pressed = false; + this.Invalidate (); + } + + public void ShowDropDown () + { + // Don't go through this whole deal if + // the DropDown is already visible + if (this.DropDown.Visible) + return; + + // Call this before the HasDropDownItems check to give + // users a chance to handle it and add drop down items + this.OnDropDownShow (EventArgs.Empty); + + if (!this.HasDropDownItems) + return; + + this.Invalidate (); + this.DropDown.Show (this.DropDownLocation); + } + #endregion + + #region Protected Methods + protected override AccessibleObject CreateAccessibilityInstance () + { + return new ToolStripDropDownItemAccessibleObject (this); + } + + protected virtual ToolStripDropDown CreateDefaultDropDown () + { + ToolStripDropDown tsdd = new ToolStripDropDown (); + tsdd.OwnerItem = this; + return tsdd; + } + + protected override void Dispose (bool disposing) + { + if (!IsDisposed) { + if(disposing) { + if (this.HasDropDownItems) + foreach (ToolStripItem tsi in this.DropDownItems) + if (tsi is ToolStripMenuItem) + ToolStripManager.RemoveToolStripMenuItem ((ToolStripMenuItem)tsi); + + if (drop_down != null) + ToolStripManager.RemoveToolStrip (drop_down); + } + base.Dispose (disposing); + } + } + + protected override void OnBoundsChanged () + { + base.OnBoundsChanged (); + } + + protected internal virtual void OnDropDownClosed (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [DropDownClosedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnDropDownHide (EventArgs e) + { + } + + protected internal virtual void OnDropDownItemClicked (ToolStripItemClickedEventArgs e) + { + ToolStripItemClickedEventHandler eh = (ToolStripItemClickedEventHandler)(Events [DropDownItemClickedEvent]); + if (eh != null) + eh (this, e); + } + + protected internal virtual void OnDropDownOpened (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [DropDownOpenedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnDropDownShow (EventArgs e) + { + EventHandler eh = (EventHandler)(Events[DropDownOpeningEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnFontChanged (EventArgs e) + { + base.OnFontChanged (e); + + // don't use DropDown directly, since doing that + // would created the DropDown Widget + if (drop_down != null) + drop_down.Font = Font; + } + + protected override void OnRightToLeftChanged (EventArgs e) + { + base.OnRightToLeftChanged (e); + } + + protected internal override bool ProcessCmdKey (ref Message m, Keys keyData) + { + if (this.HasDropDownItems) + foreach (ToolStripItem tsi in this.DropDownItems) + if (tsi.ProcessCmdKey (ref m, keyData) == true) + return true; + + return base.ProcessCmdKey (ref m, keyData); + } + + protected internal override bool ProcessDialogKey (Keys keyData) + { + if (!this.Selected || !this.HasDropDownItems) + return base.ProcessDialogKey (keyData); + + if (!this.IsOnDropDown) { + if (this.Parent.Orientation == Orientation.Horizontal) { + if (keyData == Keys.Down || keyData == Keys.Enter) { + if (this.Parent is MenuStrip) + (this.Parent as MenuStrip).MenuDroppedDown = true; + this.ShowDropDown (); + this.DropDown.SelectNextToolStripItem (null, true); + return true; + } + } else { + if (keyData == Keys.Right || keyData == Keys.Enter) { + if (this.Parent is MenuStrip) + (this.Parent as MenuStrip).MenuDroppedDown = true; + this.ShowDropDown (); + this.DropDown.SelectNextToolStripItem (null, true); + return true; + } + } + } else { + if (keyData == Keys.Right || keyData == Keys.Enter) { + if (this.HasDropDownItems) { + this.ShowDropDown (); + this.DropDown.SelectNextToolStripItem (null, true); + return true; + } + } + } + + + return base.ProcessDialogKey (keyData); + } + #endregion + + #region Public Events + static object DropDownClosedEvent = new object (); + static object DropDownItemClickedEvent = new object (); + static object DropDownOpenedEvent = new object (); + static object DropDownOpeningEvent = new object (); + + public event EventHandler DropDownClosed { + add { Events.AddHandler (DropDownClosedEvent, value); } + remove { Events.RemoveHandler (DropDownClosedEvent, value); } + } + + public event ToolStripItemClickedEventHandler DropDownItemClicked { + add { Events.AddHandler (DropDownItemClickedEvent, value); } + remove { Events.RemoveHandler (DropDownItemClickedEvent, value); } + } + + public event EventHandler DropDownOpened { + add { Events.AddHandler (DropDownOpenedEvent, value); } + remove { Events.RemoveHandler (DropDownOpenedEvent, value); } + } + + public event EventHandler DropDownOpening { + add { Events.AddHandler (DropDownOpeningEvent, value); } + remove { Events.RemoveHandler (DropDownOpeningEvent, value); } + } + #endregion + + #region Internal Methods + internal override void Dismiss (ToolStripDropDownCloseReason reason) + { + if (this.HasDropDownItems && this.DropDown.Visible) + this.DropDown.Dismiss (reason); + + base.Dismiss (reason); + } + + internal override void HandleClick (int mouse_clicks, EventArgs e) + { + OnClick (e); + } + + internal void HideDropDown (ToolStripDropDownCloseReason reason) + { + if (this.drop_down == null || !this.DropDown.Visible) + return; + + // OnDropDownHide is called before actually closing DropDown + this.OnDropDownHide (EventArgs.Empty); + this.DropDown.Close (reason); + this.is_pressed = false; + this.Invalidate (); + } + + private void DropDown_ItemAdded (object sender, ToolStripItemEventArgs e) + { + e.Item.owner_item = this; + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripDropDownItemAccessibleObject.cs b/source/ShiftUI/ToolStrip/ToolStripDropDownItemAccessibleObject.cs new file mode 100644 index 0000000..c4385b5 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripDropDownItemAccessibleObject.cs @@ -0,0 +1,66 @@ +// +// ToolStripDropDownItemAccessibleObject.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System.ComponentModel; +using ShiftUI.Design; + +namespace ShiftUI +{ + public class ToolStripDropDownItemAccessibleObject : ToolStripItem.ToolStripItemAccessibleObject + { + #region Public Constructor + public ToolStripDropDownItemAccessibleObject (ToolStripDropDownItem item) : base (item) + { + } + #endregion + + #region Public Properties + public override AccessibleRole Role { + get { return base.Role; } + } + #endregion + + #region Public Methods + public override void DoDefaultAction () + { + base.DoDefaultAction (); + } + + public override AccessibleObject GetChild (int index) + { + return (owner_item as ToolStripDropDownItem).DropDownItems[index].AccessibilityObject; + } + + public override int GetChildCount () + { + return (owner_item as ToolStripDropDownItem).DropDownItems.Count; + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripDropDownMenu.cs b/source/ShiftUI/ToolStrip/ToolStripDropDownMenu.cs new file mode 100644 index 0000000..7b5ed6f --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripDropDownMenu.cs @@ -0,0 +1,196 @@ +// +// ToolStripDropDownMenu.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System.ComponentModel; +using System.Runtime.InteropServices; +using ShiftUI.Layout; +using System; + +namespace ShiftUI +{ + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + //[Designer ("ShiftUI.Design.ToolStripDropDownDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + public class ToolStripDropDownMenu : ToolStripDropDown + { + private ToolStripLayoutStyle layout_style; + private bool show_check_margin; + private bool show_image_margin; + + #region Public Constructors + public ToolStripDropDownMenu () : base () + { + this.layout_style = ToolStripLayoutStyle.Flow; + this.show_image_margin = true; + } + #endregion + + #region Public Properties + public override Rectangle DisplayRectangle { + get { return base.DisplayRectangle; } + } + + public override LayoutEngine LayoutEngine { + get { return base.LayoutEngine; } + } + + [DefaultValue (ToolStripLayoutStyle.Flow)] + public new ToolStripLayoutStyle LayoutStyle { + get { return this.layout_style; } + set { this.layout_style = value; } + } + + [DefaultValue (false)] + public bool ShowCheckMargin { + get { return this.show_check_margin; } + set { + if (this.show_check_margin != value) { + this.show_check_margin = value; + PerformLayout (this, "ShowCheckMargin"); + } + } + } + + [DefaultValue (true)] + public bool ShowImageMargin { + get { return this.show_image_margin; } + set { + if (this.show_image_margin != value) { + this.show_image_margin = value; + PerformLayout (this, "ShowImageMargin"); + } + } + } + #endregion + + #region Protected Properties + protected override Padding DefaultPadding { + get { return base.DefaultPadding; } + } + + protected internal override Size MaxItemSize { + get { return Size; } + } + #endregion + + #region Protected Methods + protected internal override ToolStripItem CreateDefaultItem (string text, Image image, EventHandler onClick) + { + return base.CreateDefaultItem (text, image, onClick); + } + + protected override void OnFontChanged (EventArgs e) + { + base.OnFontChanged (e); + } + + protected override void OnLayout (LayoutEventArgs e) + { + // Find the widest menu item + int widest = 0; + + foreach (ToolStripItem tsi in this.Items) { + if (!tsi.Available) + continue; + + tsi.SetPlacement (ToolStripItemPlacement.Main); + + widest = Math.Max (widest, tsi.GetPreferredSize (Size.Empty).Width); + } + + int x = this.Padding.Left; + + if (show_check_margin || show_image_margin) + widest += 68 - this.Padding.Horizontal; + else + widest += 47 - this.Padding.Horizontal; + + int y = this.Padding.Top; + + foreach (ToolStripItem tsi in this.Items) { + if (!tsi.Available) + continue; + + y += tsi.Margin.Top; + + int height = 0; + + Size preferred_size = tsi.GetPreferredSize (Size.Empty); + + if (preferred_size.Height > 22) + height = preferred_size.Height; + else if (tsi is ToolStripSeparator) + height = 7; + else + height = 22; + + tsi.SetBounds (new Rectangle (x, y, widest, height)); + y += height + tsi.Margin.Bottom; + } + + this.Size = new Size (widest + this.Padding.Horizontal, y + this.Padding.Bottom);// + 2); + this.SetDisplayedItems (); + this.OnLayoutCompleted (EventArgs.Empty); + this.Invalidate (); + } + + protected override void OnPaintBackground (PaintEventArgs e) + { + Rectangle affected_bounds = new Rectangle (Point.Empty, this.Size); + + ToolStripRenderEventArgs tsrea = new ToolStripRenderEventArgs (e.Graphics, this, affected_bounds, SystemColors.Control); + tsrea.InternalConnectedArea = CalculateConnectedArea (); + + this.Renderer.DrawToolStripBackground (tsrea); + + if (this.ShowCheckMargin || this.ShowImageMargin) { + tsrea = new ToolStripRenderEventArgs (e.Graphics, this, new Rectangle (tsrea.AffectedBounds.Location, new Size (25, tsrea.AffectedBounds.Height)), SystemColors.Control); + this.Renderer.DrawImageMargin (tsrea); + } + } + + protected override void SetDisplayedItems () + { + base.SetDisplayedItems (); + } + #endregion + + #region Internal Methods + internal override Rectangle CalculateConnectedArea () + { + if (this.OwnerItem != null && !this.OwnerItem.IsOnDropDown && !(this.OwnerItem is MdiWidgetStrip.SystemMenuItem)) { + Point owner_screen_loc = OwnerItem.GetCurrentParent ().PointToScreen (OwnerItem.Location); + return new Rectangle (owner_screen_loc.X - Left, 0, this.OwnerItem.Width - 1, 2); + } + + return base.CalculateConnectedArea (); + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripGripDisplayStyle.cs b/source/ShiftUI/ToolStrip/ToolStripGripDisplayStyle.cs new file mode 100644 index 0000000..60e7fcc --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripGripDisplayStyle.cs @@ -0,0 +1,37 @@ +// +// ToolStripGripDisplayStyle.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum ToolStripGripDisplayStyle + { + Horizontal = 0, + Vertical = 1 + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripGripRenderEventArgs.cs b/source/ShiftUI/ToolStrip/ToolStripGripRenderEventArgs.cs new file mode 100644 index 0000000..54c26b9 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripGripRenderEventArgs.cs @@ -0,0 +1,70 @@ +// +// ToolStripGripRenderEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; + +namespace ShiftUI +{ + public class ToolStripGripRenderEventArgs : ToolStripRenderEventArgs + { + private Rectangle grip_bounds; + private ToolStripGripDisplayStyle grip_display_style; + private ToolStripGripStyle grip_style; + + public ToolStripGripRenderEventArgs (Graphics g, ToolStrip toolStrip) + : base (g, toolStrip) + { + this.grip_bounds = new Rectangle (2, 0, 3, 25); + this.grip_display_style = ToolStripGripDisplayStyle.Vertical; + this.grip_style = ToolStripGripStyle.Visible; + } + + // There seems to be no public way to set these properties :/ + internal ToolStripGripRenderEventArgs (Graphics g, ToolStrip toolStrip, Rectangle gripBounds, ToolStripGripDisplayStyle displayStyle, ToolStripGripStyle gripStyle) + : base (g, toolStrip) + { + this.grip_bounds = gripBounds; + this.grip_display_style = displayStyle; + this.grip_style = gripStyle; + } + + #region Public Properties + public Rectangle GripBounds { + get { return this.grip_bounds; } + } + + public ToolStripGripDisplayStyle GripDisplayStyle { + get { return this.grip_display_style; } + } + + public ToolStripGripStyle GripStyle { + get { return this.grip_style; } + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripGripRenderEventHandler.cs b/source/ShiftUI/ToolStrip/ToolStripGripRenderEventHandler.cs new file mode 100644 index 0000000..5b89c15 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripGripRenderEventHandler.cs @@ -0,0 +1,32 @@ +// +// ToolStripGripRenderEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ToolStripGripRenderEventHandler (object sender, ToolStripGripRenderEventArgs e); +} diff --git a/source/ShiftUI/ToolStrip/ToolStripGripStyle.cs b/source/ShiftUI/ToolStrip/ToolStripGripStyle.cs new file mode 100644 index 0000000..87354da --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripGripStyle.cs @@ -0,0 +1,37 @@ +// +// ToolStripGripStyle.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum ToolStripGripStyle + { + Hidden = 0, + Visible = 1 + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItem.cs b/source/ShiftUI/ToolStrip/ToolStripItem.cs new file mode 100644 index 0000000..0a8ad4a --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItem.cs @@ -0,0 +1,2077 @@ +// +// ToolStripItem.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +using System; +using System.Drawing; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [DefaultEvent ("Click")] + [DefaultProperty ("Text")] + [DesignTimeVisible (false)] + [ToolboxItem (false)] + //[Designer ("ShiftUI.Design.ToolStripItemDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + public abstract class ToolStripItem : Component, IDropTarget, IComponent, IDisposable + { + #region Private Variables + private AccessibleObject accessibility_object; + private string accessible_default_action_description; + private bool allow_drop; + private ToolStripItemAlignment alignment; + private AnchorStyles anchor; + private bool available; + private bool auto_size; + private bool auto_tool_tip; + private Color back_color; + private Image background_image; + private ImageLayout background_image_layout; + private Rectangle bounds; + private bool can_select; + private ToolStripItemDisplayStyle display_style; + private DockStyle dock; + private bool double_click_enabled; + private bool enabled; + private Size explicit_size; + private Font font; + private Color fore_color; + private Image image; + private ContentAlignment image_align; + private int image_index; + private string image_key; + private ToolStripItemImageScaling image_scaling; + private Color image_transparent_color; + private bool is_disposed; + internal bool is_pressed; + private bool is_selected; + private Padding margin; + private MergeAction merge_action; + private int merge_index; + private string name; + private ToolStripItemOverflow overflow; + private ToolStrip owner; + internal ToolStripItem owner_item; + private Padding padding; + private ToolStripItemPlacement placement; + private RightToLeft right_to_left; + private bool right_to_left_auto_mirror_image; + private Object tag; + private string text; + private ContentAlignment text_align; + private ToolStripTextDirection text_direction; + private TextImageRelation text_image_relation; + private string tool_tip_text; + private bool visible; + + private EventHandler frame_handler; // For animating images + private ToolStrip parent; + private Size text_size; + #endregion + + #region Public Constructors + protected ToolStripItem () + : this (String.Empty, null, null, String.Empty) + { + } + + protected ToolStripItem (string text, Image image, EventHandler onClick) + : this (text, image, onClick, String.Empty) + { + } + + protected ToolStripItem (string text, Image image, EventHandler onClick, string name) + { + this.alignment = ToolStripItemAlignment.Left; + this.anchor = AnchorStyles.Left | AnchorStyles.Top; + this.auto_size = true; + this.auto_tool_tip = this.DefaultAutoToolTip; + this.available = true; + this.back_color = Color.Empty; + this.background_image_layout = ImageLayout.Tile; + this.can_select = true; + this.display_style = this.DefaultDisplayStyle; + this.dock = DockStyle.None; + this.enabled = true; + this.fore_color = Color.Empty; + this.image = image; + this.image_align = ContentAlignment.MiddleCenter; + this.image_index = -1; + this.image_key = string.Empty; + this.image_scaling = ToolStripItemImageScaling.SizeToFit; + this.image_transparent_color = Color.Empty; + this.margin = this.DefaultMargin; + this.merge_action = MergeAction.Append; + this.merge_index = -1; + this.name = name; + this.overflow = ToolStripItemOverflow.AsNeeded; + this.padding = this.DefaultPadding; + this.placement = ToolStripItemPlacement.None; + this.right_to_left = RightToLeft.Inherit; + this.bounds.Size = this.DefaultSize; + this.text = text; + this.text_align = ContentAlignment.MiddleCenter; + this.text_direction = DefaultTextDirection; + this.text_image_relation = TextImageRelation.ImageBeforeText; + this.visible = true; + + this.Click += onClick; + OnLayout (new LayoutEventArgs (null, string.Empty)); + } + #endregion + + #region Public Properties + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public AccessibleObject AccessibilityObject { + get { + if (this.accessibility_object == null) + this.accessibility_object = CreateAccessibilityInstance (); + + return this.accessibility_object; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public string AccessibleDefaultActionDescription { + get { + if (this.accessibility_object == null) + return null; + + return this.accessible_default_action_description; + } + set { this.accessible_default_action_description = value; } + } + + [Localizable (true)] + [DefaultValue (null)] + public string AccessibleDescription { + get { + if (this.accessibility_object == null) + return null; + + return this.AccessibilityObject.Description; + } + set { this.AccessibilityObject.description = value; } + } + + [Localizable (true)] + [DefaultValue (null)] + public string AccessibleName { + get { + if (this.accessibility_object == null) + return null; + + return this.AccessibilityObject.Name; + } + set { this.AccessibilityObject.Name = value; } + } + + [DefaultValue (AccessibleRole.Default)] + public AccessibleRole AccessibleRole { + get + { + if (this.accessibility_object == null) + return AccessibleRole.Default; + + return this.AccessibilityObject.Role; + } + set { this.AccessibilityObject.role = value; } + } + + [DefaultValue (ToolStripItemAlignment.Left)] + public ToolStripItemAlignment Alignment { + get { return this.alignment; } + set { + if (!Enum.IsDefined (typeof (ToolStripItemAlignment), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripItemAlignment", value)); + + if (this.alignment != value) { + this.alignment = value; + this.CalculateAutoSize (); + } + } + } + + [MonoTODO ("Stub, does nothing")] + [Browsable (false)] + [DefaultValue (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public virtual bool AllowDrop { + get { return this.allow_drop; } + set { this.allow_drop = value; } + } + + [Browsable (false)] + [DefaultValue (AnchorStyles.Top | AnchorStyles.Left)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public AnchorStyles Anchor { + get { return this.anchor; } + set { this.anchor = value; } + } + + [Localizable (true)] + [DefaultValue (true)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)] + [RefreshProperties (RefreshProperties.All)] + public bool AutoSize { + get { return this.auto_size; } + set { + this.auto_size = value; + this.CalculateAutoSize (); + } + } + + [DefaultValue (false)] + public bool AutoToolTip { + get { return this.auto_tool_tip; } + set { this.auto_tool_tip = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public bool Available { + get { return this.available; } + set { + if (this.available != value) { + available = value; + visible = value; + + if (this.parent != null) + parent.PerformLayout (); + + OnAvailableChanged (EventArgs.Empty); + OnVisibleChanged (EventArgs.Empty); + } + } + } + + public virtual Color BackColor { + get { + if (back_color != Color.Empty) + return back_color; + + if (Parent != null) + return parent.BackColor; + + return Widget.DefaultBackColor; + } + set { + if (this.back_color != value) { + back_color = value; + OnBackColorChanged (EventArgs.Empty); + this.Invalidate (); + } + } + } + + [Localizable (true)] + [DefaultValue (null)] + public virtual Image BackgroundImage { + get { return this.background_image; } + set { + if (this.background_image != value) { + this.background_image = value; + this.Invalidate (); + } + } + } + + [Localizable (true)] + [DefaultValue (ImageLayout.Tile)] + public virtual ImageLayout BackgroundImageLayout { + get { return this.background_image_layout; } + set { + if (this.background_image_layout != value) { + this.background_image_layout = value; + this.Invalidate (); + } + } + } + + [Browsable (false)] + public virtual Rectangle Bounds { + get { return this.bounds; } + } + + [Browsable (false)] + public virtual bool CanSelect { + get { return this.can_select; } + } + + [Browsable (false)] + public Rectangle ContentRectangle { + get { + // ToolStripLabels don't have a border + if (this is ToolStripLabel || this is ToolStripStatusLabel) + return new Rectangle (0, 0, this.bounds.Width, this.bounds.Height); + + if (this is ToolStripDropDownButton && (this as ToolStripDropDownButton).ShowDropDownArrow) + return new Rectangle (2, 2, this.bounds.Width - 13, this.bounds.Height - 4); + + return new Rectangle (2, 2, this.bounds.Width - 4, this.bounds.Height - 4); + } + } + + public virtual ToolStripItemDisplayStyle DisplayStyle { + get { return this.display_style; } + set { + if (this.display_style != value) { + this.display_style = value; + this.CalculateAutoSize (); + OnDisplayStyleChanged (EventArgs.Empty); + } + } + } + + [Browsable (false)] + public bool IsDisposed { + get { return this.is_disposed; } + } + + [Browsable (false)] + [DefaultValue (DockStyle.None)] + public DockStyle Dock { + get { return this.dock; } + set { + if (this.dock != value) { + if (!Enum.IsDefined (typeof (DockStyle), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for DockStyle", value)); + + this.dock = value; + this.CalculateAutoSize (); + } + } + } + + [DefaultValue (false)] + public bool DoubleClickEnabled { + get { return this.double_click_enabled; } + set { this.double_click_enabled = value; } + } + + [Localizable (true)] + [DefaultValue (true)] + public virtual bool Enabled { + get { + if (Parent != null) + if (!Parent.Enabled) + return false; + + if (Owner != null) + if (!Owner.Enabled) + return false; + + return enabled; + } + set { + if (this.enabled != value) { + this.enabled = value; + OnEnabledChanged (EventArgs.Empty); + this.Invalidate (); + } + } + } + + [Localizable (true)] + public virtual Font Font { + get { + if (font != null) + return font; + + if (Parent != null) + return Parent.Font; + + return DefaultFont; + } + set { + if (this.font != value) { + this.font = value; + this.CalculateAutoSize (); + this.OnFontChanged (EventArgs.Empty); + this.Invalidate (); + } + } + } + + public virtual Color ForeColor { + get { + if (fore_color != Color.Empty) + return fore_color; + + if (Parent != null) + return parent.ForeColor; + + return Widget.DefaultForeColor; + } + set { + if (this.fore_color != value) { + this.fore_color = value; + this.OnForeColorChanged (EventArgs.Empty); + this.Invalidate (); + } + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public int Height { + get { return this.Size.Height; } + set { + this.Size = new Size (this.Size.Width, value); + this.explicit_size.Height = value; + + if (this.Visible) { + this.CalculateAutoSize (); + this.OnBoundsChanged (); + this.Invalidate (); + } + } + } + + [Localizable (true)] + public virtual Image Image { + get { + if (this.image != null) + return this.image; + + if (this.image_index >= 0) + if (this.owner != null && this.owner.ImageList != null && this.owner.ImageList.Images.Count > this.image_index) + return this.owner.ImageList.Images[this.image_index]; + + + if (!string.IsNullOrEmpty (this.image_key)) + if (this.owner != null && this.owner.ImageList != null && this.owner.ImageList.Images.Count > this.image_index) + return this.owner.ImageList.Images[this.image_key]; + + return null; + } + set { + if (this.image != value) { + StopAnimation (); + + this.image = value; + this.image_index = -1; + this.image_key = string.Empty; + this.CalculateAutoSize (); + this.Invalidate (); + + BeginAnimation (); + } + } + } + + [Localizable (true)] + [DefaultValue (ContentAlignment.MiddleCenter)] + public ContentAlignment ImageAlign { + get { return this.image_align; } + set { + if (!Enum.IsDefined (typeof (ContentAlignment), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ContentAlignment", value)); + + if (image_align != value) { + this.image_align = value; + this.CalculateAutoSize (); + } + } + } + + [Localizable (true)] + [Browsable (false)] + [RelatedImageList ("Owner.ImageList")] + [TypeConverter (typeof (NoneExcludedImageIndexConverter))] + [RefreshProperties (RefreshProperties.Repaint)] + //[Editor ("ShiftUI.Design.ToolStripImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + public int ImageIndex { + get { return this.image_index; } + set { + if (this.image_index != value) { + // Lamespec: MSDN says ArgumentException, tests say otherwise + if (value < -1) + throw new ArgumentOutOfRangeException ("ImageIndex cannot be less than -1"); + + this.image_index = value; + this.image = null; + this.image_key = string.Empty; + this.CalculateAutoSize (); + this.Invalidate (); + } + } + } + + [Localizable (true)] + [Browsable (false)] + [RelatedImageList ("Owner.ImageList")] + [TypeConverter (typeof (ImageKeyConverter))] + [RefreshProperties (RefreshProperties.Repaint)] + //[Editor ("ShiftUI.Design.ToolStripImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + public string ImageKey { + get { return this.image_key; } + set { + if (this.image_key != value) { + this.image = null; + this.image_index = -1; + this.image_key = value; + this.CalculateAutoSize (); + this.Invalidate (); + } + } + } + + [Localizable (true)] + [DefaultValue (ToolStripItemImageScaling.SizeToFit)] + public ToolStripItemImageScaling ImageScaling { + get { return this.image_scaling; } + set { + if (image_scaling != value) { + this.image_scaling = value; + this.CalculateAutoSize (); + } + } + } + + [Localizable (true)] + public Color ImageTransparentColor { + get { return this.image_transparent_color; } + set { this.image_transparent_color = value; } + } + + [Browsable (false)] + public bool IsOnDropDown { + get { + if (this.parent != null && this.parent is ToolStripDropDown) + return true; + + return false; + } + } + + [Browsable (false)] + public bool IsOnOverflow { + get { return this.placement == ToolStripItemPlacement.Overflow; } + } + + public Padding Margin { + get { return this.margin; } + set { + this.margin = value; + this.CalculateAutoSize (); + } + } + + [DefaultValue (MergeAction.Append)] + public MergeAction MergeAction { + get { return this.merge_action; } + set { + if (!Enum.IsDefined (typeof (MergeAction), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for MergeAction", value)); + + this.merge_action = value; + } + } + + [DefaultValue (-1)] + public int MergeIndex { + get { return this.merge_index; } + set { this.merge_index = value; } + } + + [DefaultValue (null)] + [Browsable (false)] + public string Name { + get { return this.name; } + set { this.name = value; } + } + + [DefaultValue (ToolStripItemOverflow.AsNeeded)] + public ToolStripItemOverflow Overflow { + get { return this.overflow; } + set { + if (this.overflow != value) { + if (!Enum.IsDefined (typeof (ToolStripItemOverflow), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripItemOverflow", value)); + + this.overflow = value; + + if (owner != null) + owner.PerformLayout (); + } + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public ToolStrip Owner { + get { return this.owner; } + set { + if (this.owner != value) { + if (this.owner != null) + this.owner.Items.Remove (this); + + if (value != null) + value.Items.Add (this); + else + this.owner = null; + } + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public ToolStripItem OwnerItem { + get { return this.owner_item; } + } + + public virtual Padding Padding { + get { return this.padding; } + set { + this.padding = value; + this.CalculateAutoSize (); + this.Invalidate (); + } + } + + [Browsable (false)] + public ToolStripItemPlacement Placement { + get { return this.placement; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public virtual bool Pressed { get { return this.is_pressed; } } + + [MonoTODO ("RTL not implemented")] + [Localizable (true)] + public virtual RightToLeft RightToLeft { + get { return this.right_to_left; } + set { + if (this.right_to_left != value) { + this.right_to_left = value; + this.OnRightToLeftChanged (EventArgs.Empty); + } + } + } + + [Localizable (true)] + [DefaultValue (false)] + public bool RightToLeftAutoMirrorImage { + get { return this.right_to_left_auto_mirror_image; } + set { + if (this.right_to_left_auto_mirror_image != value) { + this.right_to_left_auto_mirror_image = value; + this.Invalidate (); + } + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public virtual bool Selected { get { return this.is_selected; } } + + [Localizable (true)] + public virtual Size Size { + get { + if (!this.AutoSize && this.explicit_size != Size.Empty) + return this.explicit_size; + + return this.bounds.Size; + } + set { + this.bounds.Size = value; + this.explicit_size = value; + + if (this.Visible) { + this.CalculateAutoSize (); + this.OnBoundsChanged (); + } + } + } + + [Localizable (false)] + [Bindable (true)] + [DefaultValue (null)] + [TypeConverter (typeof (StringConverter))] + public Object Tag { + get { return this.tag; } + set { this.tag = value; } + } + + [Localizable (true)] + [DefaultValue ("")] + public virtual string Text + { + get { return this.text; } + set { + if (this.text != value) { + this.text = value; + this.Invalidate (); + this.CalculateAutoSize (); + this.Invalidate (); + this.OnTextChanged (EventArgs.Empty); + } + } + } + + [Localizable (true)] + [DefaultValue (ContentAlignment.MiddleCenter)] + public virtual ContentAlignment TextAlign { + get { return this.text_align; } + set { + if (!Enum.IsDefined (typeof (ContentAlignment), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ContentAlignment", value)); + + if (this.text_align != value) { + this.text_align = value; + this.CalculateAutoSize (); + } + } + } + + public virtual ToolStripTextDirection TextDirection { + get { + if (this.text_direction == ToolStripTextDirection.Inherit) { + if (this.Parent != null) + return this.Parent.TextDirection; + else + return ToolStripTextDirection.Horizontal; + } + + return this.text_direction; + } + set { + if (!Enum.IsDefined (typeof (ToolStripTextDirection), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripTextDirection", value)); + + if (this.text_direction != value) { + this.text_direction = value; + this.CalculateAutoSize (); + this.Invalidate (); + } + } + } + + [Localizable (true)] + [DefaultValue (TextImageRelation.ImageBeforeText)] + public TextImageRelation TextImageRelation { + get { return this.text_image_relation; } + set { + this.text_image_relation = value; + this.CalculateAutoSize (); + this.Invalidate (); + } + } + + [Localizable (true)] + //[Editor ("System.ComponentModel.Design.MultilineStringEditor, " + Consts.AssemblySystem_Design, + // //"System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)] + public string ToolTipText { + get { return this.tool_tip_text; } + set { this.tool_tip_text = value; } + } + + [Localizable (true)] + public bool Visible { + get { + if (this.parent == null) + return false; + + return this.visible && this.parent.Visible; + } + set { + if (this.visible != value) { + this.available = value; + this.SetVisibleCore (value); + if (this.Owner != null) + this.Owner.PerformLayout (); + } + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Always)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public int Width { + get { return this.Size.Width; } + set { + this.Size = new Size (value, this.Size.Height); + this.explicit_size.Width = value; + + if (this.Visible) { + this.CalculateAutoSize (); + this.OnBoundsChanged (); + this.Invalidate (); + } + } + } + #endregion + + #region Protected Properties + protected virtual bool DefaultAutoToolTip { get { return false; } } + protected virtual ToolStripItemDisplayStyle DefaultDisplayStyle { get { return ToolStripItemDisplayStyle.ImageAndText; } } + protected internal virtual Padding DefaultMargin { get { return new Padding (0, 1, 0, 2); } } + protected virtual Padding DefaultPadding { get { return new Padding (); } } + protected virtual Size DefaultSize { get { return new Size (23, 23); } } + protected internal virtual bool DismissWhenClicked { get { return true; } } + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + protected internal ToolStrip Parent { + get { return this.parent; } + set { + if (this.parent != value) { + ToolStrip old_parent = this.parent; + this.parent = value; + OnParentChanged(old_parent, this.parent); + } + } + } + protected internal virtual bool ShowKeyboardCues { get { return false; } } + #endregion + + #region Public Methods + [MonoTODO ("Stub, does nothing")] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public DragDropEffects DoDragDrop (Object data, DragDropEffects allowedEffects) + { + return allowedEffects; + } + + public ToolStrip GetCurrentParent () + { + return this.parent; + } + + public virtual Size GetPreferredSize (Size constrainingSize) + { + return this.CalculatePreferredSize (constrainingSize); + } + + public void Invalidate () + { + if (parent != null) + parent.Invalidate (this.bounds); + } + + public void Invalidate (Rectangle r) + { + if (parent != null) + parent.Invalidate (r); + } + + public void PerformClick () + { + this.OnClick (EventArgs.Empty); + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public virtual void ResetBackColor () { this.BackColor = Color.Empty; } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public virtual void ResetDisplayStyle () { this.display_style = this.DefaultDisplayStyle; } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public virtual void ResetFont () { this.font = null; } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public virtual void ResetForeColor () { this.ForeColor = Color.Empty; } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public virtual void ResetImage () { this.image = null; } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public void ResetMargin () { this.margin = this.DefaultMargin; } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public void ResetPadding () { this.padding = this.DefaultPadding; } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public virtual void ResetRightToLeft () { this.right_to_left = RightToLeft.Inherit; } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public virtual void ResetTextDirection () { this.TextDirection = this.DefaultTextDirection; } + + public void Select () + { + if (!this.is_selected && this.CanSelect) { + this.is_selected = true; + + if (this.Parent != null) { + if (this.Visible && this.Parent.Focused && this is ToolStripWidgetHost) + (this as ToolStripWidgetHost).Focus (); + + this.Invalidate (); + this.Parent.NotifySelectedChanged (this); + } + OnUIASelectionChanged (); + } + } + + public override string ToString () + { + return this.text; + } + #endregion + + #region Protected Methods + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual AccessibleObject CreateAccessibilityInstance () + { + return new ToolStripItemAccessibleObject (this); + } + + protected override void Dispose (bool disposing) + { + if (!is_disposed && disposing) + is_disposed = true; + + if (image != null) { + StopAnimation (); + image = null; + } + + if (owner != null && disposing) + owner.Items.Remove (this); + + base.Dispose (disposing); + } + + protected internal virtual bool IsInputChar (char charCode) + { + return false; + } + + protected internal virtual bool IsInputKey (Keys keyData) + { + return false; + } + + protected virtual void OnAvailableChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [AvailableChangedEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnBackColorChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [BackColorChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnBoundsChanged () + { + OnLayout (new LayoutEventArgs(null, string.Empty)); + } + + protected virtual void OnClick (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [ClickEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnDisplayStyleChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [DisplayStyleChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnDoubleClick (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [DoubleClickEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnDragDrop (DragEventArgs dragEvent) + { + DragEventHandler eh = (DragEventHandler)(Events[DragDropEvent]); + if (eh != null) + eh (this, dragEvent); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnDragEnter (DragEventArgs dragEvent) + { + DragEventHandler eh = (DragEventHandler)(Events[DragEnterEvent]); + if (eh != null) + eh (this, dragEvent); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnDragLeave (EventArgs e) + { + EventHandler eh = (EventHandler)(Events[DragLeaveEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnDragOver (DragEventArgs dragEvent) + { + DragEventHandler eh = (DragEventHandler)(Events[DragOverEvent]); + if (eh != null) + eh (this, dragEvent); + } + + protected virtual void OnEnabledChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [EnabledChangedEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnFontChanged (EventArgs e) + { + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnForeColorChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [ForeColorChangedEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnGiveFeedback (GiveFeedbackEventArgs giveFeedbackEvent) + { + GiveFeedbackEventHandler eh = (GiveFeedbackEventHandler)(Events[GiveFeedbackEvent]); + if (eh != null) + eh (this, giveFeedbackEvent); + } + + protected virtual void OnLayout (LayoutEventArgs e) + { + } + + protected virtual void OnLocationChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [LocationChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnMouseDown (MouseEventArgs e) + { + if (this.Enabled) { + this.is_pressed = true; + this.Invalidate (); + + MouseEventHandler eh = (MouseEventHandler)(Events [MouseDownEvent]); + if (eh != null) + eh (this, e); + } + } + + protected virtual void OnMouseEnter (EventArgs e) + { + this.Select (); + + EventHandler eh = (EventHandler)(Events [MouseEnterEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnMouseHover (EventArgs e) + { + if (this.Enabled) { + EventHandler eh = (EventHandler)(Events [MouseHoverEvent]); + if (eh != null) + eh (this, e); + } + } + + protected virtual void OnMouseLeave (EventArgs e) + { + if (this.CanSelect) { + this.is_selected = false; + this.is_pressed = false; + this.Invalidate (); + OnUIASelectionChanged (); + } + + EventHandler eh = (EventHandler)(Events [MouseLeaveEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnMouseMove (MouseEventArgs mea) + { + if (this.Enabled) { + MouseEventHandler eh = (MouseEventHandler)(Events [MouseMoveEvent]); + if (eh != null) + eh (this, mea); + } + } + + protected virtual void OnMouseUp (MouseEventArgs e) + { + if (this.Enabled) { + this.is_pressed = false; + this.Invalidate (); + + if (this.IsOnDropDown) + if (!(this is ToolStripDropDownItem) || !(this as ToolStripDropDownItem).HasDropDownItems || (this as ToolStripDropDownItem).DropDown.Visible == false) { + if ((this.Parent as ToolStripDropDown).OwnerItem != null) + ((this.Parent as ToolStripDropDown).OwnerItem as ToolStripDropDownItem).HideDropDown (); + else + (this.Parent as ToolStripDropDown).Hide (); + } + + + MouseEventHandler eh = (MouseEventHandler)(Events [MouseUpEvent]); + if (eh != null) + eh (this, e); + } + } + + protected virtual void OnOwnerChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [OwnerChangedEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected internal virtual void OnOwnerFontChanged (EventArgs e) + { + this.CalculateAutoSize (); + OnFontChanged (EventArgs.Empty); + } + + void OnPaintInternal (PaintEventArgs e) + { + // Have the background rendered independently from OnPaint + if (this.parent != null) + this.parent.Renderer.DrawItemBackground (new ToolStripItemRenderEventArgs (e.Graphics, this)); + + OnPaint (e); + } + + protected virtual void OnPaint (PaintEventArgs e) + { + PaintEventHandler eh = (PaintEventHandler)(Events [PaintEvent]); + if (eh != null) + eh (this, e); + } + + // This is never called. + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnParentBackColorChanged (EventArgs e) + { + } + + protected virtual void OnParentChanged (ToolStrip oldParent, ToolStrip newParent) + { + this.text_size = + TextRenderer.MeasureText (this.Text == null ? string.Empty : this.text, this.Font, Size.Empty, TextFormatFlags.HidePrefix); + + if (oldParent != null) + oldParent.PerformLayout (); + + if (newParent != null) + newParent.PerformLayout (); + } + + protected internal virtual void OnParentEnabledChanged (EventArgs e) + { + this.OnEnabledChanged (e); + } + + // This is never called. + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnParentForeColorChanged (EventArgs e) + { + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected internal virtual void OnParentRightToLeftChanged (EventArgs e) + { + this.OnRightToLeftChanged (e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnQueryContinueDrag (QueryContinueDragEventArgs queryContinueDragEvent) + { + QueryContinueDragEventHandler eh = (QueryContinueDragEventHandler)(Events[QueryContinueDragEvent]); + if (eh != null) + eh (this, queryContinueDragEvent); + } + + protected virtual void OnRightToLeftChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events[RightToLeftChangedEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnTextChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [TextChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnVisibleChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [VisibleChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected internal virtual bool ProcessCmdKey (ref Message m, Keys keyData) + { + return false; + } + + protected internal virtual bool ProcessDialogKey (Keys keyData) + { + if (this.Selected && keyData == Keys.Enter) { + this.FireEvent (EventArgs.Empty, ToolStripItemEventType.Click); + return true; + } + + return false; + } + + // ProcessMnemonic will only be called if we are supposed to handle + // it. None of that fancy "thinking" needed! + protected internal virtual bool ProcessMnemonic (char charCode) + { + ToolStripManager.SetActiveToolStrip (this.Parent, true); + this.PerformClick (); + return true; + } + + protected internal virtual void SetBounds (Rectangle bounds) + { + if (this.bounds != bounds) { + this.bounds = bounds; + OnBoundsChanged (); + } + } + + protected virtual void SetVisibleCore (bool visible) + { + this.visible = visible; + this.OnVisibleChanged (EventArgs.Empty); + + if (this.visible) + BeginAnimation (); + else + StopAnimation (); + this.Invalidate (); + } + #endregion + + #region Public Events + static object AvailableChangedEvent = new object (); + static object BackColorChangedEvent = new object (); + static object ClickEvent = new object (); + static object DisplayStyleChangedEvent = new object (); + static object DoubleClickEvent = new object (); + static object DragDropEvent = new object (); + static object DragEnterEvent = new object (); + static object DragLeaveEvent = new object (); + static object DragOverEvent = new object (); + static object EnabledChangedEvent = new object (); + static object ForeColorChangedEvent = new object (); + static object GiveFeedbackEvent = new object (); + static object LocationChangedEvent = new object (); + static object MouseDownEvent = new object (); + static object MouseEnterEvent = new object (); + static object MouseHoverEvent = new object (); + static object MouseLeaveEvent = new object (); + static object MouseMoveEvent = new object (); + static object MouseUpEvent = new object (); + static object OwnerChangedEvent = new object (); + static object PaintEvent = new object (); + static object QueryAccessibilityHelpEvent = new object (); + static object QueryContinueDragEvent = new object (); + static object RightToLeftChangedEvent = new object (); + static object TextChangedEvent = new object (); + static object VisibleChangedEvent = new object (); + + [Browsable (false)] + public event EventHandler AvailableChanged { + add { Events.AddHandler (AvailableChangedEvent, value); } + remove {Events.RemoveHandler (AvailableChangedEvent, value); } + } + + public event EventHandler BackColorChanged { + add { Events.AddHandler (BackColorChangedEvent, value); } + remove {Events.RemoveHandler (BackColorChangedEvent, value); } + } + + public event EventHandler Click { + add { Events.AddHandler (ClickEvent, value); } + remove {Events.RemoveHandler (ClickEvent, value); } + } + + public event EventHandler DisplayStyleChanged { + add { Events.AddHandler (DisplayStyleChangedEvent, value); } + remove {Events.RemoveHandler (DisplayStyleChangedEvent, value); } + } + + public event EventHandler DoubleClick { + add { Events.AddHandler (DoubleClickEvent, value); } + remove {Events.RemoveHandler (DoubleClickEvent, value); } + } + + [MonoTODO ("Event never raised")] + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public event DragEventHandler DragDrop { + add { Events.AddHandler (DragDropEvent, value); } + remove { Events.RemoveHandler (DragDropEvent, value); } + } + + [MonoTODO ("Event never raised")] + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public event DragEventHandler DragEnter { + add { Events.AddHandler (DragEnterEvent, value); } + remove { Events.RemoveHandler (DragEnterEvent, value); } + } + + [MonoTODO ("Event never raised")] + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public event EventHandler DragLeave { + add { Events.AddHandler (DragLeaveEvent, value); } + remove { Events.RemoveHandler (DragLeaveEvent, value); } + } + + [MonoTODO ("Event never raised")] + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public event DragEventHandler DragOver { + add { Events.AddHandler (DragOverEvent, value); } + remove { Events.RemoveHandler (DragOverEvent, value); } + } + + public event EventHandler EnabledChanged { + add { Events.AddHandler (EnabledChangedEvent, value); } + remove {Events.RemoveHandler (EnabledChangedEvent, value); } + } + + public event EventHandler ForeColorChanged { + add { Events.AddHandler (ForeColorChangedEvent, value); } + remove {Events.RemoveHandler (ForeColorChangedEvent, value); } + } + + [MonoTODO ("Event never raised")] + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public event GiveFeedbackEventHandler GiveFeedback { + add { Events.AddHandler (GiveFeedbackEvent, value); } + remove { Events.RemoveHandler (GiveFeedbackEvent, value); } + } + + public event EventHandler LocationChanged { + add { Events.AddHandler (LocationChangedEvent, value); } + remove {Events.RemoveHandler (LocationChangedEvent, value); } + } + + public event MouseEventHandler MouseDown { + add { Events.AddHandler (MouseDownEvent, value); } + remove {Events.RemoveHandler (MouseDownEvent, value); } + } + + public event EventHandler MouseEnter { + add { Events.AddHandler (MouseEnterEvent, value); } + remove {Events.RemoveHandler (MouseEnterEvent, value); } + } + + public event EventHandler MouseHover { + add { Events.AddHandler (MouseHoverEvent, value); } + remove {Events.RemoveHandler (MouseHoverEvent, value); } + } + + public event EventHandler MouseLeave { + add { Events.AddHandler (MouseLeaveEvent, value); } + remove {Events.RemoveHandler (MouseLeaveEvent, value); } + } + + public event MouseEventHandler MouseMove { + add { Events.AddHandler (MouseMoveEvent, value); } + remove {Events.RemoveHandler (MouseMoveEvent, value); } + } + + public event MouseEventHandler MouseUp { + add { Events.AddHandler (MouseUpEvent, value); } + remove {Events.RemoveHandler (MouseUpEvent, value); } + } + + public event EventHandler OwnerChanged { + add { Events.AddHandler (OwnerChangedEvent, value); } + remove {Events.RemoveHandler (OwnerChangedEvent, value); } + } + + public event PaintEventHandler Paint { + add { Events.AddHandler (PaintEvent, value); } + remove {Events.RemoveHandler (PaintEvent, value); } + } + + [MonoTODO ("Event never raised")] + public event QueryAccessibilityHelpEventHandler QueryAccessibilityHelp { + add { Events.AddHandler (QueryAccessibilityHelpEvent, value); } + remove { Events.RemoveHandler (QueryAccessibilityHelpEvent, value); } + } + + [MonoTODO ("Event never raised")] + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public event QueryContinueDragEventHandler QueryContinueDrag { + add { Events.AddHandler (QueryContinueDragEvent, value); } + remove { Events.RemoveHandler (QueryContinueDragEvent, value); } + } + + public event EventHandler RightToLeftChanged { + add { Events.AddHandler (RightToLeftChangedEvent, value); } + remove { Events.RemoveHandler (RightToLeftChangedEvent, value); } + } + + public event EventHandler TextChanged { + add { Events.AddHandler (TextChangedEvent, value); } + remove {Events.RemoveHandler (TextChangedEvent, value); } + } + + public event EventHandler VisibleChanged { + add { Events.AddHandler (VisibleChangedEvent, value); } + remove {Events.RemoveHandler (VisibleChangedEvent, value); } + } + #endregion + + #region Internal Methods + internal Rectangle AlignInRectangle (Rectangle outer, Size inner, ContentAlignment align) + { + int x = 0; + int y = 0; + + if (align == ContentAlignment.BottomLeft || align == ContentAlignment.MiddleLeft || align == ContentAlignment.TopLeft) + x = outer.X; + else if (align == ContentAlignment.BottomCenter || align == ContentAlignment.MiddleCenter || align == ContentAlignment.TopCenter) + x = Math.Max (outer.X + ((outer.Width - inner.Width) / 2), outer.Left); + else if (align == ContentAlignment.BottomRight || align == ContentAlignment.MiddleRight || align == ContentAlignment.TopRight) + x = outer.Right - inner.Width; + if (align == ContentAlignment.TopCenter || align == ContentAlignment.TopLeft || align == ContentAlignment.TopRight) + y = outer.Y; + else if (align == ContentAlignment.MiddleCenter || align == ContentAlignment.MiddleLeft || align == ContentAlignment.MiddleRight) + y = outer.Y + (outer.Height - inner.Height) / 2; + else if (align == ContentAlignment.BottomCenter || align == ContentAlignment.BottomRight || align == ContentAlignment.BottomLeft) + y = outer.Bottom - inner.Height; + + return new Rectangle (x, y, Math.Min (inner.Width, outer.Width), Math.Min (inner.Height, outer.Height)); + } + + internal void CalculateAutoSize () + { + this.text_size = TextRenderer.MeasureText (this.Text == null ? string.Empty: this.text, this.Font, Size.Empty, TextFormatFlags.HidePrefix); + + // If our text is rotated, flip the width and height + ToolStripTextDirection direction = this.TextDirection; + + if (direction == ToolStripTextDirection.Vertical270 || direction == ToolStripTextDirection.Vertical90) + this.text_size = new Size (this.text_size.Height, this.text_size.Width); + + if (!this.auto_size || this is ToolStripWidgetHost) + return; + //this.text_size.Width += 6; + + Size final_size = this.CalculatePreferredSize (Size.Empty); + + if (final_size != this.Size) { + this.bounds.Width = final_size.Width; + if (this.parent != null) + this.parent.PerformLayout (); + } + } + + internal virtual Size CalculatePreferredSize (Size constrainingSize) + { + if (!this.auto_size) + return this.explicit_size; + + Size preferred_size = this.DefaultSize; + + switch (this.display_style) { + case ToolStripItemDisplayStyle.Text: + int width = text_size.Width + this.padding.Horizontal; + int height = text_size.Height + this.padding.Vertical; + preferred_size = new Size (width, height); + break; + case ToolStripItemDisplayStyle.Image: + if (this.GetImageSize () == Size.Empty) + preferred_size = this.DefaultSize; + else { + switch (this.image_scaling) { + case ToolStripItemImageScaling.None: + preferred_size = this.GetImageSize (); + break; + case ToolStripItemImageScaling.SizeToFit: + if (this.parent == null) + preferred_size = this.GetImageSize (); + else + preferred_size = this.parent.ImageScalingSize; + break; + } + } + break; + case ToolStripItemDisplayStyle.ImageAndText: + int width2 = text_size.Width + this.padding.Horizontal; + int height2 = text_size.Height + this.padding.Vertical; + + if (this.GetImageSize () != Size.Empty) { + Size image_size = this.GetImageSize (); + + if (this.image_scaling == ToolStripItemImageScaling.SizeToFit && this.parent != null) + image_size = this.parent.ImageScalingSize; + + switch (this.text_image_relation) { + case TextImageRelation.Overlay: + width2 = Math.Max (width2, image_size.Width); + height2 = Math.Max (height2, image_size.Height); + break; + case TextImageRelation.ImageAboveText: + case TextImageRelation.TextAboveImage: + width2 = Math.Max (width2, image_size.Width); + height2 += image_size.Height; + break; + case TextImageRelation.ImageBeforeText: + case TextImageRelation.TextBeforeImage: + height2 = Math.Max (height2, image_size.Height); + width2 += image_size.Width; + break; + } + } + + preferred_size = new Size (width2, height2); + break; + } + + if (!(this is ToolStripLabel)) { // Everything but labels have a border + preferred_size.Height += 4; + preferred_size.Width += 4; + } + + return preferred_size; + } + + internal void CalculateTextAndImageRectangles (out Rectangle text_rect, out Rectangle image_rect) + { + this.CalculateTextAndImageRectangles (this.ContentRectangle, out text_rect, out image_rect); + } + + internal void CalculateTextAndImageRectangles (Rectangle contentRectangle, out Rectangle text_rect, out Rectangle image_rect) + { + text_rect = Rectangle.Empty; + image_rect = Rectangle.Empty; + + switch (this.display_style) { + case ToolStripItemDisplayStyle.None: + break; + case ToolStripItemDisplayStyle.Text: + if (this.text != string.Empty) + text_rect = AlignInRectangle (contentRectangle, this.text_size, this.text_align); + break; + case ToolStripItemDisplayStyle.Image: + if (this.Image != null && this.UseImageMargin) + image_rect = AlignInRectangle (contentRectangle, GetImageSize (), this.image_align); + break; + case ToolStripItemDisplayStyle.ImageAndText: + if (this.text != string.Empty && (this.Image == null || !this.UseImageMargin)) + text_rect = AlignInRectangle (contentRectangle, this.text_size, this.text_align); + else if (this.text == string.Empty && (this.Image == null || !this.UseImageMargin)) + break; + else if (this.text == string.Empty && this.Image != null) + image_rect = AlignInRectangle (contentRectangle, GetImageSize (), this.image_align); + else { + Rectangle text_area; + Rectangle image_area; + + switch (this.text_image_relation) { + case TextImageRelation.Overlay: + text_rect = AlignInRectangle (contentRectangle, this.text_size, this.text_align); + image_rect = AlignInRectangle (contentRectangle, GetImageSize (), this.image_align); + break; + case TextImageRelation.ImageAboveText: + text_area = new Rectangle (contentRectangle.Left, contentRectangle.Bottom - text_size.Height, contentRectangle.Width, text_size.Height); + image_area = new Rectangle (contentRectangle.Left, contentRectangle.Top, contentRectangle.Width, contentRectangle.Height - text_area.Height); + + text_rect = AlignInRectangle (text_area, this.text_size, this.text_align); + image_rect = AlignInRectangle (image_area, GetImageSize (), this.image_align); + break; + case TextImageRelation.TextAboveImage: + text_area = new Rectangle (contentRectangle.Left, contentRectangle.Top, contentRectangle.Width, text_size.Height); + image_area = new Rectangle (contentRectangle.Left, text_area.Bottom, contentRectangle.Width, contentRectangle.Height - text_area.Height); + + text_rect = AlignInRectangle (text_area, this.text_size, this.text_align); + image_rect = AlignInRectangle (image_area, GetImageSize (), this.image_align); + break; + case TextImageRelation.ImageBeforeText: + LayoutTextBeforeOrAfterImage (contentRectangle, false, text_size, GetImageSize (), text_align, image_align, out text_rect, out image_rect); + break; + case TextImageRelation.TextBeforeImage: + LayoutTextBeforeOrAfterImage (contentRectangle, true, text_size, GetImageSize (), text_align, image_align, out text_rect, out image_rect); + break; + } + } + break; + } + } + + private static Font DefaultFont { get { return new Font ("Tahoma", 8.25f); } } + + internal virtual ToolStripTextDirection DefaultTextDirection { get { return ToolStripTextDirection.Inherit; } } + + internal virtual void Dismiss (ToolStripDropDownCloseReason reason) + { + if (is_selected) { + this.is_selected = false; + this.Invalidate (); + OnUIASelectionChanged (); + } + } + + internal virtual ToolStrip GetTopLevelToolStrip () + { + if (this.Parent != null) + return this.Parent.GetTopLevelToolStrip (); + + return null; + } + + private void LayoutTextBeforeOrAfterImage (Rectangle totalArea, bool textFirst, Size textSize, Size imageSize, ContentAlignment textAlign, ContentAlignment imageAlign, out Rectangle textRect, out Rectangle imageRect) + { + int element_spacing = 0; // Spacing between the Text and the Image + int total_width = textSize.Width + element_spacing + imageSize.Width; + int excess_width = totalArea.Width - total_width; + int offset = 0; + + Rectangle final_text_rect; + Rectangle final_image_rect; + + HorizontalAlignment h_text = GetHorizontalAlignment (textAlign); + HorizontalAlignment h_image = GetHorizontalAlignment (imageAlign); + + if (h_image == HorizontalAlignment.Left) + offset = 0; + else if (h_image == HorizontalAlignment.Right && h_text == HorizontalAlignment.Right) + offset = excess_width; + else if (h_image == HorizontalAlignment.Center && (h_text == HorizontalAlignment.Left || h_text == HorizontalAlignment.Center)) + offset += (int)(excess_width / 3); + else + offset += (int)(2 * (excess_width / 3)); + + if (textFirst) { + final_text_rect = new Rectangle (totalArea.Left + offset, AlignInRectangle (totalArea, textSize, textAlign).Top, textSize.Width, textSize.Height); + final_image_rect = new Rectangle (final_text_rect.Right + element_spacing, AlignInRectangle (totalArea, imageSize, imageAlign).Top, imageSize.Width, imageSize.Height); + } else { + final_image_rect = new Rectangle (totalArea.Left + offset, AlignInRectangle (totalArea, imageSize, imageAlign).Top, imageSize.Width, imageSize.Height); + final_text_rect = new Rectangle (final_image_rect.Right + element_spacing, AlignInRectangle (totalArea, textSize, textAlign).Top, textSize.Width, textSize.Height); + } + + textRect = final_text_rect; + imageRect = final_image_rect; + } + + private HorizontalAlignment GetHorizontalAlignment (ContentAlignment align) + { + switch (align) { + case ContentAlignment.BottomLeft: + case ContentAlignment.MiddleLeft: + case ContentAlignment.TopLeft: + return HorizontalAlignment.Left; + case ContentAlignment.BottomCenter: + case ContentAlignment.MiddleCenter: + case ContentAlignment.TopCenter: + return HorizontalAlignment.Center; + case ContentAlignment.BottomRight: + case ContentAlignment.MiddleRight: + case ContentAlignment.TopRight: + return HorizontalAlignment.Right; + } + + return HorizontalAlignment.Left; + } + + internal Size GetImageSize () + { + // Get the actual size of our internal image -or- + // Get the ImageList.ImageSize if we are using ImageLists + if (this.image_scaling == ToolStripItemImageScaling.None) { + if (this.image != null) + return image.Size; + + if (this.image_index >= 0 || !string.IsNullOrEmpty (this.image_key)) + if (this.owner != null && this.owner.ImageList != null) + return this.owner.ImageList.ImageSize; + } else { + // If we have an image and a parent, return ImageScalingSize + if (this.Parent == null) + return Size.Empty; + + if (this.image != null) + return this.Parent.ImageScalingSize; + + if (this.image_index >= 0 || !string.IsNullOrEmpty (this.image_key)) + if (this.owner != null && this.owner.ImageList != null) + return this.Parent.ImageScalingSize; + } + + return Size.Empty; + } + + internal string GetToolTip () + { + if (this.auto_tool_tip && string.IsNullOrEmpty (this.tool_tip_text)) + return this.Text; + + return this.tool_tip_text; + } + + internal void FireEvent (EventArgs e, ToolStripItemEventType met) + { + // If we're disabled, don't fire any of these events, except Paint + if (!this.Enabled && met != ToolStripItemEventType.Paint) + return; + + switch (met) { + case ToolStripItemEventType.MouseUp: + if (((MouseEventArgs)e).Button == MouseButtons.Left) + this.HandleClick (((MouseEventArgs)e).Clicks, e); + this.OnMouseUp ((MouseEventArgs)e); + break; + case ToolStripItemEventType.MouseDown: + this.OnMouseDown ((MouseEventArgs)e); + break; + case ToolStripItemEventType.MouseEnter: + this.OnMouseEnter (e); + break; + case ToolStripItemEventType.MouseHover: + this.OnMouseHover (e); + break; + case ToolStripItemEventType.MouseLeave: + this.OnMouseLeave (e); + break; + case ToolStripItemEventType.MouseMove: + this.OnMouseMove ((MouseEventArgs)e); + break; + case ToolStripItemEventType.Paint: + this.OnPaintInternal ((PaintEventArgs)e); + break; + case ToolStripItemEventType.Click: + this.HandleClick (1, e); + break; + } + } + + internal virtual void HandleClick (int mouse_clicks, EventArgs e) + { + if (Parent == null) + return; + this.Parent.HandleItemClick (this); + if (mouse_clicks == 2 && double_click_enabled) + this.OnDoubleClick (e); + else + this.OnClick (e); + } + + internal virtual void SetPlacement (ToolStripItemPlacement placement) + { + this.placement = placement; + } + + private void BeginAnimation () + { + if (image != null && ImageAnimator.CanAnimate (image)) { + frame_handler = new EventHandler (OnAnimateImage); + ImageAnimator.Animate (image, frame_handler); + } + } + + private void OnAnimateImage (object sender, EventArgs e) + { + // This is called from a worker thread,BeginInvoke is used + // so the Widget is updated from the correct thread + + // Check if we have a handle again, since it may have gotten + // destroyed since the last time we checked. + if (Parent == null || !Parent.IsHandleCreated) + return; + + Parent.BeginInvoke (new EventHandler (UpdateAnimatedImage), new object[] { this, e }); + } + + private void StopAnimation () + { + if (frame_handler == null) + return; + + ImageAnimator.StopAnimate (image, frame_handler); + frame_handler = null; + } + + private void UpdateAnimatedImage (object sender, EventArgs e) + { + // Check if we have a handle again, since it may have gotten + // destroyed since the last time we checked. + if (Parent == null || !Parent.IsHandleCreated) + return; + + ImageAnimator.UpdateFrames (image); + Invalidate (); + } + + internal bool ShowMargin { + get { + if (!this.IsOnDropDown) + return true; + + if (!(this.Owner is ToolStripDropDownMenu)) + return false; + + ToolStripDropDownMenu tsddm = (ToolStripDropDownMenu)this.Owner; + + return tsddm.ShowCheckMargin || tsddm.ShowImageMargin; + } + } + + internal bool UseImageMargin { + get { + if (!this.IsOnDropDown) + return true; + + if (!(this.Owner is ToolStripDropDownMenu)) + return false; + + ToolStripDropDownMenu tsddm = (ToolStripDropDownMenu)this.Owner; + + return tsddm.ShowImageMargin || tsddm.ShowCheckMargin; + } + } + + internal virtual bool InternalVisible { + get { return this.visible; } + set { this.visible = value; Invalidate (); } + } + + internal ToolStrip InternalOwner { + set { + if (this.owner != value) { + this.owner = value; + if (this.owner != null) + this.CalculateAutoSize (); + OnOwnerChanged (EventArgs.Empty); + } + } + } + + internal Point Location { + get { return this.bounds.Location; } + set { + if (this.bounds.Location != value) { + this.bounds.Location = value; + this.OnLocationChanged (EventArgs.Empty); + } + } + } + + internal int Top { + get { return this.bounds.Y; } + set { + if (this.bounds.Y != value) { + this.bounds.Y = value; + this.OnLocationChanged (EventArgs.Empty); + } + } + } + + internal int Left { + get { return this.bounds.X; } + set { + if (this.bounds.X != value) { + this.bounds.X = value; + this.OnLocationChanged (EventArgs.Empty); + } + } + } + + internal int Right { get { return this.bounds.Right; } } + internal int Bottom { get { return this.bounds.Bottom; } } + #endregion + + #region IDropTarget Members + void IDropTarget.OnDragDrop (DragEventArgs dragEvent) + { + OnDragDrop (dragEvent); + } + + void IDropTarget.OnDragEnter (DragEventArgs dragEvent) + { + OnDragEnter (dragEvent); + } + + void IDropTarget.OnDragLeave (EventArgs e) + { + OnDragLeave (e); + } + + void IDropTarget.OnDragOver (DragEventArgs dragEvent) + { + OnDragOver (dragEvent); + } + #endregion + + #region UIA Framework: Methods, Properties and Events + + static object UIASelectionChangedEvent = new object (); + + internal event EventHandler UIASelectionChanged { + add { Events.AddHandler (UIASelectionChangedEvent, value); } + remove { Events.RemoveHandler (UIASelectionChangedEvent, value); } + } + + internal void OnUIASelectionChanged () + { + EventHandler eh = (EventHandler)(Events [UIASelectionChangedEvent]); + if (eh != null) + eh (this, EventArgs.Empty); + } + + #endregion + + [ComVisible (true)] + public class ToolStripItemAccessibleObject : AccessibleObject + { + internal ToolStripItem owner_item; + + public ToolStripItemAccessibleObject (ToolStripItem ownerItem) + { + if (ownerItem == null) + throw new ArgumentNullException ("ownerItem"); + + this.owner_item = ownerItem; + base.default_action = string.Empty; + base.keyboard_shortcut = string.Empty; + base.name = string.Empty; + base.value = string.Empty; + } + + #region Public Properties + public override Rectangle Bounds { + get { + return owner_item.Visible ? owner_item.Bounds : Rectangle.Empty; + } + } + + public override string DefaultAction { + get { return base.DefaultAction; } + } + + public override string Description { + get { return base.Description; } + } + + public override string Help { + get { return base.Help; } + } + + public override string KeyboardShortcut { + get { return base.KeyboardShortcut; } + } + + public override string Name { + get { + if (base.name == string.Empty) + return owner_item.Text; + + return base.Name; + } + set { base.Name = value; } + } + + public override AccessibleObject Parent { + get { return base.Parent; } + } + + public override AccessibleRole Role { + get { return base.Role; } + } + + public override AccessibleStates State { + get { return base.State; } + } + #endregion + + #region Public Methods + public void AddState (AccessibleStates state) + { + base.state = state; + } + + public override void DoDefaultAction () + { + base.DoDefaultAction (); + } + + public override int GetHelpTopic (out string fileName) + { + return base.GetHelpTopic (out fileName); + } + + public override AccessibleObject Navigate (AccessibleNavigation navigationDirection) + { + return base.Navigate (navigationDirection); + } + + public override string ToString () + { + return string.Format ("ToolStripItemAccessibleObject: Owner = {0}", owner_item.ToString()); + } + #endregion + } + } + + internal class NoneExcludedImageIndexConverter : ImageIndexConverter + { + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItemAlignment.cs b/source/ShiftUI/ToolStrip/ToolStripItemAlignment.cs new file mode 100644 index 0000000..5bd4bbf --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItemAlignment.cs @@ -0,0 +1,37 @@ +// +// ToolStripItemAlignment.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum ToolStripItemAlignment + { + Left = 0, + Right = 1 + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItemClickedEventArgs.cs b/source/ShiftUI/ToolStrip/ToolStripItemClickedEventArgs.cs new file mode 100644 index 0000000..65c9d34 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItemClickedEventArgs.cs @@ -0,0 +1,47 @@ +// +// ToolStripItemClickedEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// +using System; + +namespace ShiftUI +{ + public class ToolStripItemClickedEventArgs : EventArgs + { + private ToolStripItem clicked_item; + + public ToolStripItemClickedEventArgs (ToolStripItem clickedItem) : base () + { + this.clicked_item = clickedItem; + } + + #region Public Properties + public ToolStripItem ClickedItem { + get { return this.clicked_item; } + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItemClickedEventHandler.cs b/source/ShiftUI/ToolStrip/ToolStripItemClickedEventHandler.cs new file mode 100644 index 0000000..66ab988 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItemClickedEventHandler.cs @@ -0,0 +1,32 @@ +// +// ToolStripItemClickedEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ToolStripItemClickedEventHandler (object sender, ToolStripItemClickedEventArgs e); +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItemCollection.cs b/source/ShiftUI/ToolStrip/ToolStripItemCollection.cs new file mode 100644 index 0000000..46d3072 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItemCollection.cs @@ -0,0 +1,385 @@ +// +// ToolStripItemCollection.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using ShiftUI.Layout; +using System; + +namespace ShiftUI +{ + [ListBindable (false)] + //[Editor ("ShiftUI.Design.ToolStripCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + public class ToolStripItemCollection : ArrangedElementCollection, IList, ICollection, IEnumerable + { + private ToolStrip owner; + private bool internal_created; + + #region Public Constructor + public ToolStripItemCollection (ToolStrip owner, ToolStripItem[] value) : base () + { + if (owner == null) + throw new ArgumentNullException ("owner"); + + if (value == null) + throw new ArgumentNullException ("toolStripItems"); + + this.owner = owner; + + foreach (ToolStripItem tsi in value) + this.AddNoOwnerOrLayout (tsi); + } + + internal ToolStripItemCollection (ToolStrip owner, ToolStripItem[] value, bool internalcreated) : base () + { + if (owner == null) + throw new ArgumentNullException ("owner"); + + this.internal_created = internalcreated; + this.owner = owner; + + if (value != null) + foreach (ToolStripItem tsi in value) + this.AddNoOwnerOrLayout (tsi); + } + #endregion + + #region Public Properties + public override bool IsReadOnly { get { return base.IsReadOnly; } } + + public new virtual ToolStripItem this[int index] { get { return (ToolStripItem)base[index]; } } + + public virtual ToolStripItem this[string key] { + get { + foreach (ToolStripItem tsi in this) + if (tsi.Name == key) + return tsi; + + return null; + } + } + #endregion + + #region Public Methods + public ToolStripItem Add (Image image) + { + ToolStripItem tsb = owner.CreateDefaultItem (string.Empty, image, null); + this.Add (tsb); + return tsb; + } + + public ToolStripItem Add (string text) + { + ToolStripItem tsb = owner.CreateDefaultItem (text, null, null); + this.Add (tsb); + return tsb; + } + + public int Add (ToolStripItem value) + { + if (value == null) + throw new ArgumentNullException ("value"); + + if (Contains (value)) + return IndexOf (value); + + value.InternalOwner = owner; + + if (value is ToolStripMenuItem && (value as ToolStripMenuItem).ShortcutKeys != Keys.None) + ToolStripManager.AddToolStripMenuItem ((ToolStripMenuItem)value); + + int index = base.Add (value); + + if (this.internal_created) + owner.OnItemAdded (new ToolStripItemEventArgs (value)); + + return index; + } + + public ToolStripItem Add (string text, Image image) + { + ToolStripItem tsb = owner.CreateDefaultItem (text, image, null); + this.Add (tsb); + return tsb; + } + + public ToolStripItem Add (string text, Image image, EventHandler onClick) + { + ToolStripItem tsb = owner.CreateDefaultItem (text, image, onClick); + this.Add (tsb); + return tsb; + } + + public void AddRange (ToolStripItem[] toolStripItems) + { + if (toolStripItems == null) + throw new ArgumentNullException ("toolStripItems"); + if (this.IsReadOnly) + throw new NotSupportedException ("This collection is read-only"); + + this.owner.SuspendLayout (); + + foreach (ToolStripItem tsi in toolStripItems) + this.Add (tsi); + + this.owner.ResumeLayout (); + } + + public void AddRange (ToolStripItemCollection toolStripItems) + { + if (toolStripItems == null) + throw new ArgumentNullException ("toolStripItems"); + if (this.IsReadOnly) + throw new NotSupportedException ("This collection is read-only"); + + this.owner.SuspendLayout (); + + foreach (ToolStripItem tsi in toolStripItems) + this.Add (tsi); + + this.owner.ResumeLayout (); + } + + public new virtual void Clear () + { + if (this.IsReadOnly) + throw new NotSupportedException ("This collection is read-only"); + + if (internal_created) + foreach (ToolStripItem item in this) { + item.InternalOwner = null; + item.Parent = null; + } + + base.Clear (); + owner.PerformLayout (); + } + + // Don't modify Owner or Parent - used by internal collection instances. + internal void ClearInternal () + { + base.Clear (); + owner.PerformLayout (); + } + + public bool Contains (ToolStripItem value) + { + return base.Contains (value); + } + + public virtual bool ContainsKey (string key) + { + return this[key] != null; + } + + public void CopyTo (ToolStripItem[] array, int index) + { + base.CopyTo (array, index); + } + + [MonoTODO ("searchAllChildren parameter isn't used")] + public ToolStripItem[] Find (string key, bool searchAllChildren) + { + if (key == null || key.Length == 0) + throw new ArgumentNullException ("key"); + + List list = new List (); + + foreach (ToolStripItem tsi in this) { + if (String.Compare (tsi.Name, key, true) == 0) { + list.Add (tsi); + + if (searchAllChildren) { + // TODO: tsi does not have an items property yet.. + } + } + } + + return list.ToArray (); + } + + public int IndexOf (ToolStripItem value) + { + return base.IndexOf (value); + } + + public virtual int IndexOfKey (string key) + { + ToolStripItem tsi = this[key]; + + if (tsi == null) + return -1; + + return this.IndexOf (tsi); + } + + public void Insert (int index, ToolStripItem value) + { + if (value == null) + throw new ArgumentNullException ("value"); + + if (value is ToolStripMenuItem && (value as ToolStripMenuItem).ShortcutKeys != Keys.None) + ToolStripManager.AddToolStripMenuItem ((ToolStripMenuItem)value); + + if (value.Owner != null) + value.Owner.Items.Remove (value); + + base.Insert (index, value); + + if (internal_created) { + value.InternalOwner = owner; + owner.OnItemAdded (new ToolStripItemEventArgs (value)); + } + + if (owner.Created) + owner.PerformLayout (); + } + + public void Remove (ToolStripItem value) + { + if (this.IsReadOnly) + throw new NotSupportedException ("This collection is read-only"); + + base.Remove (value); + + if (value != null && internal_created) { + value.InternalOwner = null; + value.Parent = null; + } + + if (internal_created) + owner.OnItemRemoved (new ToolStripItemEventArgs (value)); + + if (owner.Created) + owner.PerformLayout (); + } + + public void RemoveAt (int index) + { + if (this.IsReadOnly) + throw new NotSupportedException ("This collection is read-only"); + + ToolStripItem tsi = (ToolStripItem)base[index]; + this.Remove (tsi); + } + + public virtual void RemoveByKey (string key) + { + if (this.IsReadOnly) + throw new NotSupportedException ("This collection is read-only"); + + ToolStripItem tsi = this[key]; + + if (tsi != null) + this.Remove (tsi); + + return; + } + #endregion + + #region Internal Methods + // When we create DisplayedItems, we don't want to modify the item's + // parent or trigger a layout. + internal int AddNoOwnerOrLayout (ToolStripItem value) + { + if (value == null) + throw new ArgumentNullException ("value"); + + int index = base.Add (value); + return index; + } + + internal void InsertNoOwnerOrLayout (int index, ToolStripItem value) + { + if (value == null) + throw new ArgumentNullException ("value"); + + if (index > Count) + base.Add (value); + else + base.Insert (index, value); + } + + internal void RemoveNoOwnerOrLayout (ToolStripItem value) + { + if (value == null) + throw new ArgumentNullException ("value"); + + base.Remove (value); + } + #endregion + + #region IList Members + int IList.Add (object value) + { + return this.Add ((ToolStripItem)value); + } + + void IList.Clear () + { + this.Clear (); + } + + bool IList.Contains (object value) + { + return this.Contains ((ToolStripItem)value); + } + + int IList.IndexOf (object value) + { + return this.IndexOf ((ToolStripItem)value); + } + + void IList.Insert (int index, object value) + { + this.Insert (index, (ToolStripItem)value); + } + + bool IList.IsFixedSize { + get { return this.IsFixedSize; } + } + + void IList.Remove (object value) + { + this.Remove ((ToolStripItem)value); ; + } + + void IList.RemoveAt (int index) + { + this.RemoveAt (index); + } + + object IList.this[int index] { + get { return this[index]; } + set { throw new NotSupportedException (); } + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItemDisplayStyle.cs b/source/ShiftUI/ToolStrip/ToolStripItemDisplayStyle.cs new file mode 100644 index 0000000..a090648 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItemDisplayStyle.cs @@ -0,0 +1,39 @@ +// +// ToolStripItemDisplayStyle.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum ToolStripItemDisplayStyle + { + None = 0, + Text = 1, + Image = 2, + ImageAndText = 3 + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItemEventArgs.cs b/source/ShiftUI/ToolStrip/ToolStripItemEventArgs.cs new file mode 100644 index 0000000..71a826b --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItemEventArgs.cs @@ -0,0 +1,50 @@ +// +// ToolStripItemEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System; + +namespace ShiftUI +{ + public class ToolStripItemEventArgs : EventArgs + { + private ToolStripItem item; + + public ToolStripItemEventArgs (ToolStripItem item) : base () + { + this.item = item; + } + + #region Public Properties + public ToolStripItem Item + { + get { return item; } + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItemEventHandler.cs b/source/ShiftUI/ToolStrip/ToolStripItemEventHandler.cs new file mode 100644 index 0000000..a10eabe --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItemEventHandler.cs @@ -0,0 +1,32 @@ +// +// ToolStripItemEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ToolStripItemEventHandler (object sender, ToolStripItemEventArgs e); +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItemEventType.cs b/source/ShiftUI/ToolStrip/ToolStripItemEventType.cs new file mode 100644 index 0000000..c58efa2 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItemEventType.cs @@ -0,0 +1,42 @@ +// +// ToolStripItemEventType.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + internal enum ToolStripItemEventType + { + MouseDown = 1, + MouseEnter = 2, + MouseHover = 3, + MouseLeave = 4, + MouseMove = 5, + MouseUp = 6, + Paint = 7, + Click = 8 + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItemImageRenderEventArgs.cs b/source/ShiftUI/ToolStrip/ToolStripItemImageRenderEventArgs.cs new file mode 100644 index 0000000..864ed9a --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItemImageRenderEventArgs.cs @@ -0,0 +1,60 @@ +// +// ToolStripItemImageRenderEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; + +namespace ShiftUI +{ + public class ToolStripItemImageRenderEventArgs : ToolStripItemRenderEventArgs + { + private Image image; + private Rectangle image_rectangle; + + public ToolStripItemImageRenderEventArgs (Graphics g, ToolStripItem item, Rectangle imageRectangle) + : this (g, item, null, imageRectangle) + { + } + + public ToolStripItemImageRenderEventArgs (Graphics g, ToolStripItem item, Image image, Rectangle imageRectangle) + : base (g, item) + { + this.image = image; + this.image_rectangle = imageRectangle; + } + + #region Public Properties + public Image Image { + get { return this.image; } + } + + public Rectangle ImageRectangle { + get { return this.image_rectangle; } + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItemImageRenderEventHandler.cs b/source/ShiftUI/ToolStrip/ToolStripItemImageRenderEventHandler.cs new file mode 100644 index 0000000..3d475c8 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItemImageRenderEventHandler.cs @@ -0,0 +1,32 @@ +// +// ToolStripItemImageRenderEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ToolStripItemImageRenderEventHandler (object sender, ToolStripItemImageRenderEventArgs e); +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItemImageScaling.cs b/source/ShiftUI/ToolStrip/ToolStripItemImageScaling.cs new file mode 100644 index 0000000..b2293c5 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItemImageScaling.cs @@ -0,0 +1,37 @@ +// +// ToolStripItemImageScaling.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum ToolStripItemImageScaling + { + None = 0, + SizeToFit = 1 + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItemOverflow.cs b/source/ShiftUI/ToolStrip/ToolStripItemOverflow.cs new file mode 100644 index 0000000..6410f0b --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItemOverflow.cs @@ -0,0 +1,38 @@ +// +// ToolStripItemOverflow.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum ToolStripItemOverflow + { + Never = 0, + Always = 1, + AsNeeded = 2 + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItemPlacement.cs b/source/ShiftUI/ToolStrip/ToolStripItemPlacement.cs new file mode 100644 index 0000000..0edde1d --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItemPlacement.cs @@ -0,0 +1,38 @@ +// +// ToolStripItemPlacement.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum ToolStripItemPlacement + { + Main = 0, + Overflow = 1, + None = 2 + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItemRenderEventArgs.cs b/source/ShiftUI/ToolStrip/ToolStripItemRenderEventArgs.cs new file mode 100644 index 0000000..ecea083 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItemRenderEventArgs.cs @@ -0,0 +1,59 @@ +// +// ToolStripItemRenderEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System; + +namespace ShiftUI +{ + public class ToolStripItemRenderEventArgs : EventArgs + { + private Graphics graphics; + private ToolStripItem item; + + public ToolStripItemRenderEventArgs (Graphics g, ToolStripItem item) : base () + { + this.graphics = g; + this.item = item; + } + + #region Public Properties + public Graphics Graphics { + get { return this.graphics; } + } + + public ToolStripItem Item { + get { return this.item; } + } + + public ToolStrip ToolStrip { + get { return this.item.Owner; } + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItemRenderEventHandler.cs b/source/ShiftUI/ToolStrip/ToolStripItemRenderEventHandler.cs new file mode 100644 index 0000000..cada3ef --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItemRenderEventHandler.cs @@ -0,0 +1,32 @@ +// +// ToolStripItemRenderEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ToolStripItemRenderEventHandler (object sender, ToolStripItemRenderEventArgs e); +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItemTextRenderEventArgs.cs b/source/ShiftUI/ToolStrip/ToolStripItemTextRenderEventArgs.cs new file mode 100644 index 0000000..f712f53 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItemTextRenderEventArgs.cs @@ -0,0 +1,131 @@ +// +// ToolStripItemTextRenderEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; + +namespace ShiftUI +{ + public class ToolStripItemTextRenderEventArgs : ToolStripItemRenderEventArgs + { + private string text; + private Color text_color; + private ToolStripTextDirection text_direction; + private Font text_font; + private TextFormatFlags text_format; + private Rectangle text_rectangle; + + #region Public Constructors + public ToolStripItemTextRenderEventArgs (Graphics g, ToolStripItem item, string text, Rectangle textRectangle, Color textColor, Font textFont, ContentAlignment textAlign) + : base (g, item) + { + this.text = text; + this.text_rectangle = textRectangle; + this.text_color = textColor; + this.text_font = textFont; + this.text_direction = item.TextDirection; + + switch (textAlign) { + case ContentAlignment.BottomCenter: + this.text_format = TextFormatFlags.Bottom | TextFormatFlags.HorizontalCenter; + break; + case ContentAlignment.BottomLeft: + this.text_format = TextFormatFlags.Bottom | TextFormatFlags.Left; + break; + case ContentAlignment.BottomRight: + this.text_format = TextFormatFlags.Bottom | TextFormatFlags.Right; + break; + case ContentAlignment.MiddleCenter: + this.text_format = TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter; + break; + case ContentAlignment.MiddleLeft: + default: + this.text_format = (TextFormatFlags.VerticalCenter | TextFormatFlags.Left); + break; + case ContentAlignment.MiddleRight: + this.text_format = TextFormatFlags.VerticalCenter | TextFormatFlags.Right; + break; + case ContentAlignment.TopCenter: + this.text_format = TextFormatFlags.Top | TextFormatFlags.HorizontalCenter; + break; + case ContentAlignment.TopLeft: + this.text_format = TextFormatFlags.Top | TextFormatFlags.Left; + break; + case ContentAlignment.TopRight: + this.text_format = TextFormatFlags.Top | TextFormatFlags.Right; + break; + } + + if ((Application.KeyboardCapture == null || !ToolStripManager.ActivatedByKeyboard) && !SystemInformation.MenuAccessKeysUnderlined) + this.text_format |= TextFormatFlags.HidePrefix; + } + + public ToolStripItemTextRenderEventArgs (Graphics g, ToolStripItem item, string text, Rectangle textRectangle, Color textColor, Font textFont, TextFormatFlags format) + : base (g, item) + { + this.text = text; + this.text_rectangle = textRectangle; + this.text_color = textColor; + this.text_font = textFont; + this.text_format = format; + this.text_direction = ToolStripTextDirection.Horizontal; + } + #endregion + + #region Public Properties + public string Text { + get { return this.text; } + set { this.text = value; } + } + + public Color TextColor { + get { return this.text_color; } + set { this.text_color = value; } + } + + public ToolStripTextDirection TextDirection { + get { return this.text_direction; } + set { this.text_direction = value; } + } + + public Font TextFont { + get { return this.text_font; } + set { this.text_font = value; } + } + + public TextFormatFlags TextFormat { + get { return this.text_format; } + set { this.text_format = value; } + } + + public Rectangle TextRectangle { + get { return this.text_rectangle; } + set { this.text_rectangle = value; } + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripItemTextRenderEventHandler.cs b/source/ShiftUI/ToolStrip/ToolStripItemTextRenderEventHandler.cs new file mode 100644 index 0000000..f265b3d --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripItemTextRenderEventHandler.cs @@ -0,0 +1,32 @@ +// +// ToolStripItemTextRenderEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ToolStripItemTextRenderEventHandler (object sender, ToolStripItemTextRenderEventArgs e); +} diff --git a/source/ShiftUI/ToolStrip/ToolStripLabel.cs b/source/ShiftUI/ToolStrip/ToolStripLabel.cs new file mode 100644 index 0000000..9f70b80 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripLabel.cs @@ -0,0 +1,288 @@ +// +// ToolStripLabel.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System.ComponentModel; +using ShiftUI.Design; +using System; + +namespace ShiftUI +{ + [ToolStripItemDesignerAvailability (ToolStripItemDesignerAvailability.ToolStrip)] + public class ToolStripLabel : ToolStripItem + { + private Color active_link_color; + private bool is_link; + private LinkBehavior link_behavior; + private Color link_color; + private bool link_visited; + private Color visited_link_color; + + #region UIA FrameWork Events + static object UIAIsLinkChangedEvent = new object (); + + internal event EventHandler UIAIsLinkChanged { + add { Events.AddHandler (UIAIsLinkChangedEvent, value); } + remove { Events.RemoveHandler (UIAIsLinkChangedEvent, value); } + } + + internal void OnUIAIsLinkChanged (EventArgs e) + { + EventHandler eh = (EventHandler) Events [UIAIsLinkChangedEvent]; + if (eh != null) + eh (this, e); + } + #endregion + + #region Public Constructors + public ToolStripLabel () + : this (null, null, false, null, String.Empty) + { + } + + public ToolStripLabel (Image image) + : this (null, image, false, null, String.Empty) + { + } + + public ToolStripLabel (string text) + : this (text, null, false, null, String.Empty) + { + } + + public ToolStripLabel (string text, Image image) + : this (text, image, false, null, String.Empty) + { + } + + public ToolStripLabel (string text, Image image, bool isLink) + : this (text, image, isLink, null, String.Empty) + { + } + + public ToolStripLabel (string text, Image image, bool isLink, EventHandler onClick) + : this (text, image, isLink, onClick, String.Empty) + { + } + + public ToolStripLabel (string text, Image image, bool isLink, EventHandler onClick, string name) + : base (text, image, onClick, name) + { + this.active_link_color = Color.Red; + this.is_link = isLink; + this.link_behavior = LinkBehavior.SystemDefault; + this.link_color = Color.FromArgb (0, 0, 255); + this.link_visited = false; + this.visited_link_color = Color.FromArgb (128, 0, 128); + } + #endregion + + #region Public Properties + public Color ActiveLinkColor { + get { return this.active_link_color; } + set { + this.active_link_color = value; + this.Invalidate (); + } + } + + public override bool CanSelect { get { return false; } } + + [DefaultValue (false)] + public bool IsLink { + get { return this.is_link; } + set { + this.is_link = value; + this.Invalidate (); + + // UIA Framework Event: IsLink Changed + OnUIAIsLinkChanged (EventArgs.Empty); + } + } + + [DefaultValue (LinkBehavior.SystemDefault)] + public LinkBehavior LinkBehavior { + get { return this.link_behavior; } + set { + this.link_behavior = value; + this.Invalidate (); + } + } + + public Color LinkColor { + get { return this.link_color; } + set { + this.link_color = value; + this.Invalidate (); + } + } + + [DefaultValue (false)] + public bool LinkVisited { + get { return this.link_visited; } + set { + this.link_visited = value; + this.Invalidate (); + } + } + + public Color VisitedLinkColor + { + get { return this.visited_link_color; } + set { + this.visited_link_color = value; + this.Invalidate (); + } + } + #endregion + + #region Protected Methods + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override AccessibleObject CreateAccessibilityInstance () + { + ToolStripItemAccessibleObject ao = new ToolStripItemAccessibleObject (this); + + ao.role = AccessibleRole.StaticText; + ao.state = AccessibleStates.ReadOnly; + + return ao; + } + + protected override void OnFontChanged (EventArgs e) + { + base.OnFontChanged (e); + } + + protected override void OnMouseEnter (EventArgs e) + { + base.OnMouseEnter (e); + } + + protected override void OnMouseLeave (EventArgs e) + { + base.OnMouseLeave (e); + } + + protected override void OnPaint (ShiftUI.PaintEventArgs e) + { + if (this.Owner != null) { + Color font_color = this.Enabled ? this.ForeColor : SystemColors.GrayText; + Image draw_image = this.Enabled ? this.Image : ToolStripRenderer.CreateDisabledImage (this.Image); + + this.Owner.Renderer.DrawLabelBackground (new ShiftUI.ToolStripItemRenderEventArgs (e.Graphics, this)); + + Rectangle text_layout_rect; + Rectangle image_layout_rect; + + this.CalculateTextAndImageRectangles (out text_layout_rect, out image_layout_rect); + + if (this.IsOnDropDown) { + if (this.ShowMargin) + text_layout_rect = new Rectangle (35, text_layout_rect.Top, text_layout_rect.Width, text_layout_rect.Height); + else + text_layout_rect = new Rectangle (7, text_layout_rect.Top, text_layout_rect.Width, text_layout_rect.Height); + if (image_layout_rect != Rectangle.Empty) + image_layout_rect = new Rectangle (new Point (4, 3), base.GetImageSize ()); + } + + if (image_layout_rect != Rectangle.Empty) + this.Owner.Renderer.DrawItemImage (new ShiftUI.ToolStripItemImageRenderEventArgs (e.Graphics, this, draw_image, image_layout_rect)); + if (text_layout_rect != Rectangle.Empty) + if (this.is_link) { + if (this.Pressed) // Mouse Down + { + switch (this.link_behavior) { + case LinkBehavior.SystemDefault: + case LinkBehavior.AlwaysUnderline: + case LinkBehavior.HoverUnderline: + this.Owner.Renderer.DrawItemText (new ShiftUI.ToolStripItemTextRenderEventArgs (e.Graphics, this, this.Text, text_layout_rect, this.active_link_color, new Font (this.Font, FontStyle.Underline), this.TextAlign)); + break; + case LinkBehavior.NeverUnderline: + this.Owner.Renderer.DrawItemText (new ShiftUI.ToolStripItemTextRenderEventArgs (e.Graphics, this, this.Text, text_layout_rect, this.active_link_color, this.Font, this.TextAlign)); + break; + } + } + else if (this.Selected) // Hover + { + switch (this.link_behavior) { + case LinkBehavior.SystemDefault: + case LinkBehavior.AlwaysUnderline: + case LinkBehavior.HoverUnderline: + this.Owner.Renderer.DrawItemText (new ShiftUI.ToolStripItemTextRenderEventArgs (e.Graphics, this, this.Text, text_layout_rect, this.link_color, new Font (this.Font, FontStyle.Underline), this.TextAlign)); + break; + case LinkBehavior.NeverUnderline: + this.Owner.Renderer.DrawItemText (new ShiftUI.ToolStripItemTextRenderEventArgs (e.Graphics, this, this.Text, text_layout_rect, this.link_color, this.Font, this.TextAlign)); + break; + } + } + else { + + if (this.link_visited) // Normal, Visited + { + switch (this.link_behavior) { + case LinkBehavior.SystemDefault: + case LinkBehavior.AlwaysUnderline: + this.Owner.Renderer.DrawItemText (new ShiftUI.ToolStripItemTextRenderEventArgs (e.Graphics, this, this.Text, text_layout_rect, this.visited_link_color, new Font (this.Font, FontStyle.Underline), this.TextAlign)); + break; + case LinkBehavior.NeverUnderline: + case LinkBehavior.HoverUnderline: + this.Owner.Renderer.DrawItemText (new ShiftUI.ToolStripItemTextRenderEventArgs (e.Graphics, this, this.Text, text_layout_rect, this.visited_link_color, this.Font, this.TextAlign)); + break; + } + } + else // Normal + { + switch (this.link_behavior) { + case LinkBehavior.SystemDefault: + case LinkBehavior.AlwaysUnderline: + this.Owner.Renderer.DrawItemText (new ShiftUI.ToolStripItemTextRenderEventArgs (e.Graphics, this, this.Text, text_layout_rect, this.link_color, new Font (this.Font, FontStyle.Underline), this.TextAlign)); + break; + case LinkBehavior.NeverUnderline: + case LinkBehavior.HoverUnderline: + this.Owner.Renderer.DrawItemText (new ShiftUI.ToolStripItemTextRenderEventArgs (e.Graphics, this, this.Text, text_layout_rect, this.link_color, this.Font, this.TextAlign)); + break; + } + + } + } + } else + this.Owner.Renderer.DrawItemText (new ShiftUI.ToolStripItemTextRenderEventArgs (e.Graphics, this, this.Text, text_layout_rect, font_color, this.Font, this.TextAlign)); + } + + // call Paint handlers last. + base.OnPaint (e); + } + + protected internal override bool ProcessMnemonic (char charCode) + { + this.Parent.SelectNextToolStripItem (this, true); + return true; + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripLayoutStyle.cs b/source/ShiftUI/ToolStrip/ToolStripLayoutStyle.cs new file mode 100644 index 0000000..39d3c10 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripLayoutStyle.cs @@ -0,0 +1,40 @@ +// +// ToolStripLayoutStyle.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum ToolStripLayoutStyle + { + StackWithOverflow = 0, + HorizontalStackWithOverflow = 1, + VerticalStackWithOverflow = 2, + Flow = 3, + Table = 4 + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripManager.cs b/source/ShiftUI/ToolStrip/ToolStripManager.cs new file mode 100644 index 0000000..f580413 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripManager.cs @@ -0,0 +1,634 @@ +// +// ToolStripManager.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System.Runtime.InteropServices; +using System.ComponentModel; +using System.Collections.Generic; +using System; + +namespace ShiftUI +{ + public sealed class ToolStripManager + { + private static ToolStripRenderer renderer = new ToolStripProfessionalRenderer (); + private static ToolStripManagerRenderMode render_mode = ToolStripManagerRenderMode.Professional; + private static bool visual_styles_enabled = Application.RenderWithVisualStyles; + private static List toolstrips = new List (); + private static List menu_items = new List (); + private static bool activated_by_keyboard; + + #region Private Constructor + private ToolStripManager () + { + } + #endregion + + #region Public Properties + public static ToolStripRenderer Renderer { + get { return ToolStripManager.renderer; } + set { + if (ToolStripManager.Renderer != value) { + ToolStripManager.renderer = value; + ToolStripManager.OnRendererChanged (EventArgs.Empty); + } + } + } + + public static ToolStripManagerRenderMode RenderMode { + get { return ToolStripManager.render_mode; } + set { + if (!Enum.IsDefined (typeof (ToolStripManagerRenderMode), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripManagerRenderMode", value)); + + if (ToolStripManager.render_mode != value) { + ToolStripManager.render_mode = value; + + switch (value) { + case ToolStripManagerRenderMode.Custom: + throw new NotSupportedException (); + case ToolStripManagerRenderMode.System: + ToolStripManager.Renderer = new ToolStripSystemRenderer (); + break; + case ToolStripManagerRenderMode.Professional: + ToolStripManager.Renderer = new ToolStripProfessionalRenderer (); + break; + } + } + } + } + + public static bool VisualStylesEnabled { + get { return ToolStripManager.visual_styles_enabled; } + set { + if (ToolStripManager.visual_styles_enabled != value) { + ToolStripManager.visual_styles_enabled = value; + + if (ToolStripManager.render_mode == ToolStripManagerRenderMode.Professional) { + (ToolStripManager.renderer as ToolStripProfessionalRenderer).ColorTable.UseSystemColors = !value; + ToolStripManager.OnRendererChanged (EventArgs.Empty); + } + } + } + } + #endregion + + #region Public Methods + public static ToolStrip FindToolStrip (string toolStripName) + { + lock (toolstrips) + foreach (WeakReference wr in toolstrips) { + ToolStrip ts = (ToolStrip)wr.Target; + + if (ts == null) + continue; + + if (ts.Name == toolStripName) + return ts; + } + + return null; + } + + public static bool IsShortcutDefined (Keys shortcut) + { + lock (menu_items) + foreach (ToolStripMenuItem tsmi in menu_items) + if (tsmi.ShortcutKeys == shortcut) + return true; + + return false; + } + + public static bool IsValidShortcut (Keys shortcut) + { + // Anything with an F1 - F12 is a shortcut + if ((shortcut & Keys.F1) == Keys.F1) + return true; + else if ((shortcut & Keys.F2) == Keys.F2) + return true; + else if ((shortcut & Keys.F3) == Keys.F3) + return true; + else if ((shortcut & Keys.F4) == Keys.F4) + return true; + else if ((shortcut & Keys.F5) == Keys.F5) + return true; + else if ((shortcut & Keys.F6) == Keys.F6) + return true; + else if ((shortcut & Keys.F7) == Keys.F7) + return true; + else if ((shortcut & Keys.F8) == Keys.F8) + return true; + else if ((shortcut & Keys.F9) == Keys.F9) + return true; + else if ((shortcut & Keys.F10) == Keys.F10) + return true; + else if ((shortcut & Keys.F11) == Keys.F11) + return true; + else if ((shortcut & Keys.F12) == Keys.F12) + return true; + + // Modifier keys alone are not shortcuts + switch (shortcut) { + case Keys.Alt: + case Keys.Widget: + case Keys.Shift: + case Keys.Alt | Keys.Widget: + case Keys.Alt | Keys.Shift: + case Keys.Widget | Keys.Shift: + case Keys.Alt | Keys.Widget | Keys.Shift: + return false; + } + + // Anything else with a modifier key is a shortcut + if ((shortcut & Keys.Alt) == Keys.Alt) + return true; + else if ((shortcut & Keys.Widget) == Keys.Widget) + return true; + else if ((shortcut & Keys.Shift) == Keys.Shift) + return true; + + // Anything else is not a shortcut + return false; + } + + [MonoTODO ("Stub, does nothing")] + public static void LoadSettings (Form targetForm) + { + if (targetForm == null) + throw new ArgumentNullException ("targetForm"); + } + + [MonoTODO ("Stub, does nothing")] + public static void LoadSettings (Form targetForm, string key) + { + if (targetForm == null) + throw new ArgumentNullException ("targetForm"); + if (string.IsNullOrEmpty (key)) + throw new ArgumentNullException ("key"); + } + + [MonoLimitation ("Only supports one level of merging, cannot merge the same ToolStrip multiple times")] + public static bool Merge (ToolStrip sourceToolStrip, string targetName) + { + if (string.IsNullOrEmpty (targetName)) + throw new ArgumentNullException ("targetName"); + + return Merge (sourceToolStrip, FindToolStrip (targetName)); + } + + [MonoLimitation ("Only supports one level of merging, cannot merge the same ToolStrip multiple times")] + public static bool Merge (ToolStrip sourceToolStrip, ToolStrip targetToolStrip) + { + // Check for exceptions + if (sourceToolStrip == null) + throw new ArgumentNullException ("sourceToolStrip"); + + if (targetToolStrip == null) + throw new ArgumentNullException ("targetName"); + + if (targetToolStrip == sourceToolStrip) + throw new ArgumentException ("Source and target ToolStrip must be different."); + + // If the toolstrips don't allow merging, don't merge them + if (!sourceToolStrip.AllowMerge || !targetToolStrip.AllowMerge) + return false; + + // We currently can't support merging multiple times + if (sourceToolStrip.IsCurrentlyMerged || targetToolStrip.IsCurrentlyMerged) + return false; + + // What I wouldn't give to be able to modify a collection + // while enumerating through it... + + List items_to_move = new List (); + + // Create a list of every ToolStripItem we plan on moving + foreach (ToolStripItem tsi in sourceToolStrip.Items) { + switch (tsi.MergeAction) { + case MergeAction.Append: + default: + items_to_move.Add (tsi); + break; + case MergeAction.Insert: + if (tsi.MergeIndex >= 0) + items_to_move.Add (tsi); + break; + case MergeAction.Replace: + case MergeAction.Remove: + case MergeAction.MatchOnly: + foreach (ToolStripItem target_tsi in targetToolStrip.Items) + if (tsi.Text == target_tsi.Text) { + items_to_move.Add (tsi); + break; + } + break; + } + } + + // If there was nothing valid to merge, return false + if (items_to_move.Count == 0) + return false; + + // Set some state so we can unmerge later + sourceToolStrip.BeginMerge (); + targetToolStrip.BeginMerge (); + + sourceToolStrip.SuspendLayout (); + targetToolStrip.SuspendLayout (); + + while (items_to_move.Count > 0) { + ToolStripItem tsi = items_to_move[0]; + items_to_move.Remove (tsi); + + switch (tsi.MergeAction) { + case MergeAction.Append: + default: + // Just changing the parent will append it to the target + // and remove it from the source + ToolStrip.SetItemParent (tsi, targetToolStrip); + + break; + case MergeAction.Insert: + // Do the same work as Append, except Insert it into the + // location specified by the MergeIndex + RemoveItemFromParentToolStrip (tsi); + + if (tsi.MergeIndex == -1) + continue; + else if (tsi.MergeIndex >= CountRealToolStripItems (targetToolStrip)) + targetToolStrip.Items.AddNoOwnerOrLayout (tsi); + else + targetToolStrip.Items.InsertNoOwnerOrLayout (AdjustItemMergeIndex (targetToolStrip, tsi), tsi); + + tsi.Parent = targetToolStrip; + + break; + case MergeAction.Replace: + // Find a target ToolStripItem with the same Text, remove it + // and replace it with the source one + foreach (ToolStripItem target_tsi in targetToolStrip.Items) + if (tsi.Text == target_tsi.Text) { + RemoveItemFromParentToolStrip (tsi); + + // Insert where the old one is, then remove the old one + targetToolStrip.Items.InsertNoOwnerOrLayout (targetToolStrip.Items.IndexOf (target_tsi), tsi); + targetToolStrip.Items.RemoveNoOwnerOrLayout (target_tsi); + + // Store the replaced one so we can get it back in unmerge + targetToolStrip.HiddenMergedItems.Add (target_tsi); + break; + } + + break; + case MergeAction.Remove: + // Find a target ToolStripItem with the same Text, and remove + // it from the target, nothing else + foreach (ToolStripItem target_tsi in targetToolStrip.Items) + if (tsi.Text == target_tsi.Text) { + targetToolStrip.Items.RemoveNoOwnerOrLayout (target_tsi); + + // Store the removed one so we can get it back in unmerge + targetToolStrip.HiddenMergedItems.Add (target_tsi); + break; + } + + break; + case MergeAction.MatchOnly: + // Ugh, find the target ToolStripItem with the same Text, and take + // all the subitems from the source one, and append it to the target one + foreach (ToolStripItem target_tsi in targetToolStrip.Items) + if (tsi.Text == target_tsi.Text) { + if (target_tsi is ToolStripMenuItem && tsi is ToolStripMenuItem) { + ToolStripMenuItem source = (ToolStripMenuItem)tsi; + ToolStripMenuItem target = (ToolStripMenuItem)target_tsi; + + ToolStripManager.Merge (source.DropDown, target.DropDown); + } + + break; + } + + break; + } + } + + sourceToolStrip.ResumeLayout (); + targetToolStrip.ResumeLayout (); + + // Store who we merged with, so we can unmerge when only given the target toolstrip + sourceToolStrip.CurrentlyMergedWith = targetToolStrip; + targetToolStrip.CurrentlyMergedWith = sourceToolStrip; + + return true; + } + + public static bool RevertMerge (string targetName) + { + return RevertMerge (FindToolStrip (targetName)); + } + + public static bool RevertMerge (ToolStrip targetToolStrip) + { + if (targetToolStrip == null) + return false; + + return RevertMerge (targetToolStrip, targetToolStrip.CurrentlyMergedWith); + } + + public static bool RevertMerge (ToolStrip targetToolStrip, ToolStrip sourceToolStrip) + { + if (sourceToolStrip == null) + return false; + + List items_to_move = new List (); + + // Find every ToolStripItem who's Owner is the source toolstrip + // - If it's a TSMI, see if any of the subitems need to be moved back + foreach (ToolStripItem tsi in targetToolStrip.Items) { + if (tsi.Owner == sourceToolStrip) + items_to_move.Add (tsi); + else if (tsi is ToolStripMenuItem) + foreach (ToolStripItem menuitem in (tsi as ToolStripMenuItem).DropDownItems) + foreach (ToolStripMenuItem tsmi in sourceToolStrip.Items) + if (menuitem.Owner == tsmi.DropDown) + items_to_move.Add (menuitem); + } + + // If we didn't find anything, return false + if (items_to_move.Count == 0 && targetToolStrip.HiddenMergedItems.Count == 0) + return false; + + // Put back all the target's items removed in the merge + while (targetToolStrip.HiddenMergedItems.Count > 0) { + targetToolStrip.RevertMergeItem (targetToolStrip.HiddenMergedItems[0]); + targetToolStrip.HiddenMergedItems.RemoveAt (0); + } + + sourceToolStrip.SuspendLayout (); + targetToolStrip.SuspendLayout (); + + // Revert everything + while (items_to_move.Count > 0) { + sourceToolStrip.RevertMergeItem (items_to_move[0]); + items_to_move.Remove (items_to_move[0]); + } + + sourceToolStrip.ResumeLayout (); + targetToolStrip.ResumeLayout (); + + sourceToolStrip.IsCurrentlyMerged = false; + targetToolStrip.IsCurrentlyMerged = false; + + sourceToolStrip.CurrentlyMergedWith = null; + targetToolStrip.CurrentlyMergedWith = null; + + return true; + } + + public static void SaveSettings (Form sourceForm) + { + if (sourceForm == null) + throw new ArgumentNullException ("sourceForm"); + } + + public static void SaveSettings (Form sourceForm, string key) + { + if (sourceForm == null) + throw new ArgumentNullException ("sourceForm"); + if (string.IsNullOrEmpty (key)) + throw new ArgumentNullException ("key"); + } + #endregion + + #region Public Events + public static event EventHandler RendererChanged; + #endregion + + #region Private/Internal Methods + internal static bool ActivatedByKeyboard { + get { return activated_by_keyboard; } + set { activated_by_keyboard = value; } + } + + internal static void AddToolStrip (ToolStrip ts) + { + lock (toolstrips) + toolstrips.Add (new WeakReference (ts)); + } + + // When we have merged in MDI items like the min/max/close buttons, we + // can't count them for the sake of menu merging or it will mess up + // where people are trying to put them + private static int AdjustItemMergeIndex (ToolStrip ts, ToolStripItem tsi) + { + if (ts.Items[0] is MdiWidgetStrip.SystemMenuItem) + return tsi.MergeIndex + 1; + + return tsi.MergeIndex; + } + + private static int CountRealToolStripItems (ToolStrip ts) + { + int count = 0; + + foreach (ToolStripItem tsi in ts.Items) + if (!(tsi is MdiWidgetStrip.WidgetBoxMenuItem) && !(tsi is MdiWidgetStrip.SystemMenuItem)) + count++; + + return count; + } + + internal static ToolStrip GetNextToolStrip (ToolStrip ts, bool forward) + { + lock (toolstrips) { + List tools = new List (); + + foreach (WeakReference wr in toolstrips) { + ToolStrip t = (ToolStrip)wr.Target; + + if (t != null) + tools.Add (t); + } + + int index = tools.IndexOf (ts); + + if (forward) { + // Look for any toolstrip after this one in the collection + for (int i = index + 1; i < tools.Count; i++) + if (tools[i].TopLevelWidget == ts.TopLevelWidget && !(tools[i] is StatusStrip)) + return tools[i]; + + // Look for any toolstrip before this one in the collection + for (int i = 0; i < index; i++) + if (tools[i].TopLevelWidget == ts.TopLevelWidget && !(tools[i] is StatusStrip)) + return tools[i]; + } else { + // Look for any toolstrip before this one in the collection + for (int i = index - 1; i >= 0; i--) + if (tools[i].TopLevelWidget == ts.TopLevelWidget && !(tools[i] is StatusStrip)) + return tools[i]; + + // Look for any toolstrip after this one in the collection + for (int i = tools.Count - 1; i > index; i--) + if (tools[i].TopLevelWidget == ts.TopLevelWidget && !(tools[i] is StatusStrip)) + return tools[i]; + } + } + + return null; + } + + internal static bool ProcessCmdKey (ref Message m, Keys keyData) + { + lock (menu_items) + foreach (ToolStripMenuItem tsmi in menu_items) + if (tsmi.ProcessCmdKey (ref m, keyData) == true) + return true; + + return false; + } + + internal static bool ProcessMenuKey (ref Message m) + { + // If we have a currently active menu, deactivate it + if (Application.KeyboardCapture != null) { + if (Application.KeyboardCapture.OnMenuKey ()) + return true; + } + + // Get the parent form of this message + Form f = (Form)Widget.FromHandle (m.HWnd).TopLevelWidget; + + // If there isn't a Form with this, there isn't much we can do + if (f == null) + return false; + + // Check the MainMenuStrip property first + if (f.MainMenuStrip != null) + if (f.MainMenuStrip.OnMenuKey ()) + return true; + + // Look for any MenuStrip in the form + lock (toolstrips) + foreach (WeakReference wr in toolstrips) { + ToolStrip ts = (ToolStrip)wr.Target; + + if (ts == null) + continue; + + if (ts.TopLevelWidget == f) + if (ts.OnMenuKey ()) + return true; + } + + return false; + } + + internal static void SetActiveToolStrip (ToolStrip toolStrip, bool keyboard) + { + if (Application.KeyboardCapture != null) + Application.KeyboardCapture.KeyboardActive = false; + + if (toolStrip == null) { + activated_by_keyboard = false; + return; + } + + activated_by_keyboard = keyboard; + + toolStrip.KeyboardActive = true; + } + + internal static void AddToolStripMenuItem (ToolStripMenuItem tsmi) + { + lock (menu_items) + menu_items.Add (tsmi); + } + + internal static void RemoveToolStrip (ToolStrip ts) + { + lock (toolstrips) { + foreach (WeakReference wr in toolstrips) + if (wr.Target == ts) { + toolstrips.Remove (wr); + return; + } + } + } + + internal static void RemoveToolStripMenuItem (ToolStripMenuItem tsmi) + { + lock (menu_items) + menu_items.Remove (tsmi); + } + + internal static void FireAppClicked () + { + if (AppClicked != null) AppClicked (null, EventArgs.Empty); + + if (Application.KeyboardCapture != null) + Application.KeyboardCapture.Dismiss (ToolStripDropDownCloseReason.AppClicked); + } + + internal static void FireAppFocusChanged (Form form) + { + if (AppFocusChange != null) AppFocusChange (form, EventArgs.Empty); + + if (Application.KeyboardCapture != null) + Application.KeyboardCapture.Dismiss (ToolStripDropDownCloseReason.AppFocusChange); + } + + internal static void FireAppFocusChanged (object sender) + { + if (AppFocusChange != null) AppFocusChange (sender, EventArgs.Empty); + + if (Application.KeyboardCapture != null) + Application.KeyboardCapture.Dismiss (ToolStripDropDownCloseReason.AppFocusChange); + } + + private static void OnRendererChanged (EventArgs e) + { + if (RendererChanged != null) RendererChanged (null, e); + } + + private static void RemoveItemFromParentToolStrip (ToolStripItem tsi) + { + if (tsi.Owner != null) { + tsi.Owner.Items.RemoveNoOwnerOrLayout (tsi); + + if (tsi.Owner is ToolStripOverflow) + (tsi.Owner as ToolStripOverflow).ParentToolStrip.Items.RemoveNoOwnerOrLayout (tsi); + } + } + + internal static event EventHandler AppClicked; + internal static event EventHandler AppFocusChange; + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripManagerRenderMode.cs b/source/ShiftUI/ToolStrip/ToolStripManagerRenderMode.cs new file mode 100644 index 0000000..d8f008b --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripManagerRenderMode.cs @@ -0,0 +1,41 @@ +// +// ToolStripManagerRenderMode.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.ComponentModel; + +namespace ShiftUI +{ + public enum ToolStripManagerRenderMode + { + [Browsable (false)] + Custom = 0, + + System = 1, + Professional = 2 + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripMenuItem.cs b/source/ShiftUI/ToolStrip/ToolStripMenuItem.cs new file mode 100644 index 0000000..1b83dee --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripMenuItem.cs @@ -0,0 +1,548 @@ +// +// ToolStripMenuItem.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Drawing; +using System.ComponentModel; +using ShiftUI.Design; +using System.ComponentModel.Design.Serialization; + +namespace ShiftUI +{ + [ToolStripItemDesignerAvailability (ToolStripItemDesignerAvailability.MenuStrip | ToolStripItemDesignerAvailability.ContextMenuStrip)] + //[DesignerSerializer ("ShiftUI.Design.ToolStripMenuItemCodeDomSerializer, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)] + public class ToolStripMenuItem : ToolStripDropDownItem + { + private CheckState checked_state; + private bool check_on_click; + private bool close_on_mouse_release; + private string shortcut_display_string; + private Keys shortcut_keys = Keys.None; + private bool show_shortcut_keys = true; + private Form mdi_client_form; + + #region Public Constructors + public ToolStripMenuItem () + : this (null, null, null, string.Empty) + { + } + + public ToolStripMenuItem (Image image) + : this (null, image, null, string.Empty) + { + } + + public ToolStripMenuItem (string text) + : this (text, null, null, string.Empty) + { + } + + public ToolStripMenuItem (string text, Image image) + : this (text, image, null, string.Empty) + { + } + + public ToolStripMenuItem (string text, Image image, EventHandler onClick) + : this (text, image, onClick, string.Empty) + { + } + + public ToolStripMenuItem (string text, Image image, params ToolStripItem[] dropDownItems) + : this (text, image, null, string.Empty) + { + if (dropDownItems != null) + foreach (ToolStripItem tsi in dropDownItems) + this.DropDownItems.Add (tsi); + } + + public ToolStripMenuItem (string text, Image image, EventHandler onClick, Keys shortcutKeys) + : this (text, image, onClick, string.Empty) + { + } + + public ToolStripMenuItem (string text, Image image, EventHandler onClick, string name) + : base (text, image, onClick, name) + { + base.Overflow = ToolStripItemOverflow.Never; + } + #endregion + + #region Public Properties + [Bindable (true)] + [DefaultValue (false)] + [RefreshProperties (RefreshProperties.All)] + public bool Checked { + get { + switch (this.checked_state) { + case CheckState.Unchecked: + default: + return false; + case CheckState.Checked: + case CheckState.Indeterminate: + return true; + } + } + set { + CheckState = value ? CheckState.Checked : CheckState.Unchecked; + } + } + + [DefaultValue (false)] + public bool CheckOnClick { + get { return this.check_on_click; } + set { + if (this.check_on_click != value) { + this.check_on_click = value; + OnUIACheckOnClickChangedEvent (EventArgs.Empty); + } + } + } + + [Bindable (true)] + [DefaultValue (CheckState.Unchecked)] + [RefreshProperties (RefreshProperties.All)] + public CheckState CheckState { + get { return this.checked_state; } + set + { + if (!Enum.IsDefined (typeof (CheckState), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for CheckState", value)); + + if (value == checked_state) + return; + + this.checked_state = value; + this.Invalidate (); + this.OnCheckedChanged (EventArgs.Empty); + this.OnCheckStateChanged (EventArgs.Empty); + } + } + + public override bool Enabled { + get { return base.Enabled; } + set { base.Enabled = value; } + } + + [Browsable (false)] + public bool IsMdiWindowListEntry { + get { return this.mdi_client_form != null; } + } + + [DefaultValue (ToolStripItemOverflow.Never)] + public new ToolStripItemOverflow Overflow { + get { return base.Overflow; } + set { base.Overflow = value; } + } + + [Localizable (true)] + [DefaultValue (true)] + public bool ShowShortcutKeys { + get { return this.show_shortcut_keys; } + set { this.show_shortcut_keys = value; } + } + + [Localizable (true)] + [DefaultValue (null)] + public string ShortcutKeyDisplayString { + get { return this.shortcut_display_string; } + set { this.shortcut_display_string = value; } + } + + [Localizable (true)] + [DefaultValue (Keys.None)] + public Keys ShortcutKeys { + get { return this.shortcut_keys; } + set { + if (this.shortcut_keys != value) { + this.shortcut_keys = value; + + if (this.Parent != null) + ToolStripManager.AddToolStripMenuItem (this); + } + } + } + #endregion + + #region Protected Properties + protected internal override Padding DefaultMargin { + get { return new Padding (0); } + } + + protected override Padding DefaultPadding { + get { return new Padding (4, 0, 4, 0); } + } + + protected override Size DefaultSize { + get { return new Size (32, 19); } + } + #endregion + + #region Protected Methods + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override AccessibleObject CreateAccessibilityInstance () + { + return new ToolStripMenuItemAccessibleObject (); + } + + protected override ToolStripDropDown CreateDefaultDropDown () + { + ToolStripDropDownMenu tsddm = new ToolStripDropDownMenu (); + tsddm.OwnerItem = this; + return tsddm; + } + + protected override void Dispose (bool disposing) + { + base.Dispose (disposing); + } + + protected virtual void OnCheckedChanged (EventArgs e) + { + EventHandler eh = (EventHandler)Events [CheckedChangedEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnCheckStateChanged (EventArgs e) + { + EventHandler eh = (EventHandler)Events [CheckStateChangedEvent]; + if (eh != null) + eh (this, e); + } + + protected override void OnClick (EventArgs e) + { + if (!this.Enabled) + return; + + if (this.HasDropDownItems) { + base.OnClick (e); + return; + } + + if (this.OwnerItem is ToolStripDropDownItem) + (this.OwnerItem as ToolStripDropDownItem).OnDropDownItemClicked (new ToolStripItemClickedEventArgs (this)); + + if (this.IsOnDropDown) { + ToolStrip ts = this.GetTopLevelToolStrip (); + + if (ts != null) + ts.Dismiss (ToolStripDropDownCloseReason.ItemClicked); + } + + if (this.IsMdiWindowListEntry) { + this.mdi_client_form.MdiParent.MdiContainer.ActivateChild (this.mdi_client_form); + return; + } + + if (this.check_on_click) + this.Checked = !this.Checked; + + base.OnClick (e); + + if (!this.IsOnDropDown && !this.HasDropDownItems) { + ToolStrip ts = this.GetTopLevelToolStrip (); + + if (ts != null) + ts.Dismiss (ToolStripDropDownCloseReason.ItemClicked); + } + } + + protected override void OnDropDownHide (EventArgs e) + { + base.OnDropDownHide (e); + } + + protected override void OnDropDownShow (EventArgs e) + { + base.OnDropDownShow (e); + } + + protected override void OnFontChanged (EventArgs e) + { + base.OnFontChanged (e); + } + + protected override void OnMouseDown (MouseEventArgs e) + { + if (!this.IsOnDropDown && this.HasDropDownItems && this.DropDown.Visible) + this.close_on_mouse_release = true; + + if (Enabled && !this.DropDown.Visible) + this.ShowDropDown (); + + base.OnMouseDown (e); + } + + protected override void OnMouseEnter (EventArgs e) + { + if (this.IsOnDropDown && this.HasDropDownItems && Enabled) + this.ShowDropDown (); + + base.OnMouseEnter (e); + } + + protected override void OnMouseLeave (EventArgs e) + { + base.OnMouseLeave (e); + } + + protected override void OnMouseUp (MouseEventArgs e) + { + if (this.close_on_mouse_release) { + this.Parent.Dismiss (ToolStripDropDownCloseReason.ItemClicked); + this.Invalidate (); + this.close_on_mouse_release = false; + } + + if (!this.HasDropDownItems && Enabled) + base.OnMouseUp (e); + } + + protected override void OnOwnerChanged (EventArgs e) + { + base.OnOwnerChanged (e); + } + + protected override void OnPaint (ShiftUI.PaintEventArgs e) + { + base.OnPaint (e); + + // Can't render without an owner + if (this.Owner == null) + return; + + // If DropDown.ShowImageMargin is false, we don't display the image + Image draw_image = this.UseImageMargin ? this.Image : null; + + // Disable this color detection until we do the color detection for ToolStrip *completely* + // Color font_color = this.ForeColor == SystemColors.ControlText ? SystemColors.MenuText : this.ForeColor; + Color font_color = ForeColor; + + if ((this.Selected || this.Pressed) && this.IsOnDropDown && font_color == SystemColors.MenuText) + font_color = SystemColors.HighlightText; + + if (!this.Enabled && this.ForeColor == SystemColors.ControlText) + font_color = SystemColors.GrayText; + + // Gray stuff out if we're disabled + draw_image = this.Enabled ? draw_image : ToolStripRenderer.CreateDisabledImage (draw_image); + + // Draw our background + this.Owner.Renderer.DrawMenuItemBackground (new ToolStripItemRenderEventArgs (e.Graphics, this)); + + // Figure out where our text and image go + Rectangle text_layout_rect; + Rectangle image_layout_rect; + + this.CalculateTextAndImageRectangles (out text_layout_rect, out image_layout_rect); + + if (this.IsOnDropDown) { + if (!this.UseImageMargin) { + image_layout_rect = Rectangle.Empty; + text_layout_rect = new Rectangle (8, text_layout_rect.Top, text_layout_rect.Width, text_layout_rect.Height); + } else { + text_layout_rect = new Rectangle (35, text_layout_rect.Top, text_layout_rect.Width, text_layout_rect.Height); + + if (image_layout_rect != Rectangle.Empty) + image_layout_rect = new Rectangle (new Point (4, 3), base.GetImageSize ()); + } + + if (this.Checked && this.ShowMargin) + this.Owner.Renderer.DrawItemCheck (new ToolStripItemImageRenderEventArgs (e.Graphics, this, new Rectangle (2, 1, 19, 19))); + } + if (text_layout_rect != Rectangle.Empty) + this.Owner.Renderer.DrawItemText (new ToolStripItemTextRenderEventArgs (e.Graphics, this, this.Text, text_layout_rect, font_color, this.Font, this.TextAlign)); + + string key_string = GetShortcutDisplayString (); + + if (!string.IsNullOrEmpty (key_string) && !this.HasDropDownItems) { + int offset = 15; + Size key_string_size = TextRenderer.MeasureText (key_string, this.Font); + Rectangle key_string_rect = new Rectangle (this.ContentRectangle.Right - key_string_size.Width - offset, text_layout_rect.Top, key_string_size.Width, text_layout_rect.Height); + this.Owner.Renderer.DrawItemText (new ToolStripItemTextRenderEventArgs (e.Graphics, this, key_string, key_string_rect, font_color, this.Font, this.TextAlign)); + } + + if (image_layout_rect != Rectangle.Empty) + this.Owner.Renderer.DrawItemImage (new ToolStripItemImageRenderEventArgs (e.Graphics, this, draw_image, image_layout_rect)); + + if (this.IsOnDropDown && this.HasDropDownItems && this.Parent is ToolStripDropDownMenu) + this.Owner.Renderer.DrawArrow (new ToolStripArrowRenderEventArgs (e.Graphics, this, new Rectangle (this.Bounds.Width - 17, 2, 10, 20), Color.Black, ArrowDirection.Right)); + + return; + } + + protected internal override bool ProcessCmdKey (ref Message m, Keys keyData) + { + Widget source = Widget.FromHandle (m.HWnd); + Form f = source == null ? null : (Form)source.TopLevelWidget; + + if (this.Enabled && keyData == this.shortcut_keys && GetTopLevelWidget () == f) { + this.FireEvent (EventArgs.Empty, ToolStripItemEventType.Click); + return true; + } + + return base.ProcessCmdKey (ref m, keyData); + } + + Widget GetTopLevelWidget () + { + ToolStripItem item = this; + while (item.OwnerItem != null) + item = item.OwnerItem; + + if (item.Owner == null) + return null; + + if (item.Owner is ContextMenuStrip) { + Widget container = ((ContextMenuStrip)item.Owner).container; + return container == null ? null : container.TopLevelWidget; + } + + // MainMenuStrip + return item.Owner.TopLevelWidget; + } + + protected internal override bool ProcessMnemonic (char charCode) + { + if (!this.Selected) + this.Parent.ChangeSelection (this); + + if (this.HasDropDownItems) { + ToolStripManager.SetActiveToolStrip (this.Parent, true); + this.ShowDropDown (); + this.DropDown.SelectNextToolStripItem (null, true); + } else + this.PerformClick (); + + return true; + } + + protected internal override void SetBounds (Rectangle rect) + { + base.SetBounds (rect); + } + #endregion + + #region Public Events + static object CheckedChangedEvent = new object (); + static object CheckStateChangedEvent = new object (); + + public event EventHandler CheckedChanged { + add { Events.AddHandler (CheckedChangedEvent, value); } + remove {Events.RemoveHandler (CheckedChangedEvent, value); } + } + + public event EventHandler CheckStateChanged { + add { Events.AddHandler (CheckStateChangedEvent, value); } + remove {Events.RemoveHandler (CheckStateChangedEvent, value); } + } + #endregion + + #region UIA Framework Events + static object UIACheckOnClickChangedEvent = new object (); + + internal event EventHandler UIACheckOnClickChanged { + add { Events.AddHandler (UIACheckOnClickChangedEvent, value); } + remove { Events.RemoveHandler (UIACheckOnClickChangedEvent, value); } + } + + internal void OnUIACheckOnClickChangedEvent (EventArgs args) + { + EventHandler eh + = (EventHandler) Events [UIACheckOnClickChangedEvent]; + if (eh != null) + eh (this, args); + } + #endregion + + #region Internal Properties + internal Form MdiClientForm { + get { return this.mdi_client_form; } + set { this.mdi_client_form = value; } + } + #endregion + + #region Internal Methods + internal override Size CalculatePreferredSize (Size constrainingSize) + { + Size base_size = base.CalculatePreferredSize (constrainingSize); + + string key_string = GetShortcutDisplayString (); + + if (string.IsNullOrEmpty (key_string)) + return base_size; + + Size text_size = TextRenderer.MeasureText (key_string, this.Font); + + return new Size (base_size.Width + text_size.Width - 25, base_size.Height); + } + + internal string GetShortcutDisplayString () + { + if (this.show_shortcut_keys == false) + return string.Empty; + if (this.Parent == null || !(this.Parent is ToolStripDropDownMenu)) + return string.Empty; + + string key_string = string.Empty; + + if (!string.IsNullOrEmpty (this.shortcut_display_string)) + key_string = this.shortcut_display_string; + else if (this.shortcut_keys != Keys.None) { + KeysConverter kc = new KeysConverter (); + key_string = kc.ConvertToString (this.shortcut_keys); + } + + return key_string; + } + + internal void HandleAutoExpansion () + { + if (this.HasDropDownItems) { + this.ShowDropDown (); + this.DropDown.SelectNextToolStripItem (null, true); + } + } + + internal override void HandleClick (int mouse_clicks, EventArgs e) + { + this.OnClick (e); + + if (Parent != null) + Parent.Invalidate (); + } + #endregion + + #region ToolStripMenuItemAccessibleObject + private class ToolStripMenuItemAccessibleObject : AccessibleObject + { + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripOverflow.cs b/source/ShiftUI/ToolStrip/ToolStripOverflow.cs new file mode 100644 index 0000000..3e8fd92 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripOverflow.cs @@ -0,0 +1,151 @@ +// +// ToolStripOverflow.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Runtime.InteropServices; +using System.ComponentModel; +using System.Drawing; +using ShiftUI.Layout; + +namespace ShiftUI +{ + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + public class ToolStripOverflow : ToolStripDropDown, IComponent, IDisposable + { + private LayoutEngine layout_engine; + + #region Public Constructors + public ToolStripOverflow (ToolStripItem parentItem) + { + this.OwnerItem = parentItem; + } + #endregion + + #region Public Properties + // XXX - This probably adds ToolStripOverflowButton to the returned collection + public override ToolStripItemCollection Items { + get { return base.Items; } + } + + public override LayoutEngine LayoutEngine { + get { + if (this.layout_engine == null) + this.layout_engine = new FlowLayout (); + + return base.LayoutEngine; + } + } + #endregion + + #region Protected Properties + protected internal override ToolStripItemCollection DisplayedItems { + get { return base.DisplayedItems; } + } + #endregion + + #region Public Methods + public override Size GetPreferredSize (Size constrainingSize) + { + return base.GetToolStripPreferredSize (constrainingSize); + } + #endregion + + #region Protected Methods + protected override AccessibleObject CreateAccessibilityInstance () + { + return new ToolStripOverflowAccessibleObject (); + } + + [MonoInternalNote ("This should stack in rows of ~3, but for now 1 column will work.")] + protected override void OnLayout (LayoutEventArgs e) + { + SetDisplayedItems (); + + // Find the widest menu item + int widest = 0; + + foreach (ToolStripItem tsi in this.DisplayedItems) { + if (!tsi.Available) + continue; + if (tsi.GetPreferredSize (Size.Empty).Width > widest) + widest = tsi.GetPreferredSize (Size.Empty).Width; + } + + int x = this.Padding.Left; + widest += this.Padding.Horizontal; + int y = this.Padding.Top; + + foreach (ToolStripItem tsi in this.DisplayedItems) { + if (!tsi.Available) + continue; + + y += tsi.Margin.Top; + + int height = 0; + + if (tsi is ToolStripSeparator) + height = 7; + else + height = tsi.GetPreferredSize (Size.Empty).Height; + + tsi.SetBounds (new Rectangle (x, y, widest, height)); + y += tsi.Height + tsi.Margin.Bottom; + } + + this.Size = new Size (widest + this.Padding.Horizontal, y + this.Padding.Bottom);// + 2); + } + + protected override void SetDisplayedItems () + { + this.displayed_items.ClearInternal (); + + if (this.OwnerItem != null && this.OwnerItem.Parent != null) + foreach (ToolStripItem tsi in this.OwnerItem.Parent.Items) + if (tsi.Placement == ToolStripItemPlacement.Overflow && tsi.Available && !(tsi is ToolStripSeparator)) { + this.displayed_items.AddNoOwnerOrLayout (tsi); + //tsi.Parent = this; + } + + this.PerformLayout (); + } + #endregion + + #region Internal Methods + internal ToolStrip ParentToolStrip { + get { return (ToolStrip)this.OwnerItem.Parent; } + } + #endregion + + #region ToolStripOverflowAccessibleObject Class + private class ToolStripOverflowAccessibleObject : AccessibleObject + { + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripOverflowButton.cs b/source/ShiftUI/ToolStrip/ToolStripOverflowButton.cs new file mode 100644 index 0000000..f9415ed --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripOverflowButton.cs @@ -0,0 +1,113 @@ +// +// ToolStripOverflowButton.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2007 Novell +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Runtime.InteropServices; +using System.ComponentModel; +using System.Drawing; +using ShiftUI.Design; + +namespace ShiftUI +{ + [ToolStripItemDesignerAvailability (ToolStripItemDesignerAvailability.None)] + public class ToolStripOverflowButton : ToolStripDropDownButton + { + #region Internal Constructor + internal ToolStripOverflowButton (ToolStrip ts) + { + this.InternalOwner = ts; + this.Parent = ts; + this.Visible = false; + } + #endregion + + #region Public Properties + public override bool HasDropDownItems { + get { + if (this.drop_down == null) + return false; + + return this.DropDown.DisplayedItems.Count > 0; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new bool RightToLeftAutoMirrorImage { + get { return base.RightToLeftAutoMirrorImage; } + set { base.RightToLeftAutoMirrorImage = value; } + } + #endregion + + #region Protected Properties + protected internal override Padding DefaultMargin { + get { return new Padding (0, 1, 0, 2); } + } + #endregion + + #region Public Methods + public override Size GetPreferredSize (Size constrainingSize) + { + return new Size (16, this.Parent.Height); + } + #endregion + + #region Protected Methods + protected override AccessibleObject CreateAccessibilityInstance () + { + return new ToolStripOverflowButtonAccessibleObject (); + } + + protected override ToolStripDropDown CreateDefaultDropDown () + { + ToolStripDropDown tsdd = new ToolStripOverflow (this); + tsdd.DefaultDropDownDirection = ToolStripDropDownDirection.BelowLeft; + tsdd.OwnerItem = this; + return tsdd; + } + + protected override void OnPaint (PaintEventArgs e) + { + if (this.Owner != null) + this.Owner.Renderer.DrawOverflowButtonBackground (new ToolStripItemRenderEventArgs (e.Graphics, this)); + } + + protected internal override void SetBounds (Rectangle bounds) + { + base.SetBounds (bounds); + } + #endregion + + #region ToolStripOverflowButtonAccessibleObject Class + private class ToolStripOverflowButtonAccessibleObject : AccessibleObject + { + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripPanel.cs b/source/ShiftUI/ToolStrip/ToolStripPanel.cs new file mode 100644 index 0000000..86def53 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripPanel.cs @@ -0,0 +1,618 @@ +// +// ToolStripPanel.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +using System.Collections; +using System.ComponentModel; +using System.Drawing; +using System.Runtime.InteropServices; +using ShiftUI.Layout; +using System; + +namespace ShiftUI +{ + [ComVisible (true)] + [ToolboxBitmap ("")] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + //[Designer ("ShiftUI.Design.ToolStripPanelDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + public class ToolStripPanel : ContainerWidget, IComponent, IDisposable, IBindableComponent, IDropTarget + { + private bool done_first_layout; + private LayoutEngine layout_engine; + private bool locked; + private Orientation orientation; + private ToolStripRenderer renderer; + private ToolStripRenderMode render_mode; + private Padding row_margin; + private ToolStripPanelRowCollection rows; + + public ToolStripPanel () : base () + { + base.AutoSize = true; + this.locked = false; + this.renderer = null; + this.render_mode = ToolStripRenderMode.ManagerRenderMode; + this.row_margin = new Padding (3, 0, 0, 0); + this.rows = new ToolStripPanelRowCollection (this); + } + + #region Public Properties + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override bool AllowDrop { + get { return base.AllowDrop; } + set { base.AllowDrop = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override bool AutoScroll { + get { return base.AutoScroll; } + set { base.AutoScroll = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Size AutoScrollMargin { + get { return base.AutoScrollMargin; } + set { base.AutoScrollMargin = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Size AutoScrollMinSize { + get { return base.AutoScrollMinSize; } + set { base.AutoScrollMinSize = value; } + } + + [DefaultValue (true)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)] + public override bool AutoSize { + get { return base.AutoSize; } + set { base.AutoSize = value; } + } + + public override DockStyle Dock { + get { return base.Dock; } + set { + base.Dock = value; + + switch (value) { + case DockStyle.Top: + case DockStyle.Bottom: + case DockStyle.None: + this.orientation = Orientation.Horizontal; + break; + case DockStyle.Left: + case DockStyle.Right: + this.orientation = Orientation.Vertical; + break; + } + } + } + + public override LayoutEngine LayoutEngine { + get { + if (this.layout_engine == null) + this.layout_engine = new FlowLayout (); + + return this.layout_engine; + } + } + + [Browsable (false)] + [DefaultValue (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public bool Locked { + get { return this.locked; } + set { this.locked = value; } + } + + public Orientation Orientation { + get { return this.orientation; } + set { this.orientation = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public ToolStripRenderer Renderer { + get { + if (this.render_mode == ToolStripRenderMode.ManagerRenderMode) + return ToolStripManager.Renderer; + + return this.renderer; + } + set { + if (this.renderer != value) { + this.renderer = value; + this.render_mode = ToolStripRenderMode.Custom; + this.OnRendererChanged (EventArgs.Empty); + } + } + } + + public ToolStripRenderMode RenderMode { + get { return this.render_mode; } + set { + if (!Enum.IsDefined (typeof (ToolStripRenderMode), value)) + throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripRenderMode", value)); + + if (value == ToolStripRenderMode.Custom && this.renderer == null) + throw new NotSupportedException ("Must set Renderer property before setting RenderMode to Custom"); + if (value == ToolStripRenderMode.Professional || value == ToolStripRenderMode.System) + this.Renderer = new ToolStripProfessionalRenderer (); + + this.render_mode = value; + } + } + + public Padding RowMargin { + get { return this.row_margin; } + set { this.row_margin = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public ToolStripPanelRow[] Rows { + get { + ToolStripPanelRow[] retval = new ToolStripPanelRow [this.rows.Count]; + this.rows.CopyTo (retval, 0); + return retval; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new int TabIndex { + get { return base.TabIndex; } + set { base.TabIndex = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new bool TabStop { + get { return base.TabStop; } + set { base.TabStop = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override string Text { + get { return base.Text; } + set { base.Text = value; } + } + #endregion + + #region Protected Properties + protected override Padding DefaultMargin { + get { return new Padding (0); } + } + + protected override Padding DefaultPadding { + get { return new Padding (0); } + } + #endregion + + #region Public Methods + public void BeginInit () + { + } + + public void EndInit () + { + } + + [MonoTODO("Not implemented")] + public void Join (ToolStrip toolStripToDrag) + { + if (!Contains (toolStripToDrag)) + Widgets.Add (toolStripToDrag); + } + + [MonoTODO("Not implemented")] + public void Join (ToolStrip toolStripToDrag, int row) + { + Join (toolStripToDrag); + } + + [MonoTODO("Not implemented")] + public void Join (ToolStrip toolStripToDrag, Point location) + { + Join (toolStripToDrag); + } + + [MonoTODO("Not implemented")] + public void Join (ToolStrip toolStripToDrag, int x, int y) + { + Join (toolStripToDrag); + } + + public ToolStripPanelRow PointToRow (Point clientLocation) + { + foreach (ToolStripPanelRow row in this.rows) + if (row.Bounds.Contains (clientLocation)) + return row; + + return null; + } + #endregion + + #region Protected Methods + protected override WidgetCollection CreateWidgetsInstance () + { + return new ToolStripPanelWidgetCollection (this); + } + + protected override void Dispose (bool disposing) + { + base.Dispose (disposing); + } + + protected override void OnWidgetAdded (WidgetEventArgs e) + { + if (this.Dock == DockStyle.Left || this.Dock == DockStyle.Right) + (e.Widget as ToolStrip).LayoutStyle = ToolStripLayoutStyle.VerticalStackWithOverflow; + else + (e.Widget as ToolStrip).LayoutStyle = ToolStripLayoutStyle.HorizontalStackWithOverflow; + + if (done_first_layout && e.Widget is ToolStrip) + this.AddWidgetToRows (e.Widget); + + base.OnWidgetAdded (e); + } + + protected override void OnWidgetRemoved (WidgetEventArgs e) + { + base.OnWidgetRemoved (e); + + foreach (ToolStripPanelRow row in this.rows) + if (row.Widgets.Contains (e.Widget)) + row.OnWidgetRemoved (e.Widget, 0); + } + + protected override void OnDockChanged (EventArgs e) + { + base.OnDockChanged (e); + } + + protected override void OnLayout (LayoutEventArgs e) + { + // Don't see any reason to layout if we aren't created + if (!this.Created) + return; + + // The first time through, we have to layout everything where it belongs. + // The key is that when we resize and stuff, we don't resize or move toolstrips. + if (!done_first_layout) { + ArrayList al = new ArrayList (this.Widgets); + al.Sort (new TabIndexComparer ()); + + foreach (ToolStrip ts in al) + this.AddWidgetToRows (ts); + + done_first_layout = true; + } + + // Lay out all the rows + Point position = this.DisplayRectangle.Location; + + if (this.Dock == DockStyle.Left || this.Dock == DockStyle.Right) { + foreach (ToolStripPanelRow row in this.rows) { + row.SetBounds (new Rectangle (position, new Size (row.Bounds.Width, this.Height))); + + position.X += row.Bounds.Width; + } + + // Find how big we are so we can autosize ourself + if (this.rows.Count > 0) { + int last_row_right = this.rows[this.rows.Count - 1].Bounds.Right; + + if (last_row_right != this.Width) + this.SetBounds (bounds.X, bounds.Y, last_row_right, bounds.Bottom); + } + } else { + foreach (ToolStripPanelRow row in this.rows) { + row.SetBounds (new Rectangle (position, new Size (this.Width, row.Bounds.Height))); + + position.Y += row.Bounds.Height; + } + + // Find how big we are so we can autosize ourself + if (this.rows.Count > 0) { + int last_row_bottom = this.rows[this.rows.Count - 1].Bounds.Bottom; + + if (last_row_bottom != this.Height) + this.SetBounds (bounds.X, bounds.Y, bounds.Width, last_row_bottom); + } + } + + this.Invalidate (); + + return; + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void OnPaintBackground (PaintEventArgs e) + { + base.OnPaintBackground (e); + + this.Renderer.DrawToolStripPanelBackground (new ToolStripPanelRenderEventArgs (e.Graphics, this)); + } + + protected override void OnParentChanged (EventArgs e) + { + base.OnParentChanged (e); + } + + protected virtual void OnRendererChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [RendererChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnRightToLeftChanged (EventArgs e) + { + base.OnRightToLeftChanged (e); + } + #endregion + + #region Public Events + static object RendererChangedEvent = new object (); + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler AutoSizeChanged { + add { base.AutoSizeChanged += value; } + remove { base.AutoSizeChanged -= value; } + } + + public event EventHandler RendererChanged { + add { Events.AddHandler (RendererChangedEvent, value); } + remove { Events.RemoveHandler (RendererChangedEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TabIndexChanged { + add { base.TabIndexChanged += value; } + remove { base.TabIndexChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TabStopChanged { + add { base.TabStopChanged += value; } + remove { base.TabStopChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + #endregion + + #region Private Methods + + private void AddWidgetToRows (Widget Widget) + { + if (this.rows.Count > 0) + if (this.rows[this.rows.Count - 1].CanMove ((ToolStrip)Widget)) { + this.rows[this.rows.Count - 1].OnWidgetAdded (Widget, 0); + return; + } + + ToolStripPanelRow new_row = new ToolStripPanelRow (this); + + if (this.Dock == DockStyle.Left || this.Dock == DockStyle.Right) + new_row.SetBounds (new Rectangle (0, 0, 25, this.Height)); + else + new_row.SetBounds (new Rectangle (0, 0, this.Width, 25)); + + this.rows.Add (new_row); + new_row.OnWidgetAdded (Widget, 0); + } + /* + private Region FindBackgroundRegion () + { + Region r = new Region (this.Bounds); + + foreach (Widget c in this.Widgets) + r.Exclude (c.Bounds); + + return r; + } + */ + #endregion + + #region Nested Classes + [ComVisible (false)] + [ListBindable (false)] + public class ToolStripPanelRowCollection : ArrangedElementCollection, IList, ICollection, IEnumerable + { + //private ToolStripPanel owner; + + public ToolStripPanelRowCollection (ToolStripPanel owner) : base () + { + //this.owner = owner; + } + + public ToolStripPanelRowCollection (ToolStripPanel owner, ToolStripPanelRow[] value) : this (owner) + { + if (value != null) + foreach (ToolStripPanelRow tspr in value) + this.Add (tspr); + } + + public new virtual ToolStripPanelRow this [int index] { + get { return (ToolStripPanelRow)base[index]; } + } + + #region Public Methods + public int Add (ToolStripPanelRow value) + { + return base.Add (value); + } + + public void AddRange (ToolStripPanelRowCollection value) + { + if (value == null) + throw new ArgumentNullException ("value"); + + foreach (ToolStripPanelRow tspr in value) + this.Add (tspr); + } + + public void AddRange (ToolStripPanelRow[] value) + { + if (value == null) + throw new ArgumentNullException ("value"); + + foreach (ToolStripPanelRow tspr in value) + this.Add (tspr); + } + + public new virtual void Clear () + { + base.Clear (); + } + + public bool Contains (ToolStripPanelRow value) + { + return base.Contains (value); + } + + public void CopyTo (ToolStripPanelRow[] array, int index) + { + base.CopyTo (array, index); + } + + public int IndexOf (ToolStripPanelRow value) + { + return base.IndexOf (value); + } + + public void Insert (int index, ToolStripPanelRow value) + { + base.Insert (index, value); + } + + public void Remove (ToolStripPanelRow value) + { + base.Remove (value); + } + + public void RemoveAt (int index) + { + base.InternalRemoveAt (index); + } + #endregion + + #region IList Members + object IList.this [int index] { + get { return this [index]; } + [MonoTODO ("Stub, does nothing")] + set { } + } + + bool IList.IsFixedSize { + get { return IsFixedSize; } + } + + bool IList.IsReadOnly { + get { return IsReadOnly; } + } + + int IList.Add (object value) + { + return Add (value as ToolStripPanelRow); + } + + void IList.Clear () + { + Clear (); + } + + bool IList.Contains (object value) + { + return Contains (value as ToolStripPanelRow); + } + + int IList.IndexOf (object value) + { + return IndexOf (value as ToolStripPanelRow); + } + + void IList.Insert (int index, object value) + { + Insert (index, value as ToolStripPanelRow); + } + + void IList.Remove (object value) + { + Remove (value as ToolStripPanelRow); + } + + void IList.RemoveAt (int index) + { + base.InternalRemoveAt (index); + } + #endregion + } + + private class ToolStripPanelWidgetCollection : WidgetCollection + { + public ToolStripPanelWidgetCollection (Widget owner) : base (owner) + { + } + } + + private class TabIndexComparer : IComparer + { + #region IComparer Members + public int Compare (object x, object y) + { + if (!(x is Widget) || !(y is Widget)) + throw new ArgumentException (); + + return (x as Widget).TabIndex - (y as Widget).TabIndex; + } + #endregion + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripPanelRenderEventArgs.cs b/source/ShiftUI/ToolStrip/ToolStripPanelRenderEventArgs.cs new file mode 100644 index 0000000..88fceaf --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripPanelRenderEventArgs.cs @@ -0,0 +1,62 @@ +// +// ToolStripPanelRenderEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System; + +namespace ShiftUI +{ + public class ToolStripPanelRenderEventArgs : EventArgs + { + private Graphics graphics; + private bool handled; + private ToolStripPanel tool_strip_panel; + + public ToolStripPanelRenderEventArgs (Graphics g, ToolStripPanel toolStripPanel) + { + this.graphics = g; + this.tool_strip_panel = toolStripPanel; + this.handled = false; + } + + #region Public Properties + public Graphics Graphics { + get { return this.graphics; } + } + + public bool Handled { + get { return this.handled; } + set { this.handled = value; } + } + + public ToolStripPanel ToolStripPanel { + get { return this.tool_strip_panel; } + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripPanelRenderEventHandler.cs b/source/ShiftUI/ToolStrip/ToolStripPanelRenderEventHandler.cs new file mode 100644 index 0000000..ecf71ed --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripPanelRenderEventHandler.cs @@ -0,0 +1,32 @@ +// +// ToolStripPanelRenderEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ToolStripPanelRenderEventHandler (object sender, ToolStripPanelRenderEventArgs e); +} diff --git a/source/ShiftUI/ToolStrip/ToolStripPanelRow.cs b/source/ShiftUI/ToolStrip/ToolStripPanelRow.cs new file mode 100644 index 0000000..ae2e8a8 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripPanelRow.cs @@ -0,0 +1,227 @@ +// +// ToolStripPanelRow.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System.Runtime.InteropServices; +using System.ComponentModel; +using ShiftUI.Layout; +using System.Collections.Generic; +using System; + +namespace ShiftUI +{ + [ToolboxItem (false)] + public class ToolStripPanelRow : Component, IComponent, IDisposable, IBounds + { + private Rectangle bounds; + internal List _Widgets; + private LayoutEngine layout_engine; + private Padding margin; + private Padding padding; + private ToolStripPanel parent; + + #region Public Constructors + public ToolStripPanelRow (ToolStripPanel parent) + { + this.bounds = Rectangle.Empty; + this._Widgets = new List (); + this.layout_engine = new DefaultLayout (); + this.parent = parent; + } + #endregion + + #region Public Properties + public Rectangle Bounds { + get { return this.bounds; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public List Widgets { + get { return this._Widgets; } + } + + public Rectangle DisplayRectangle { + get { return this.Bounds; } + } + + public LayoutEngine LayoutEngine { + get { + if (this.layout_engine == null) + this.layout_engine = new DefaultLayout (); + + return this.layout_engine; + } + } + + public Padding Margin { + get { return this.margin; } + set { this.margin = value; } + } + + public Orientation Orientation { + get { return this.parent.Orientation; } + } + + public virtual Padding Padding { + get { return this.padding; } + set { this.padding = value; } + } + + public ToolStripPanel ToolStripPanel { + get { return this.parent; } + } + #endregion + + #region Protected Properties + protected virtual Padding DefaultMargin { get { return Padding.Empty; } } + protected virtual Padding DefaultPadding { get { return Padding.Empty; } } + #endregion + + #region Public Methods + public bool CanMove (ToolStrip toolStripToDrag) + { + // If something uses Stretch, it gets a whole Row to itself + if (this.Widgets.Count > 0) + if (toolStripToDrag.Stretch || (this.Widgets[0] as ToolStrip).Stretch) + return false; + + int width = 0; + + foreach (ToolStrip ts in this.Widgets) + width += (ts.Width + ts.Margin.Horizontal); + + if (width + toolStripToDrag.Width + toolStripToDrag.Margin.Horizontal <= this.bounds.Width) + return true; + + return false; + } + #endregion + + #region Protected Methods + protected override void Dispose (bool disposing) + { + base.Dispose (disposing); + } + + protected void OnBoundsChanged (Rectangle oldBounds, Rectangle newBounds) + { + } + + protected internal virtual void OnWidgetAdded (Widget Widget, int index) + { + Widget.SizeChanged += new EventHandler (Widget_SizeChanged); + Widgets.Add (Widget); + this.OnLayout (new LayoutEventArgs (Widget, string.Empty)); + } + + protected internal virtual void OnWidgetRemoved (Widget Widget, int index) + { + Widget.SizeChanged -= new EventHandler (Widget_SizeChanged); + Widgets.Remove (Widget); + this.OnLayout (new LayoutEventArgs (Widget, string.Empty)); + } + + protected virtual void OnLayout (LayoutEventArgs e) + { + int height = 0; + + if (this.Orientation == Orientation.Horizontal) { + foreach (ToolStrip ts in this.Widgets) + if (ts.Height > height) + height = ts.Height; + + if (height != this.bounds.Height) + this.bounds.Height = height; + } else { + foreach (ToolStrip ts in this.Widgets) + if (ts.GetPreferredSize (Size.Empty).Width > height) + height = ts.GetPreferredSize (Size.Empty).Width; + + if (height != this.bounds.Width) + this.bounds.Width = height; + } + + this.Layout (this, e); + } + + protected internal virtual void OnOrientationChanged () + { + } + #endregion + + #region Private/Internal Methods + internal void SetBounds (Rectangle bounds) + { + if (this.bounds != bounds) { + Rectangle old_bounds = this.bounds; + this.bounds = bounds; + this.OnBoundsChanged (old_bounds, bounds); + this.OnLayout (new LayoutEventArgs (null, "Bounds")); + } + } + + private bool Layout (object container, LayoutEventArgs args) + { + ToolStripPanelRow tspr = (ToolStripPanelRow)container; + Point position = tspr.DisplayRectangle.Location; + foreach (ToolStrip ts in tspr.Widgets) + { + if (Orientation == Orientation.Horizontal) { + if (ts.Stretch) + ts.Width = this.bounds.Width - ts.Margin.Horizontal - this.Padding.Horizontal; + else + ts.Width = ts.GetToolStripPreferredSize (Size.Empty).Width; + + position.X += ts.Margin.Left; + ts.Location = position; + + position.X += (ts.Width + ts.Margin.Left); + } else { + if (ts.Stretch) + ts.Size = new Size (ts.GetToolStripPreferredSize (Size.Empty).Width, this.bounds.Height - ts.Margin.Vertical - this.Padding.Vertical); + else + ts.Size = ts.GetToolStripPreferredSize (Size.Empty); + + position.Y += ts.Margin.Top; + ts.Location = position; + + position.Y += (ts.Height + ts.Margin.Top); + } + } + + return false; + } + + void Widget_SizeChanged (object sender, EventArgs e) + { + this.OnLayout (new LayoutEventArgs ((Widget)sender, string.Empty)); + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripProfessionalRenderer.cs b/source/ShiftUI/ToolStrip/ToolStripProfessionalRenderer.cs new file mode 100644 index 0000000..018d02b --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripProfessionalRenderer.cs @@ -0,0 +1,470 @@ +// +// ToolStripProfessionalRenderer.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; + +namespace ShiftUI +{ + public class ToolStripProfessionalRenderer : ToolStripRenderer + { + private ProfessionalColorTable color_table; + private bool rounded_edges; + + #region Public Constructor + public ToolStripProfessionalRenderer () : this (new ProfessionalColorTable ()) + { + } + + public ToolStripProfessionalRenderer (ProfessionalColorTable professionalColorTable) : base () + { + color_table = professionalColorTable; + rounded_edges = true; + } + #endregion + + #region Public Properties + public ProfessionalColorTable ColorTable { + get { return this.color_table; } + } + + public bool RoundedEdges { + get { return this.rounded_edges; } + set { this.rounded_edges = value; } + } + #endregion + + #region Protected Methods + protected override void OnRenderArrow (ToolStripArrowRenderEventArgs e) + { + base.OnRenderArrow (e); + } + + protected override void OnRenderButtonBackground (ToolStripItemRenderEventArgs e) + { + if (e.Item.Enabled == false) + return; + + Rectangle paint_here = new Rectangle (0, 0, e.Item.Width, e.Item.Height); + + // Paint gradient background + if (e.Item is ToolStripButton && (e.Item as ToolStripButton).Checked && !e.Item.Selected) { + if (this.ColorTable.UseSystemColors) + e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (this.ColorTable.ButtonCheckedHighlight), paint_here); + else + using (Brush b = new LinearGradientBrush (paint_here, this.ColorTable.ButtonCheckedGradientBegin, this.ColorTable.ButtonCheckedGradientEnd, LinearGradientMode.Vertical)) + e.Graphics.FillRectangle (b, paint_here); } + else + if (e.Item is ToolStripDropDownItem && e.Item.Pressed) // || (e.Item as ToolStripMenuItem).DropDown.Visible == true)) + using (Brush b = new LinearGradientBrush (paint_here, this.ColorTable.ToolStripGradientBegin, this.ColorTable.ToolStripGradientEnd, LinearGradientMode.Vertical)) + e.Graphics.FillRectangle (b, paint_here); + else if (e.Item.Pressed || (e.Item is ToolStripButton && (e.Item as ToolStripButton).Checked)) + using (Brush b = new LinearGradientBrush (paint_here, this.ColorTable.ButtonPressedGradientBegin, this.ColorTable.ButtonPressedGradientEnd, LinearGradientMode.Vertical)) + e.Graphics.FillRectangle (b, paint_here); + else if (e.Item.Selected) // && !e.Item.Pressed) + using (Brush b = new LinearGradientBrush (paint_here, this.ColorTable.ButtonSelectedGradientBegin, this.ColorTable.ButtonSelectedGradientEnd, LinearGradientMode.Vertical)) + e.Graphics.FillRectangle (b, paint_here); + else if (e.Item.BackColor != Widget.DefaultBackColor && e.Item.BackColor != Color.Empty) + using (Brush b = new SolidBrush (e.Item.BackColor)) + e.Graphics.FillRectangle (b, paint_here); + + paint_here.Width -= 1; + paint_here.Height -= 1; + + // Paint border + if (e.Item.Selected && !e.Item.Pressed) + using (Pen p = new Pen (this.ColorTable.ButtonSelectedBorder)) + e.Graphics.DrawRectangle (p, paint_here); + else if (e.Item.Pressed) + using (Pen p = new Pen (this.ColorTable.ButtonPressedBorder)) + e.Graphics.DrawRectangle (p, paint_here); + else if (e.Item is ToolStripButton && (e.Item as ToolStripButton).Checked) + using (Pen p = new Pen (this.ColorTable.ButtonPressedBorder)) + e.Graphics.DrawRectangle (p, paint_here); + + base.OnRenderButtonBackground (e); + } + + protected override void OnRenderDropDownButtonBackground (ToolStripItemRenderEventArgs e) + { + Rectangle paint_here = new Rectangle (0, 0, e.Item.Width, e.Item.Height); + + // Paint gradient background + if (e.Item.Selected && !e.Item.Pressed) + using (Brush b = new LinearGradientBrush (paint_here, this.ColorTable.ButtonSelectedGradientBegin, this.ColorTable.ButtonSelectedGradientEnd, LinearGradientMode.Vertical)) + e.Graphics.FillRectangle (b, paint_here); + else if (e.Item.Pressed) + using (Brush b = new LinearGradientBrush (paint_here, this.ColorTable.ImageMarginGradientMiddle, this.ColorTable.ImageMarginGradientEnd, LinearGradientMode.Vertical)) + e.Graphics.FillRectangle (b, paint_here); + + paint_here.Width -= 1; + paint_here.Height -= 1; + + // Paint border + if (e.Item.Selected && !e.Item.Pressed) + using (Pen p = new Pen (this.ColorTable.ButtonSelectedBorder)) + e.Graphics.DrawRectangle (p, paint_here); + else if (e.Item.Pressed) + using (Pen p = new Pen (this.ColorTable.MenuBorder)) + e.Graphics.DrawRectangle (p, paint_here); + + base.OnRenderDropDownButtonBackground (e); + } + + protected override void OnRenderGrip (ToolStripGripRenderEventArgs e) + { + if (e.GripStyle == ToolStripGripStyle.Hidden) + return; + + if (e.GripDisplayStyle == ToolStripGripDisplayStyle.Vertical) { + Rectangle r = new Rectangle (e.GripBounds.Left, e.GripBounds.Top + 5, 2, 2); + + for (int i = 0; i < e.GripBounds.Height - 12; i += 4) { + e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (this.ColorTable.GripLight), r); + r.Offset (0, 4); + } + + Rectangle r2 = new Rectangle (e.GripBounds.Left - 1, e.GripBounds.Top + 4, 2, 2); + + for (int i = 0; i < e.GripBounds.Height - 12; i += 4) { + e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (this.ColorTable.GripDark), r2); + r2.Offset (0, 4); + } + } + else { + Rectangle r = new Rectangle (e.GripBounds.Left + 5, e.GripBounds.Top, 2, 2); + + for (int i = 0; i < e.GripBounds.Width - 11; i += 4) { + e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (this.ColorTable.GripLight), r); + r.Offset (4, 0); + } + + Rectangle r2 = new Rectangle (e.GripBounds.Left + 4, e.GripBounds.Top - 1, 2, 2); + + for (int i = 0; i < e.GripBounds.Width - 11; i += 4) { + e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (this.ColorTable.GripDark), r2); + r2.Offset (4, 0); + } + } + + base.OnRenderGrip (e); + } + + protected override void OnRenderImageMargin (ToolStripRenderEventArgs e) + { + if (!(e.ToolStrip is ToolStripOverflow)) { + Rectangle side_gradient = new Rectangle (1, 2, 24, e.ToolStrip.Height - 3); + using (LinearGradientBrush b = new LinearGradientBrush (side_gradient, this.ColorTable.ToolStripGradientBegin, this.ColorTable.ToolStripGradientEnd, LinearGradientMode.Horizontal)) + e.Graphics.FillRectangle (b, side_gradient); + } + + base.OnRenderImageMargin (e); + } + + protected override void OnRenderItemCheck (ToolStripItemImageRenderEventArgs e) + { + if (e.Item.Selected) + { + e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (this.ColorTable.CheckPressedBackground), e.ImageRectangle); + e.Graphics.DrawRectangle (ThemeEngine.Current.ResPool.GetPen (this.ColorTable.ButtonPressedBorder), e.ImageRectangle); + } + else if (e.Item.Pressed) + { + e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (this.ColorTable.CheckSelectedBackground), e.ImageRectangle); + e.Graphics.DrawRectangle (ThemeEngine.Current.ResPool.GetPen (this.ColorTable.ButtonSelectedBorder), e.ImageRectangle); + } + else + { + e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (this.ColorTable.CheckSelectedBackground), e.ImageRectangle); + e.Graphics.DrawRectangle (ThemeEngine.Current.ResPool.GetPen (this.ColorTable.ButtonSelectedBorder), e.ImageRectangle); + } + if (e.Item.Image == null) + WidgetPaint.DrawMenuGlyph(e.Graphics, new Rectangle (6,5,7,6), MenuGlyph.Checkmark); + + base.OnRenderItemCheck (e); + } + + protected override void OnRenderItemImage (ToolStripItemImageRenderEventArgs e) + { + base.OnRenderItemImage (e); + } + + protected override void OnRenderItemText (ToolStripItemTextRenderEventArgs e) + { + base.OnRenderItemText (e); + } + + protected override void OnRenderLabelBackground (ToolStripItemRenderEventArgs e) + { + base.OnRenderLabelBackground (e); + } + + protected override void OnRenderMenuItemBackground (ToolStripItemRenderEventArgs e) + { + ToolStripMenuItem tsmi = (ToolStripMenuItem)e.Item; + Rectangle paint_here; + + if (tsmi.IsOnDropDown) { + paint_here = new Rectangle (1, 0, e.Item.Bounds.Width - 3, e.Item.Bounds.Height - 1); + + if (e.Item.Selected || e.Item.Pressed) + if (e.Item.Enabled) + e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (this.ColorTable.MenuItemSelectedGradientEnd), paint_here); + + if (tsmi.Selected || tsmi.Pressed) + using (Pen p = new Pen (this.ColorTable.MenuItemBorder)) + e.Graphics.DrawRectangle (p, paint_here); + } + else { + paint_here = new Rectangle (0, 0, e.Item.Width, e.Item.Height); + + if (e.Item.Pressed) + using (Brush b = new LinearGradientBrush (paint_here, this.ColorTable.ToolStripGradientBegin, this.ColorTable.ToolStripGradientEnd, LinearGradientMode.Vertical)) + e.Graphics.FillRectangle (b, paint_here); + else if (e.Item.Selected) + using (Brush b = new LinearGradientBrush (paint_here, this.ColorTable.ButtonSelectedGradientBegin, this.ColorTable.ButtonSelectedGradientEnd, LinearGradientMode.Vertical)) + e.Graphics.FillRectangle (b, paint_here); + else if (e.Item.BackColor != Widget.DefaultBackColor && e.Item.BackColor != Color.Empty) + using (Brush b = new SolidBrush (e.Item.BackColor)) + e.Graphics.FillRectangle (b, paint_here); + + paint_here.Width -= 1; + paint_here.Height -= 1; + + if (tsmi.Selected || tsmi.Pressed) { + if (tsmi.HasDropDownItems && tsmi.DropDown.Visible) + using (Pen p = new Pen (this.ColorTable.MenuBorder)) + e.Graphics.DrawRectangle (p, paint_here); + else + using (Pen p = new Pen (this.ColorTable.MenuItemBorder)) + e.Graphics.DrawRectangle (p, paint_here); + } + } + + base.OnRenderMenuItemBackground (e); + } + + protected override void OnRenderOverflowButtonBackground (ToolStripItemRenderEventArgs e) + { + Rectangle paint_here; + LinearGradientMode gradient_direction = e.ToolStrip.Orientation == Orientation.Vertical ? LinearGradientMode.Horizontal : LinearGradientMode.Vertical; + + if (e.ToolStrip.Orientation == Orientation.Horizontal) + paint_here = new Rectangle (e.Item.Width - 11, 0, 11, e.Item.Height - 1); + else + paint_here = new Rectangle (0, e.Item.Height - 11, e.Item.Width - 1, 11); + + // Paint gradient background + if (e.Item.Selected && !e.Item.Pressed) + using (Brush b = new LinearGradientBrush (paint_here, this.ColorTable.ButtonSelectedGradientBegin, this.ColorTable.ButtonSelectedGradientEnd, gradient_direction)) + e.Graphics.FillRectangle (b, paint_here); + else if (e.Item.Pressed) + using (Brush b = new LinearGradientBrush (paint_here, this.ColorTable.ButtonPressedGradientBegin, this.ColorTable.ButtonPressedGradientEnd, gradient_direction)) + e.Graphics.FillRectangle (b, paint_here); + else + using (Brush b = new LinearGradientBrush (paint_here, this.ColorTable.OverflowButtonGradientBegin, this.ColorTable.OverflowButtonGradientEnd, gradient_direction)) + e.Graphics.FillRectangle (b, paint_here); + + // Paint the arrow + PaintOverflowArrow (e, paint_here); + + base.OnRenderOverflowButtonBackground (e); + } + + protected override void OnRenderSeparator (ToolStripSeparatorRenderEventArgs e) + { + if (e.Vertical) { + Rectangle r = new Rectangle (4, 6, 1, e.Item.Height - 10); + e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (this.ColorTable.SeparatorLight), r); + + Rectangle r2 = new Rectangle (3, 5, 1, e.Item.Height - 10); + e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (this.ColorTable.SeparatorDark), r2); + } + else { + if (!e.Item.IsOnDropDown) { + Rectangle r = new Rectangle (6, 4, e.Item.Width - 10, 1); + e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (this.ColorTable.SeparatorLight), r); + } + + Rectangle r3; + if (e.Item.IsOnDropDown) { + if (e.Item.UseImageMargin) + r3 = new Rectangle (35, 3, e.Item.Width - 36, 1); + else + r3 = new Rectangle (7, 3, e.Item.Width - 7, 1); + } else + r3 = new Rectangle (5, 3, e.Item.Width - 10, 1); + + e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (this.ColorTable.SeparatorDark), r3); + } + + base.OnRenderSeparator (e); + } + + protected override void OnRenderSplitButtonBackground (ToolStripItemRenderEventArgs e) + { + ToolStripSplitButton tssb = (ToolStripSplitButton)e.Item; + Rectangle paint_here = new Rectangle (0, 0, tssb.Width, tssb.Height); + Rectangle button_part = new Rectangle (0, 0, tssb.ButtonBounds.Width, tssb.ButtonBounds.Height); + + // Paint gradient background + if (tssb.ButtonSelected && !tssb.DropDownButtonPressed) + using (Brush b = new LinearGradientBrush (paint_here, this.ColorTable.ButtonSelectedGradientBegin, this.ColorTable.ButtonSelectedGradientEnd, LinearGradientMode.Vertical)) + e.Graphics.FillRectangle (b, paint_here); + if (tssb.ButtonPressed) + using (Brush b = new LinearGradientBrush (button_part, this.ColorTable.ButtonPressedGradientBegin, this.ColorTable.ButtonPressedGradientEnd, LinearGradientMode.Vertical)) + e.Graphics.FillRectangle (b, button_part); + + paint_here.Width -= 1; + paint_here.Height -= 1; + + // Paint border + if (e.Item.Selected && !tssb.DropDownButtonPressed) + using (Pen p = new Pen (this.ColorTable.ButtonSelectedBorder)) + { + e.Graphics.DrawRectangle (p, paint_here); + e.Graphics.DrawLine (p, button_part.Right, 0, button_part.Right, button_part.Height); + } + else if (e.Item.Pressed) + using (Pen p = new Pen (this.ColorTable.MenuBorder)) + e.Graphics.DrawRectangle (p, paint_here); + + base.OnRenderSplitButtonBackground (e); + } + + protected override void OnRenderToolStripBackground (ToolStripRenderEventArgs e) + { + // Don't clear and fill the background if we already painted an image there + if (e.ToolStrip.BackgroundImage != null) { + if (e.ToolStrip is StatusStrip) + e.Graphics.DrawLine (Pens.White, e.AffectedBounds.Left, e.AffectedBounds.Top, e.AffectedBounds.Right, e.AffectedBounds.Top); + + return; + } + + if (e.ToolStrip is ToolStripDropDown) { + e.Graphics.Clear (this.ColorTable.ToolStripDropDownBackground); + return; + } + + if (e.ToolStrip is MenuStrip || e.ToolStrip is StatusStrip) { + using (LinearGradientBrush b = new LinearGradientBrush (e.AffectedBounds, this.ColorTable.MenuStripGradientBegin, this.ColorTable.MenuStripGradientEnd, e.ToolStrip.Orientation == Orientation.Horizontal ? LinearGradientMode.Horizontal : LinearGradientMode.Vertical)) + e.Graphics.FillRectangle (b, e.AffectedBounds); + } + else + using (LinearGradientBrush b = new LinearGradientBrush (e.AffectedBounds, this.ColorTable.ToolStripGradientBegin, this.ColorTable.ToolStripGradientEnd, e.ToolStrip.Orientation == Orientation.Vertical ? LinearGradientMode.Horizontal : LinearGradientMode.Vertical)) + e.Graphics.FillRectangle (b, e.AffectedBounds); + + if (e.ToolStrip is StatusStrip) + e.Graphics.DrawLine (Pens.White, e.AffectedBounds.Left, e.AffectedBounds.Top, e.AffectedBounds.Right, e.AffectedBounds.Top); + + base.OnRenderToolStripBackground (e); + } + + protected override void OnRenderToolStripBorder (ToolStripRenderEventArgs e) + { + if (e.ToolStrip is ToolStripDropDown) { + if (e.ToolStrip is ToolStripOverflow) + e.Graphics.DrawLines (ThemeEngine.Current.ResPool.GetPen (this.ColorTable.MenuBorder), new Point[] { e.AffectedBounds.Location, new Point (e.AffectedBounds.Left, e.AffectedBounds.Bottom - 1), new Point (e.AffectedBounds.Right - 1, e.AffectedBounds.Bottom - 1), new Point (e.AffectedBounds.Right - 1, e.AffectedBounds.Top), new Point (e.AffectedBounds.Left, e.AffectedBounds.Top) }); + else + e.Graphics.DrawLines (ThemeEngine.Current.ResPool.GetPen (this.ColorTable.MenuBorder), new Point[] { new Point (e.AffectedBounds.Left + e.ConnectedArea.Left, e.AffectedBounds.Top), e.AffectedBounds.Location, new Point (e.AffectedBounds.Left, e.AffectedBounds.Bottom - 1), new Point (e.AffectedBounds.Right - 1, e.AffectedBounds.Bottom - 1), new Point (e.AffectedBounds.Right - 1, e.AffectedBounds.Top), new Point (e.AffectedBounds.Left + e.ConnectedArea.Right, e.AffectedBounds.Top) }); + return; + } + + if (e.ToolStrip is MenuStrip || e.ToolStrip is StatusStrip) + return; + + using (Pen p = new Pen (this.ColorTable.ToolStripBorder)) { + if (this.RoundedEdges == true) { + e.Graphics.DrawLine (p, new Point (2, e.ToolStrip.Height - 1), new Point (e.ToolStrip.Width - 3, e.ToolStrip.Height - 1)); + e.Graphics.DrawLine (p, new Point (e.ToolStrip.Width - 2, e.ToolStrip.Height - 2), new Point (e.ToolStrip.Width - 1, e.ToolStrip.Height - 2)); + e.Graphics.DrawLine (p, new Point (e.ToolStrip.Width - 1, 2), new Point (e.ToolStrip.Width - 1, e.ToolStrip.Height - 3)); + } + else + e.Graphics.DrawLine (p, new Point (e.ToolStrip.Left, e.ToolStrip.Bottom - 1), new Point (e.ToolStrip.Width, e.ToolStrip.Bottom - 1)); + } + + base.OnRenderToolStripBorder (e); + } + + protected override void OnRenderToolStripContentPanelBackground (ToolStripContentPanelRenderEventArgs e) + { + base.OnRenderToolStripContentPanelBackground (e); + } + + protected override void OnRenderToolStripPanelBackground (ToolStripPanelRenderEventArgs e) + { + using (LinearGradientBrush b = new LinearGradientBrush (e.ToolStripPanel.Bounds, this.ColorTable.MenuStripGradientBegin, this.ColorTable.MenuStripGradientEnd, e.ToolStripPanel.Orientation == Orientation.Horizontal ? LinearGradientMode.Horizontal : LinearGradientMode.Vertical)) + e.Graphics.FillRectangle (b, e.ToolStripPanel.Bounds); + + base.OnRenderToolStripPanelBackground (e); + } + + protected override void OnRenderToolStripStatusLabelBackground (ToolStripItemRenderEventArgs e) + { + base.OnRenderToolStripStatusLabelBackground (e); + } + #endregion + + #region Private Methods + private static void PaintOverflowArrow (ToolStripItemRenderEventArgs e, Rectangle paint_here) + { + if (e.ToolStrip.Orientation == Orientation.Horizontal) { + // Paint down arrow + Point arrow_loc = new Point (paint_here.X + 2, paint_here.Bottom - 9); + + e.Graphics.DrawLine (Pens.White, arrow_loc.X + 1, arrow_loc.Y + 1, arrow_loc.X + 5, arrow_loc.Y + 1); + e.Graphics.DrawLine (Pens.Black, arrow_loc.X, arrow_loc.Y, arrow_loc.X + 4, arrow_loc.Y); + + e.Graphics.DrawLine (Pens.White, arrow_loc.X + 3, arrow_loc.Y + 4, arrow_loc.X + 5, arrow_loc.Y + 4); + e.Graphics.DrawLine (Pens.White, arrow_loc.X + 3, arrow_loc.Y + 5, arrow_loc.X + 4, arrow_loc.Y + 5); + e.Graphics.DrawLine (Pens.White, arrow_loc.X + 3, arrow_loc.Y + 4, arrow_loc.X + 3, arrow_loc.Y + 6); + + e.Graphics.DrawLine (Pens.Black, arrow_loc.X, arrow_loc.Y + 3, arrow_loc.X + 4, arrow_loc.Y + 3); + e.Graphics.DrawLine (Pens.Black, arrow_loc.X + 1, arrow_loc.Y + 4, arrow_loc.X + 3, arrow_loc.Y + 4); + e.Graphics.DrawLine (Pens.Black, arrow_loc.X + 2, arrow_loc.Y + 4, arrow_loc.X + 2, arrow_loc.Y + 5); + } else { + Point arrow_loc = new Point (paint_here.Right - 9, paint_here.Y + 2); + + e.Graphics.DrawLine (Pens.White, arrow_loc.X + 1, arrow_loc.Y + 1, arrow_loc.X + 1, arrow_loc.Y + 5); + e.Graphics.DrawLine (Pens.Black, arrow_loc.X, arrow_loc.Y, arrow_loc.X, arrow_loc.Y + 4); + + e.Graphics.DrawLine (Pens.White, arrow_loc.X + 4, arrow_loc.Y + 3, arrow_loc.X + 4, arrow_loc.Y + 5); + e.Graphics.DrawLine (Pens.White, arrow_loc.X + 5, arrow_loc.Y + 3, arrow_loc.X + 5, arrow_loc.Y + 4); + e.Graphics.DrawLine (Pens.White, arrow_loc.X + 4, arrow_loc.Y + 3, arrow_loc.X + 6, arrow_loc.Y + 3); + + e.Graphics.DrawLine (Pens.Black, arrow_loc.X + 3, arrow_loc.Y, arrow_loc.X + 3, arrow_loc.Y + 4); + e.Graphics.DrawLine (Pens.Black, arrow_loc.X + 4, arrow_loc.Y + 1, arrow_loc.X + 4, arrow_loc.Y + 3); + e.Graphics.DrawLine (Pens.Black, arrow_loc.X + 4, arrow_loc.Y + 2, arrow_loc.X + 5, arrow_loc.Y + 2); + } + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripProgressBar.cs b/source/ShiftUI/ToolStrip/ToolStripProgressBar.cs new file mode 100644 index 0000000..91ec88e --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripProgressBar.cs @@ -0,0 +1,223 @@ +// +// ToolStripProgressBar.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System.ComponentModel; +using System; + +namespace ShiftUI +{ + [DefaultProperty ("Value")] + public class ToolStripProgressBar : ToolStripWidgetHost + { + #region Public Constructors + public ToolStripProgressBar () : base (new ProgressBar ()) + { + } + + public ToolStripProgressBar (string name) : this () + { + this.Name = name; + } + #endregion + + #region Public Properties + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override Image BackgroundImage { + get { return base.BackgroundImage; } + set { base.BackgroundImage = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + [DefaultValue (100)] + public int MarqueeAnimationSpeed { + get { return this.ProgressBar.MarqueeAnimationSpeed; } + set { this.ProgressBar.MarqueeAnimationSpeed = value; } + } + + [DefaultValue (100)] + [RefreshProperties (RefreshProperties.Repaint)] + public int Maximum { + get { return this.ProgressBar.Maximum; } + set { this.ProgressBar.Maximum = value; } + } + + [DefaultValue (0)] + [RefreshProperties (RefreshProperties.Repaint)] + public int Minimum { + get { return this.ProgressBar.Minimum; } + set { this.ProgressBar.Minimum = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public ProgressBar ProgressBar { + get { return (ProgressBar)base.Widget; } + } + + [Localizable (true)] + [DefaultValue (false)] + public virtual bool RightToLeftLayout { + get { return this.ProgressBar.RightToLeftLayout; } + set { this.ProgressBar.RightToLeftLayout = value; } + } + + [DefaultValue (10)] + public int Step { + get { return this.ProgressBar.Step; } + set { this.ProgressBar.Step = value; } + } + + [DefaultValue (ProgressBarStyle.Blocks)] + public ProgressBarStyle Style { + get { return this.ProgressBar.Style; } + set { this.ProgressBar.Style = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override string Text { + get { return base.Text; } + set { base.Text = value; } + } + + [Bindable (true)] + [DefaultValue (0)] + public int Value { + get { return this.ProgressBar.Value; } + set { this.ProgressBar.Value = value; } + } + #endregion + + #region Protected Properties + protected internal override Padding DefaultMargin { get { return new Padding (1, 2, 1, 1); } } + protected override Size DefaultSize { get { return new Size (100, 15); } } + #endregion + + #region Public Methods + public void Increment (int value) + { + this.ProgressBar.Increment (value); + } + + public void PerformStep () + { + this.ProgressBar.PerformStep (); + } + #endregion + + #region Protected Methods + protected virtual void OnRightToLeftLayoutChanged (EventArgs e) + { + } + + protected override void OnSubscribeWidgetEvents (Widget Widget) + { + base.OnSubscribeWidgetEvents (Widget); + } + + protected override void OnUnsubscribeWidgetEvents (Widget Widget) + { + base.OnUnsubscribeWidgetEvents (Widget); + } + #endregion + + #region Public Events + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event KeyEventHandler KeyDown { + add { base.KeyDown += value; } + remove { base.KeyDown -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event KeyPressEventHandler KeyPress { + add { base.KeyPress += value; } + remove { base.KeyPress -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event KeyEventHandler KeyUp { + add { base.KeyUp += value; } + remove { base.KeyUp -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler LocationChanged { + add { base.LocationChanged += value; } + remove { base.LocationChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler OwnerChanged { + add { base.OwnerChanged += value; } + remove { base.OwnerChanged -= value; } + } + + public event EventHandler RightToLeftLayoutChanged { + add { ProgressBar.RightToLeftLayoutChanged += value; } + remove { ProgressBar.RightToLeftLayoutChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler Validated { + add { base.Validated += value; } + remove { base.Validated -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event CancelEventHandler Validating { + add { base.Validating += value; } + remove { base.Validating -= value; } + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripRenderEventArgs.cs b/source/ShiftUI/ToolStrip/ToolStripRenderEventArgs.cs new file mode 100644 index 0000000..2accf17 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripRenderEventArgs.cs @@ -0,0 +1,85 @@ +// +// ToolStripRenderEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System; + +namespace ShiftUI +{ + public class ToolStripRenderEventArgs : EventArgs + { + private Rectangle affected_bounds; + private Color back_color; + private Rectangle connected_area; + private Graphics graphics; + private ToolStrip tool_strip; + + #region Public Constructors + public ToolStripRenderEventArgs (Graphics g, ToolStrip toolStrip) + : this (g, toolStrip, new Rectangle (0, 0, 100, 25), SystemColors.Control) + { + } + + public ToolStripRenderEventArgs (Graphics g, ToolStrip toolStrip, Rectangle affectedBounds, Color backColor) + { + this.graphics = g; + this.tool_strip = toolStrip; + this.affected_bounds = affectedBounds; + this.back_color = backColor; + } + #endregion + + #region Public Properties + public Rectangle AffectedBounds { + get { return this.affected_bounds; } + } + + public Color BackColor { + get { return this.back_color; } + } + + public Rectangle ConnectedArea { + get { return this.connected_area; } + } + + public Graphics Graphics { + get { return this.graphics; } + } + + public ToolStrip ToolStrip { + get { return this.tool_strip; } + } + #endregion + + #region Internal Properties + internal Rectangle InternalConnectedArea { + set { this.connected_area = value; } + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripRenderEventHandler.cs b/source/ShiftUI/ToolStrip/ToolStripRenderEventHandler.cs new file mode 100644 index 0000000..539fe3c --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripRenderEventHandler.cs @@ -0,0 +1,32 @@ +// +// ToolStripRenderEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ToolStripRenderEventHandler (object sender, ToolStripRenderEventArgs e); +} diff --git a/source/ShiftUI/ToolStrip/ToolStripRenderMode.cs b/source/ShiftUI/ToolStrip/ToolStripRenderMode.cs new file mode 100644 index 0000000..ada6dfc --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripRenderMode.cs @@ -0,0 +1,43 @@ +// +// ToolStripRenderMode.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +using System.ComponentModel; + +namespace ShiftUI +{ + public enum ToolStripRenderMode + { + [Browsable (false)] + Custom = 0, + + System = 1, + Professional = 2, + ManagerRenderMode = 3 + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripRenderer.cs b/source/ShiftUI/ToolStrip/ToolStripRenderer.cs new file mode 100644 index 0000000..9066352 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripRenderer.cs @@ -0,0 +1,572 @@ +// +// ToolStripRenderer.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Imaging; +using System.Drawing.Drawing2D; + +namespace ShiftUI +{ + public abstract class ToolStripRenderer + { + private static ColorMatrix grayscale_matrix = new ColorMatrix (new float[][] { + new float[] {0.22f, 0.22f, 0.22f, 0, 0}, + new float[] {0.27f, 0.27f, 0.27f, 0, 0}, + new float[] {0.04f, 0.04f, 0.04f, 0, 0}, + new float[] {0.365f, 0.365f, 0.365f, 0.7f, 0}, + new float[] {0, 0, 0, 0, 1} + }); + + protected ToolStripRenderer () + { + } + + #region Public Methods + public static Image CreateDisabledImage(Image normalImage) + { + if (normalImage == null) + return null; + + // Code adapted from ThemeWin32Classic.cs + ImageAttributes ia = new ImageAttributes(); + ia.SetColorMatrix (grayscale_matrix); + + Bitmap b = new Bitmap(normalImage.Width, normalImage.Height); + using (Graphics g = Graphics.FromImage(b)) + g.DrawImage(normalImage, new Rectangle (0, 0, normalImage.Width, normalImage.Height), 0, 0, normalImage.Width, normalImage.Height, GraphicsUnit.Pixel, ia); + + return b; + } + + public void DrawArrow (ToolStripArrowRenderEventArgs e) + { this.OnRenderArrow (e); } + + public void DrawButtonBackground (ToolStripItemRenderEventArgs e) + { this.OnRenderButtonBackground (e); } + + public void DrawDropDownButtonBackground (ToolStripItemRenderEventArgs e) + { this.OnRenderDropDownButtonBackground (e); } + + public void DrawGrip (ToolStripGripRenderEventArgs e) + { this.OnRenderGrip (e); } + + public void DrawImageMargin (ToolStripRenderEventArgs e) + { this.OnRenderImageMargin (e); } + + public void DrawItemBackground (ToolStripItemRenderEventArgs e) + { this.OnRenderItemBackground (e); } + + public void DrawItemCheck (ToolStripItemImageRenderEventArgs e) + { this.OnRenderItemCheck (e); } + + public void DrawItemImage (ToolStripItemImageRenderEventArgs e) + { this.OnRenderItemImage (e); } + + public void DrawItemText (ToolStripItemTextRenderEventArgs e) + { this.OnRenderItemText (e); } + + public void DrawLabelBackground (ToolStripItemRenderEventArgs e) + { this.OnRenderLabelBackground (e); } + + public void DrawMenuItemBackground (ToolStripItemRenderEventArgs e) + { this.OnRenderMenuItemBackground (e); } + + public void DrawOverflowButtonBackground (ToolStripItemRenderEventArgs e) + { this.OnRenderOverflowButtonBackground (e); } + + public void DrawSeparator (ToolStripSeparatorRenderEventArgs e) + { this.OnRenderSeparator (e); } + + public void DrawSplitButton (ToolStripItemRenderEventArgs e) + { this.OnRenderSplitButtonBackground (e); } + + public void DrawStatusStripSizingGrip (ToolStripRenderEventArgs e) + { this.OnRenderStatusStripSizingGrip (e); } + + public void DrawToolStripBackground (ToolStripRenderEventArgs e) + { this.OnRenderToolStripBackground (e); } + + public void DrawToolStripBorder (ToolStripRenderEventArgs e) + { this.OnRenderToolStripBorder (e); } + + public void DrawToolStripContentPanelBackground (ToolStripContentPanelRenderEventArgs e) + { this.OnRenderToolStripContentPanelBackground (e); } + + public void DrawToolStripPanelBackground (ToolStripPanelRenderEventArgs e) + { this.OnRenderToolStripPanelBackground (e); } + + public void DrawToolStripStatusLabelBackground (ToolStripItemRenderEventArgs e) + { this.OnRenderToolStripStatusLabelBackground (e); } + #endregion + + #region Protected Methods + protected internal virtual void Initialize (ToolStrip toolStrip) {} + protected internal virtual void InitializeContentPanel (ToolStripContentPanel contentPanel) {} + protected internal virtual void InitializeItem (ToolStripItem item) {} + protected internal virtual void InitializePanel (ToolStripPanel toolStripPanel) {} + + protected virtual void OnRenderArrow (ToolStripArrowRenderEventArgs e) + { + switch (e.Direction) { + case ArrowDirection.Down: + using (Pen p = new Pen (e.ArrowColor)) { + int x = e.ArrowRectangle.Left + (e.ArrowRectangle.Width / 2) - 3; + int y = e.ArrowRectangle.Top + (e.ArrowRectangle.Height / 2) - 2; + + DrawDownArrow (e.Graphics, p, x, y); + } + break; + case ArrowDirection.Left: + break; + case ArrowDirection.Right: + using (Pen p = new Pen (e.ArrowColor)) { + int x = e.ArrowRectangle.Left + (e.ArrowRectangle.Width / 2) - 3; + int y = e.ArrowRectangle.Top + (e.ArrowRectangle.Height / 2) - 4; + + DrawRightArrow (e.Graphics, p, x, y); + } + break; + case ArrowDirection.Up: + break; + } + + ToolStripArrowRenderEventHandler eh = (ToolStripArrowRenderEventHandler)Events[RenderArrowEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderButtonBackground (ToolStripItemRenderEventArgs e) + { + ToolStripItemRenderEventHandler eh = (ToolStripItemRenderEventHandler)Events [RenderButtonBackgroundEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderDropDownButtonBackground (ToolStripItemRenderEventArgs e) + { + ToolStripItemRenderEventHandler eh = (ToolStripItemRenderEventHandler)Events [RenderDropDownButtonBackgroundEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderGrip (ToolStripGripRenderEventArgs e) + { + ToolStripGripRenderEventHandler eh = (ToolStripGripRenderEventHandler)Events [RenderGripEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderImageMargin (ToolStripRenderEventArgs e) + { + ToolStripRenderEventHandler eh = (ToolStripRenderEventHandler)Events [RenderImageMarginEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderItemBackground (ToolStripItemRenderEventArgs e) + { + if (e.Item.BackColor != Widget.DefaultBackColor) { + // Only paint the BackColor if it's not the default one, + // to avoid painting a solid background color over the parent ToolStrip gradient. + Rectangle item_bounds = new Rectangle (0, 0, e.Item.Width, e.Item.Height); + e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (e.Item.BackColor), item_bounds); + } + + if (e.Item.BackgroundImage != null) { + Rectangle item_bounds = new Rectangle (0, 0, e.Item.Width, e.Item.Height); + DrawBackground (e.Graphics, item_bounds, e.Item.BackgroundImage, e.Item.BackgroundImageLayout); + } + + ToolStripItemRenderEventHandler eh = (ToolStripItemRenderEventHandler)Events [RenderItemBackgroundEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderItemCheck (ToolStripItemImageRenderEventArgs e) + { + ToolStripItemImageRenderEventHandler eh = (ToolStripItemImageRenderEventHandler)Events [RenderItemCheckEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderItemImage (ToolStripItemImageRenderEventArgs e) + { + bool need_dispose = false; + Image i = e.Image; + + if (e.Item.RightToLeft == RightToLeft.Yes && e.Item.RightToLeftAutoMirrorImage == true) { + i = CreateMirrorImage (i); + need_dispose = true; + } + + if (e.Item.ImageTransparentColor != Color.Empty) { + ImageAttributes ia = new ImageAttributes (); + ia.SetColorKey (e.Item.ImageTransparentColor, e.Item.ImageTransparentColor); + e.Graphics.DrawImage (i, e.ImageRectangle, 0, 0, i.Width, i.Height, GraphicsUnit.Pixel, ia); + ia.Dispose (); + } + else + e.Graphics.DrawImage (i, e.ImageRectangle); + + if (need_dispose) + i.Dispose (); + + ToolStripItemImageRenderEventHandler eh = (ToolStripItemImageRenderEventHandler)Events [RenderItemImageEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderItemText (ToolStripItemTextRenderEventArgs e) + { + if (e.TextDirection == ToolStripTextDirection.Vertical90) { + GraphicsState gs = e.Graphics.Save (); + PointF p = new PointF (e.Graphics.Transform.OffsetX, e.Graphics.Transform.OffsetY); + + e.Graphics.ResetTransform (); + e.Graphics.RotateTransform (90); + + RectangleF r = new RectangleF ((e.Item.Height - e.TextRectangle.Height) / 2, (e.TextRectangle.Width + p.X) * -1 - 18, e.TextRectangle.Height, e.TextRectangle.Width); + + StringFormat sf = new StringFormat (); + sf.Alignment = StringAlignment.Center; + + e.Graphics.DrawString (e.Text, e.TextFont, ThemeEngine.Current.ResPool.GetSolidBrush (e.TextColor), r, sf); + + e.Graphics.Restore (gs); + } else if (e.TextDirection == ToolStripTextDirection.Vertical270) { + GraphicsState gs = e.Graphics.Save (); + PointF p = new PointF (e.Graphics.Transform.OffsetX, e.Graphics.Transform.OffsetY); + + e.Graphics.ResetTransform (); + e.Graphics.RotateTransform (270); + + RectangleF r = new RectangleF (-e.TextRectangle.Height - (e.Item.Height - e.TextRectangle.Height) / 2, (e.TextRectangle.Width + p.X) + 4, e.TextRectangle.Height, e.TextRectangle.Width); + + StringFormat sf = new StringFormat (); + sf.Alignment = StringAlignment.Center; + + e.Graphics.DrawString (e.Text, e.TextFont, ThemeEngine.Current.ResPool.GetSolidBrush (e.TextColor), r, sf); + + e.Graphics.Restore (gs); + } else + TextRenderer.DrawText (e.Graphics, e.Text, e.TextFont, e.TextRectangle, e.TextColor, e.TextFormat); + + ToolStripItemTextRenderEventHandler eh = (ToolStripItemTextRenderEventHandler)Events[RenderItemTextEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderLabelBackground (ToolStripItemRenderEventArgs e) + { + ToolStripItemRenderEventHandler eh = (ToolStripItemRenderEventHandler)Events [RenderLabelBackgroundEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderMenuItemBackground (ToolStripItemRenderEventArgs e) + { + ToolStripItemRenderEventHandler eh = (ToolStripItemRenderEventHandler)Events [RenderMenuItemBackgroundEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderOverflowButtonBackground (ToolStripItemRenderEventArgs e) + { + ToolStripItemRenderEventHandler eh = (ToolStripItemRenderEventHandler)Events [RenderOverflowButtonBackgroundEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderSeparator (ToolStripSeparatorRenderEventArgs e) + { + ToolStripSeparatorRenderEventHandler eh = (ToolStripSeparatorRenderEventHandler)Events [RenderSeparatorEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderSplitButtonBackground (ToolStripItemRenderEventArgs e) + { + ToolStripItemRenderEventHandler eh = (ToolStripItemRenderEventHandler)Events [RenderSplitButtonBackgroundEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderStatusStripSizingGrip (ToolStripRenderEventArgs e) + { + StatusStrip ss = (StatusStrip)e.ToolStrip; + + if (ss.SizingGrip == true) + DrawSizingGrip (e.Graphics, ss.SizeGripBounds); + + ToolStripRenderEventHandler eh = (ToolStripRenderEventHandler)Events [RenderStatusStripSizingGripEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderToolStripBackground (ToolStripRenderEventArgs e) + { + ToolStripRenderEventHandler eh = (ToolStripRenderEventHandler)Events [RenderToolStripBackgroundEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderToolStripBorder (ToolStripRenderEventArgs e) + { + ToolStripRenderEventHandler eh = (ToolStripRenderEventHandler)Events [RenderToolStripBorderEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderToolStripContentPanelBackground (ToolStripContentPanelRenderEventArgs e) + { + ToolStripContentPanelRenderEventHandler eh = (ToolStripContentPanelRenderEventHandler)Events [RenderToolStripContentPanelBackgroundEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderToolStripPanelBackground (ToolStripPanelRenderEventArgs e) + { + ToolStripPanelRenderEventHandler eh = (ToolStripPanelRenderEventHandler)Events [RenderToolStripPanelBackgroundEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRenderToolStripStatusLabelBackground (ToolStripItemRenderEventArgs e) + { + ToolStripItemRenderEventHandler eh = (ToolStripItemRenderEventHandler)Events [RenderToolStripStatusLabelBackgroundEvent]; + if (eh != null) + eh (this, e); + } + #endregion + + #region Public Events + EventHandlerList events; + + EventHandlerList Events { + get { + if (events == null) + events = new EventHandlerList (); + return events; + } + } + + static object RenderArrowEvent = new object (); + static object RenderButtonBackgroundEvent = new object (); + static object RenderDropDownButtonBackgroundEvent = new object (); + static object RenderGripEvent = new object (); + static object RenderImageMarginEvent = new object (); + static object RenderItemBackgroundEvent = new object (); + static object RenderItemCheckEvent = new object (); + static object RenderItemImageEvent = new object (); + static object RenderItemTextEvent = new object (); + static object RenderLabelBackgroundEvent = new object (); + static object RenderMenuItemBackgroundEvent = new object (); + static object RenderOverflowButtonBackgroundEvent = new object (); + static object RenderSeparatorEvent = new object (); + static object RenderSplitButtonBackgroundEvent = new object (); + static object RenderStatusStripSizingGripEvent = new object (); + static object RenderToolStripBackgroundEvent = new object (); + static object RenderToolStripBorderEvent = new object (); + static object RenderToolStripContentPanelBackgroundEvent = new object (); + static object RenderToolStripPanelBackgroundEvent = new object (); + static object RenderToolStripStatusLabelBackgroundEvent = new object (); + + public event ToolStripArrowRenderEventHandler RenderArrow { + add { Events.AddHandler (RenderArrowEvent, value); } + remove {Events.RemoveHandler (RenderArrowEvent, value); } + } + public event ToolStripItemRenderEventHandler RenderButtonBackground { + add { Events.AddHandler (RenderButtonBackgroundEvent, value); } + remove {Events.RemoveHandler (RenderButtonBackgroundEvent, value); } + } + public event ToolStripItemRenderEventHandler RenderDropDownButtonBackground { + add { Events.AddHandler (RenderDropDownButtonBackgroundEvent, value); } + remove {Events.RemoveHandler (RenderDropDownButtonBackgroundEvent, value); } + } + public event ToolStripGripRenderEventHandler RenderGrip { + add { Events.AddHandler (RenderGripEvent, value); } + remove {Events.RemoveHandler (RenderGripEvent, value); } + } + public event ToolStripRenderEventHandler RenderImageMargin { + add { Events.AddHandler (RenderImageMarginEvent, value); } + remove {Events.RemoveHandler (RenderImageMarginEvent, value); } + } + public event ToolStripItemRenderEventHandler RenderItemBackground { + add { Events.AddHandler (RenderItemBackgroundEvent, value); } + remove {Events.RemoveHandler (RenderItemBackgroundEvent, value); } + } + public event ToolStripItemImageRenderEventHandler RenderItemCheck { + add { Events.AddHandler (RenderItemCheckEvent, value); } + remove {Events.RemoveHandler (RenderItemCheckEvent, value); } + } + public event ToolStripItemImageRenderEventHandler RenderItemImage { + add { Events.AddHandler (RenderItemImageEvent, value); } + remove {Events.RemoveHandler (RenderItemImageEvent, value); } + } + public event ToolStripItemTextRenderEventHandler RenderItemText { + add { Events.AddHandler (RenderItemTextEvent, value); } + remove {Events.RemoveHandler (RenderItemTextEvent, value); } + } + public event ToolStripItemRenderEventHandler RenderLabelBackground { + add { Events.AddHandler (RenderLabelBackgroundEvent, value); } + remove {Events.RemoveHandler (RenderLabelBackgroundEvent, value); } + } + public event ToolStripItemRenderEventHandler RenderMenuItemBackground { + add { Events.AddHandler (RenderMenuItemBackgroundEvent, value); } + remove {Events.RemoveHandler (RenderMenuItemBackgroundEvent, value); } + } + public event ToolStripItemRenderEventHandler RenderOverflowButtonBackground { + add { Events.AddHandler (RenderOverflowButtonBackgroundEvent, value); } + remove {Events.RemoveHandler (RenderOverflowButtonBackgroundEvent, value); } + } + public event ToolStripSeparatorRenderEventHandler RenderSeparator { + add { Events.AddHandler (RenderSeparatorEvent, value); } + remove {Events.RemoveHandler (RenderSeparatorEvent, value); } + } + public event ToolStripItemRenderEventHandler RenderSplitButtonBackground { + add { Events.AddHandler (RenderSplitButtonBackgroundEvent, value); } + remove {Events.RemoveHandler (RenderSplitButtonBackgroundEvent, value); } + } + public event ToolStripRenderEventHandler RenderStatusStripSizingGrip { + add { Events.AddHandler (RenderStatusStripSizingGripEvent, value); } + remove {Events.RemoveHandler (RenderStatusStripSizingGripEvent, value); } + } + public event ToolStripRenderEventHandler RenderToolStripBackground { + add { Events.AddHandler (RenderToolStripBackgroundEvent, value); } + remove {Events.RemoveHandler (RenderToolStripBackgroundEvent, value); } + } + public event ToolStripRenderEventHandler RenderToolStripBorder { + add { Events.AddHandler (RenderToolStripBorderEvent, value); } + remove {Events.RemoveHandler (RenderToolStripBorderEvent, value); } + } + public event ToolStripContentPanelRenderEventHandler RenderToolStripContentPanelBackground { + add { Events.AddHandler (RenderToolStripContentPanelBackgroundEvent, value); } + remove {Events.RemoveHandler (RenderToolStripContentPanelBackgroundEvent, value); } + } + public event ToolStripPanelRenderEventHandler RenderToolStripPanelBackground { + add { Events.AddHandler (RenderToolStripPanelBackgroundEvent, value); } + remove {Events.RemoveHandler (RenderToolStripPanelBackgroundEvent, value); } + } + public event ToolStripItemRenderEventHandler RenderToolStripStatusLabelBackground { + add { Events.AddHandler (RenderToolStripStatusLabelBackgroundEvent, value); } + remove {Events.RemoveHandler (RenderToolStripStatusLabelBackgroundEvent, value); } + } + #endregion + + #region Private Methods + internal static Image CreateMirrorImage (Image normalImage) + { + if (normalImage == null) + return null; + + Bitmap b = new Bitmap (normalImage); + b.RotateFlip (RotateFlipType.RotateNoneFlipX); + + return b; + } + + private void DrawBackground (Graphics g, Rectangle bounds, Image image, ImageLayout layout) + { + // Center and Tile don't matter if the image is larger than the Widget + if (layout == ImageLayout.Center || layout == ImageLayout.Tile) + if (image.Size.Width >= bounds.Size.Width && image.Size.Height >= bounds.Size.Height) + layout = ImageLayout.None; + + switch (layout) { + case ImageLayout.None: + g.DrawImageUnscaledAndClipped (image, bounds); + break; + case ImageLayout.Tile: + int x = 0; + int y = 0; + + while (y < bounds.Height) { + while (x < bounds.Width) { + g.DrawImageUnscaledAndClipped (image, bounds); + x += image.Width; + } + x = 0; + y += image.Height; + } + break; + case ImageLayout.Center: + Rectangle r = new Rectangle ((bounds.Size.Width - image.Size.Width) / 2, (bounds.Size.Height - image.Size.Height) / 2, image.Width, image.Height); + g.DrawImageUnscaledAndClipped (image, r); + break; + case ImageLayout.Stretch: + g.DrawImage (image, bounds); + break; + case ImageLayout.Zoom: + if (((float)image.Height / (float)image.Width) < ((float)bounds.Height / (float)bounds.Width)) { + Rectangle rzoom = new Rectangle (0, 0, bounds.Width, (int)((float)bounds.Width * ((float)image.Height / (float)image.Width))); + rzoom.Y = (bounds.Height - rzoom.Height)/ 2; + g.DrawImage (image, rzoom); + } else { + Rectangle rzoom = new Rectangle (0, 0, (int)((float)bounds.Height * ((float)image.Width / (float)image.Height)), bounds.Height); + rzoom.X = (bounds.Width - rzoom.Width) / 2; + g.DrawImage (image, rzoom); + } + break; + } + } + + internal static void DrawRightArrow (Graphics g, Pen p, int x, int y) + { + g.DrawLine (p, x, y, x, y + 6); + g.DrawLine (p, x + 1, y + 1, x + 1, y + 5); + g.DrawLine (p, x + 2, y + 2, x + 2, y + 4); + g.DrawLine (p, x + 2, y + 3, x + 3, y + 3); + } + + internal static void DrawDownArrow (Graphics g, Pen p, int x, int y) + { + g.DrawLine (p, x + 1, y, x + 5, y); + g.DrawLine (p, x + 2, y + 1, x + 4, y + 1); + g.DrawLine (p, x + 3, y + 1, x + 3, y + 2); + } + + private void DrawSizingGrip (Graphics g, Rectangle rect) + { + DrawGripBox (g, rect.Right - 5, rect.Bottom - 5); + DrawGripBox (g, rect.Right - 9, rect.Bottom - 5); + DrawGripBox (g, rect.Right - 5, rect.Bottom - 9); + DrawGripBox (g, rect.Right - 13, rect.Bottom - 5); + DrawGripBox (g, rect.Right - 5, rect.Bottom - 13); + DrawGripBox (g, rect.Right - 9, rect.Bottom - 9); + } + + private void DrawGripBox (Graphics g, int x, int y) + { + g.DrawRectangle (Pens.White, x + 1, y + 1, 1, 1); + g.DrawRectangle (ThemeEngine.Current.ResPool.GetPen (Color.FromArgb (172, 168, 153)), x, y, 1, 1); + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripSeparator.cs b/source/ShiftUI/ToolStrip/ToolStripSeparator.cs new file mode 100644 index 0000000..3f91d8d --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripSeparator.cs @@ -0,0 +1,278 @@ +// +// ToolStripSeparator.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System.ComponentModel; +using ShiftUI.Design; +using System; + +namespace ShiftUI +{ + [ToolStripItemDesignerAvailability (ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.ContextMenuStrip)] + public class ToolStripSeparator : ToolStripItem + { + public ToolStripSeparator () : base () + { + Dock = DockStyle.Fill; + } + + #region Public Properties + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new bool AutoToolTip { + get { return base.AutoToolTip; } + set { base.AutoToolTip = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override Image BackgroundImage { + get { return base.BackgroundImage; } + set { base.BackgroundImage = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + public override bool CanSelect { get { return false; } } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new ToolStripItemDisplayStyle DisplayStyle { + get { return base.DisplayStyle; } + set { base.DisplayStyle = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new bool DoubleClickEnabled { + get { return base.DoubleClickEnabled; } + set { base.DoubleClickEnabled = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override bool Enabled { + get { return base.Enabled; } + set { base.Enabled = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override Font Font { + get { return base.Font; } + set { base.Font = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override Image Image { + get { return base.Image; } + set { base.Image = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new ContentAlignment ImageAlign { + get { return base.ImageAlign; } + set { base.ImageAlign = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + [RefreshProperties (RefreshProperties.Repaint)] + public new int ImageIndex { + get { return base.ImageIndex; } + set { base.ImageIndex = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new string ImageKey { + get { return base.ImageKey; } + set { base.ImageKey = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new ToolStripItemImageScaling ImageScaling { + get { return base.ImageScaling; } + set { base.ImageScaling = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Color ImageTransparentColor { + get { return base.ImageTransparentColor; } + set { base.ImageTransparentColor = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new bool RightToLeftAutoMirrorImage { + get { return base.RightToLeftAutoMirrorImage; } + set { base.RightToLeftAutoMirrorImage = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override string Text { + get { return base.Text; } + set { base.Text = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new ContentAlignment TextAlign { + get { return base.TextAlign; } + set { base.TextAlign = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + [DefaultValue (ToolStripTextDirection.Horizontal)] + public override ToolStripTextDirection TextDirection { + get { return base.TextDirection; } + set { base.TextDirection = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new TextImageRelation TextImageRelation { + get { return base.TextImageRelation; } + set { base.TextImageRelation = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new string ToolTipText { + get { return base.ToolTipText; } + set { base.ToolTipText = value; } + } + #endregion + + #region Protected Properties + protected internal override Padding DefaultMargin { get { return new Padding(); } } + protected override Size DefaultSize { get { return new Size(6, 6); } } + #endregion + + #region Public Methods + public override Size GetPreferredSize (Size constrainingSize) + { + return new Size(6, 6); + } + #endregion + + #region Protected Methods + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override AccessibleObject CreateAccessibilityInstance () + { + ToolStripItemAccessibleObject ao = new ToolStripItemAccessibleObject (this); + + ao.default_action = "Press"; + ao.role = AccessibleRole.Separator; + ao.state = AccessibleStates.None; + + return ao; + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + protected override void OnFontChanged (EventArgs e) + { + base.OnFontChanged (e); + } + + protected override void OnPaint (PaintEventArgs e) + { + base.OnPaint (e); + + if (this.Owner != null) + { + if (this.IsOnDropDown) + this.Owner.Renderer.DrawSeparator (new ToolStripSeparatorRenderEventArgs (e.Graphics, this, this.Owner.Orientation == Orientation.Horizontal ? false : true)); + else + this.Owner.Renderer.DrawSeparator (new ToolStripSeparatorRenderEventArgs (e.Graphics, this, this.Owner.Orientation == Orientation.Horizontal ? true : false)); + } + } + + protected internal override void SetBounds (Rectangle rect) + { + base.SetBounds (rect); + } + #endregion + + #region Public Events + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler DisplayStyleChanged { + add { base.DisplayStyleChanged += value; } + remove { base.DisplayStyleChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler EnabledChanged { + add { base.EnabledChanged += value; } + remove { base.EnabledChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + #endregion + + #region Internal Method/Properties + internal override ToolStripTextDirection DefaultTextDirection { get { return ToolStripTextDirection.Horizontal; } } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripSeparatorRenderEventArgs.cs b/source/ShiftUI/ToolStrip/ToolStripSeparatorRenderEventArgs.cs new file mode 100644 index 0000000..de46025 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripSeparatorRenderEventArgs.cs @@ -0,0 +1,49 @@ +// +// ToolStripSeparatorRenderEventArgs.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; + +namespace ShiftUI +{ + public class ToolStripSeparatorRenderEventArgs : ToolStripItemRenderEventArgs + { + private bool vertical; + + public ToolStripSeparatorRenderEventArgs (Graphics g, ToolStripSeparator separator, bool vertical) + : base (g, separator) + { + this.vertical = vertical; + } + + #region Public Properties + public bool Vertical { + get { return this.vertical; } + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripSeparatorRenderEventHandler.cs b/source/ShiftUI/ToolStrip/ToolStripSeparatorRenderEventHandler.cs new file mode 100644 index 0000000..c362bcf --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripSeparatorRenderEventHandler.cs @@ -0,0 +1,32 @@ +// +// ToolStripSeparatorRenderEventHandler.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +namespace ShiftUI +{ + public delegate void ToolStripSeparatorRenderEventHandler (object sender, ToolStripSeparatorRenderEventArgs e); +} diff --git a/source/ShiftUI/ToolStrip/ToolStripSplitButton.cs b/source/ShiftUI/ToolStrip/ToolStripSplitButton.cs new file mode 100644 index 0000000..e845b3c --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripSplitButton.cs @@ -0,0 +1,372 @@ +// +// ToolStripSplitButton.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Drawing; +using System.ComponentModel; +using ShiftUI.Design; + +namespace ShiftUI +{ + [DefaultEvent ("ButtonClick")] + [ToolStripItemDesignerAvailability (ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.StatusStrip)] + public class ToolStripSplitButton : ToolStripDropDownItem + { + private bool button_pressed; + private ToolStripItem default_item; + private bool drop_down_button_selected; + private int drop_down_button_width; + + #region Public Constructors + public ToolStripSplitButton() + : this (string.Empty, null, null, string.Empty) + { + } + + public ToolStripSplitButton (Image image) + : this (string.Empty, image, null, string.Empty) + { + } + + public ToolStripSplitButton (string text) + : this (text, null, null, string.Empty) + { + } + + public ToolStripSplitButton (string text, Image image) + : this (text, image, null, string.Empty) + { + } + + public ToolStripSplitButton (string text, Image image, EventHandler onClick) + : this (text, image, onClick, string.Empty) + { + } + + public ToolStripSplitButton (string text, Image image, params ToolStripItem[] dropDownItems) + : base (text, image, dropDownItems) + { + this.ResetDropDownButtonWidth (); + } + + public ToolStripSplitButton (string text, Image image, EventHandler onClick, string name) + : base (text, image, onClick, name) + { + this.ResetDropDownButtonWidth (); + } + #endregion + + #region Public Properties + [DefaultValue (true)] + public new bool AutoToolTip { + get { return base.AutoToolTip; } + set { base.AutoToolTip = value; } + } + + [Browsable (false)] + public Rectangle ButtonBounds { + get { return new Rectangle (Bounds.Left, Bounds.Top, this.Bounds.Width - this.drop_down_button_width - 1, this.Height); } + } + + [Browsable (false)] + public bool ButtonPressed { + get { return this.button_pressed; } + } + + [Browsable (false)] + public bool ButtonSelected { + get { return base.Selected; } + } + + [Browsable (false)] + [DefaultValue (null)] + public ToolStripItem DefaultItem { + get { return this.default_item; } + set { + if (this.default_item != value) { + this.default_item = value; + this.OnDefaultItemChanged (EventArgs.Empty); + } + } + } + + [Browsable (false)] + public Rectangle DropDownButtonBounds { + get { return new Rectangle (this.Bounds.Right - this.drop_down_button_width, 0, this.drop_down_button_width, this.Bounds.Height); } + } + + [Browsable (false)] + public bool DropDownButtonPressed { + get { return this.drop_down_button_selected || (this.HasDropDownItems && this.DropDown.Visible); } + } + + [Browsable (false)] + public bool DropDownButtonSelected { + get { return base.Selected; } + } + + public int DropDownButtonWidth { + get { return this.drop_down_button_width; } + set { + if (value < 0) + throw new ArgumentOutOfRangeException (); + if (this.drop_down_button_width != value) { + this.drop_down_button_width = value; + CalculateAutoSize (); + } + } + } + + [Browsable (false)] + public Rectangle SplitterBounds { + get { return new Rectangle (this.Bounds.Width - this.drop_down_button_width - 1, 0, 1, this.Height); } + } + #endregion + + #region Protected Properties + protected override bool DefaultAutoToolTip { + get { return true; } + } + + protected internal override bool DismissWhenClicked { + get { return true; } + } + #endregion + + #region Public Methods + public override Size GetPreferredSize (Size constrainingSize) + { + // base should calculate the button part for us, add the splitter + // and drop down arrow part to that + Size s = base.GetPreferredSize (constrainingSize); + + if (s.Width < 23) + s.Width = 23; + + // If we are a fixed size, we can't add more in for the drop down + // button, but we can for autosize + if (AutoSize) + s.Width += (this.drop_down_button_width - 2); + + return s; + } + + public virtual void OnButtonDoubleClick (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [ButtonDoubleClickEvent]); + if (eh != null) + eh (this, e); + } + + public void PerformButtonClick () + { + if (this.Enabled) + this.OnButtonClick (EventArgs.Empty); + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public virtual void ResetDropDownButtonWidth () + { + this.DropDownButtonWidth = 11; + } + #endregion + + #region Protected Methods + protected override AccessibleObject CreateAccessibilityInstance () + { + return new ToolStripSplitButtonAccessibleObject (this); + } + + protected override ToolStripDropDown CreateDefaultDropDown () + { + ToolStripDropDownMenu tsddm = new ToolStripDropDownMenu (); + tsddm.OwnerItem = this; + return tsddm; + } + + protected virtual void OnButtonClick (EventArgs e) + { + EventHandler eh = (EventHandler)Events [ButtonClickEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnDefaultItemChanged (EventArgs e) + { + EventHandler eh = (EventHandler)Events [DefaultItemChangedEvent]; + if (eh != null) + eh (this, e); + } + + protected override void OnMouseDown (MouseEventArgs e) + { + if (this.ButtonBounds.Contains (e.Location)) + { + this.button_pressed = true; + this.Invalidate (); + base.OnMouseDown (e); + } + else if (this.DropDownButtonBounds.Contains (e.Location)) + { + if (this.DropDown.Visible) + this.HideDropDown (ToolStripDropDownCloseReason.ItemClicked); + else + this.ShowDropDown (); + + this.Invalidate (); + base.OnMouseDown (e); + } + } + + protected override void OnMouseLeave (EventArgs e) + { + this.drop_down_button_selected = false; + this.button_pressed = false; + + this.Invalidate (); + + base.OnMouseLeave (e); + } + + protected override void OnMouseUp (MouseEventArgs e) + { + this.button_pressed = false; + this.Invalidate (); + + base.OnMouseUp (e); + } + + protected override void OnPaint (PaintEventArgs e) + { + base.OnPaint (e); + + if (this.Owner != null) { + Color font_color = this.Enabled ? this.ForeColor : SystemColors.GrayText; + Image draw_image = this.Enabled ? this.Image : ToolStripRenderer.CreateDisabledImage (this.Image); + + this.Owner.Renderer.DrawSplitButton (new ShiftUI.ToolStripItemRenderEventArgs (e.Graphics, this)); + + Rectangle text_layout_rect; + Rectangle image_layout_rect; + + Rectangle r = this.ContentRectangle; + r.Width -= (this.drop_down_button_width + 1); + + this.CalculateTextAndImageRectangles (r, out text_layout_rect, out image_layout_rect); + + if (text_layout_rect != Rectangle.Empty) + this.Owner.Renderer.DrawItemText (new ShiftUI.ToolStripItemTextRenderEventArgs (e.Graphics, this, this.Text, text_layout_rect, font_color, this.Font, this.TextAlign)); + if (image_layout_rect != Rectangle.Empty) + this.Owner.Renderer.DrawItemImage (new ShiftUI.ToolStripItemImageRenderEventArgs (e.Graphics, this, draw_image, image_layout_rect)); + + this.Owner.Renderer.DrawArrow (new ToolStripArrowRenderEventArgs (e.Graphics, this, new Rectangle (this.Width - 9, 1, 6, this.Height), Color.Black, ArrowDirection.Down)); + + return; + } + } + + protected override void OnRightToLeftChanged (EventArgs e) + { + base.OnRightToLeftChanged (e); + } + + protected internal override bool ProcessDialogKey (Keys keyData) + { + if (this.Selected && keyData == Keys.Enter && this.DefaultItem != null) { + this.DefaultItem.FireEvent (EventArgs.Empty, ToolStripItemEventType.Click); + return true; + } + + return base.ProcessDialogKey (keyData); + } + + protected internal override bool ProcessMnemonic (char charCode) + { + if (!this.Selected) + this.Parent.ChangeSelection (this); + + if (this.HasDropDownItems) + this.ShowDropDown (); + else + this.PerformClick (); + + return true; + } + #endregion + + #region Internal Methods + internal override void HandleClick (int mouse_clicks, EventArgs e) + { + base.HandleClick (mouse_clicks, e); + + MouseEventArgs mea = e as MouseEventArgs; + + if (mea != null) + if (ButtonBounds.Contains (mea.Location)) + OnButtonClick (EventArgs.Empty); + } + #endregion + + #region Public Events + static object ButtonClickEvent = new object (); + static object ButtonDoubleClickEvent = new object (); + static object DefaultItemChangedEvent = new object (); + + public event EventHandler ButtonClick { + add { Events.AddHandler (ButtonClickEvent, value); } + remove {Events.RemoveHandler (ButtonClickEvent, value); } + } + public event EventHandler ButtonDoubleClick { + add { Events.AddHandler (ButtonDoubleClickEvent, value); } + remove {Events.RemoveHandler (ButtonDoubleClickEvent, value); } + } + public event EventHandler DefaultItemChanged { + add { Events.AddHandler (DefaultItemChangedEvent, value); } + remove {Events.RemoveHandler (DefaultItemChangedEvent, value); } + } + #endregion + + #region ToolStripSplitButtonAccessibleObject Class + public class ToolStripSplitButtonAccessibleObject : ToolStripItemAccessibleObject + { + #region Public Constructor + public ToolStripSplitButtonAccessibleObject (ToolStripSplitButton item) : base (item) + { + } + #endregion + + #region Public Method + public override void DoDefaultAction () + { + (owner_item as ToolStripSplitButton).PerformButtonClick (); + } + #endregion + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripSplitStackLayout.cs b/source/ShiftUI/ToolStrip/ToolStripSplitStackLayout.cs new file mode 100644 index 0000000..9124adb --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripSplitStackLayout.cs @@ -0,0 +1,264 @@ +// +// ToolStripSplitStackLayout.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Drawing; +using ShiftUI.Layout; + +namespace ShiftUI +{ + class ToolStripSplitStackLayout : LayoutEngine + { + public override bool Layout (object container, LayoutEventArgs args) + { + if (container is ToolStrip) + { + ToolStrip ts = (ToolStrip)container; + + if (ts.Items == null) + return false; + + Rectangle ts_rect = ts.DisplayRectangle; + + // Mono hasn't yet implemented ToolStripLayoutStyle.Table, so it comes here + // for layout. The default (minimal) Table layout is 1 column, any number of rows, + // which translates effectively to Vertical orientation. + if (ts.Orientation == Orientation.Horizontal && ts.LayoutStyle != ToolStripLayoutStyle.Table) + LayoutHorizontalToolStrip (ts, ts_rect); + else + LayoutVerticalToolStrip (ts, ts_rect); + + return false; + } else { + ToolStripContentPanel ts = (ToolStripContentPanel)container; + int x = ts.DisplayRectangle.Left; + int y = ts.DisplayRectangle.Top; + + foreach (ToolStrip tsi in ts.Widgets) { + Rectangle new_bounds = new Rectangle (); + + x += tsi.Margin.Left; + + new_bounds.Location = new Point (x, y + tsi.Margin.Top); + new_bounds.Height = ts.DisplayRectangle.Height - tsi.Margin.Vertical; + new_bounds.Width = tsi.GetToolStripPreferredSize (new Size (0, new_bounds.Height)).Width; + + tsi.Width = new_bounds.Width + 12; + + x += new_bounds.Width + tsi.Margin.Right; + } + } + + return false; + } + + private void LayoutHorizontalToolStrip (ToolStrip ts, Rectangle bounds) + { + //if (!ts.Visible) return; + + ToolStripItemOverflow[] overflow = new ToolStripItemOverflow[ts.Items.Count]; + ToolStripItemPlacement[] placement = new ToolStripItemPlacement[ts.Items.Count]; + Size proposedSize = new Size (0, bounds.Height); + int[] widths = new int[ts.Items.Count]; + int total_width = 0; + int toolstrip_width = bounds.Width; + int i = 0; + bool can_overflow = ts.CanOverflow & !(ts is MenuStrip) & !(ts is StatusStrip); + bool need_overflow = false; + + foreach (ToolStripItem tsi in ts.Items) { + overflow[i] = tsi.Overflow; + placement[i] = tsi.Overflow == ToolStripItemOverflow.Always ? ToolStripItemPlacement.Overflow : ToolStripItemPlacement.Main; + widths[i] = tsi.GetPreferredSize (proposedSize).Width + tsi.Margin.Horizontal; + if (!tsi.Available) + placement[i] = ToolStripItemPlacement.None; + total_width += placement[i] == ToolStripItemPlacement.Main ? widths[i] : 0; + + if (placement[i] == ToolStripItemPlacement.Overflow) + need_overflow = true; + i++; + } + + // This is needed for a button set to Overflow = Always + if (need_overflow) { + ts.OverflowButton.Visible = true; + ts.OverflowButton.SetBounds (new Rectangle (ts.Width - 16, 0, 16, ts.Height)); + toolstrip_width -= ts.OverflowButton.Width; + } else + ts.OverflowButton.Visible = false; + + while (total_width > toolstrip_width) { + // If we can overflow, get our overflow button setup, and subtract it's width + // from our available width + if (can_overflow && !ts.OverflowButton.Visible) { + ts.OverflowButton.Visible = true; + ts.OverflowButton.SetBounds (new Rectangle (ts.Width - 16, 0, 16, ts.Height)); + toolstrip_width -= ts.OverflowButton.Width; + } + + bool removed_one = false; + + // Start at the right, removing Overflow.AsNeeded first + for (int j = widths.Length - 1; j >= 0; j--) + if (overflow[j] == ToolStripItemOverflow.AsNeeded && placement[j] == ToolStripItemPlacement.Main) { + placement[j] = ToolStripItemPlacement.Overflow; + total_width -= widths[j]; + removed_one = true; + break; + } + + // If we didn't remove any AsNeeded ones, we have to start removing Never ones + // These are not put on the Overflow, they are simply not shown + if (!removed_one) + for (int j = widths.Length - 1; j >= 0; j--) + if (overflow[j] == ToolStripItemOverflow.Never && placement[j] == ToolStripItemPlacement.Main) { + placement[j] = ToolStripItemPlacement.None; + total_width -= widths[j]; + removed_one = true; + break; + } + + // There's nothing left to remove, break or we will loop forever + if (!removed_one) + break; + } + + i = 0; + Point start_layout_pointer = new Point (ts.DisplayRectangle.Left, ts.DisplayRectangle.Top); + Point end_layout_pointer = new Point (ts.DisplayRectangle.Right, ts.DisplayRectangle.Top); + int button_height = ts.DisplayRectangle.Height; + + // Now we should know where everything goes, so lay everything out + foreach (ToolStripItem tsi in ts.Items) { + tsi.SetPlacement (placement[i]); + + if (placement[i] == ToolStripItemPlacement.Main) { + if (tsi.Alignment == ToolStripItemAlignment.Left) { + tsi.SetBounds (new Rectangle (start_layout_pointer.X + tsi.Margin.Left, start_layout_pointer.Y + tsi.Margin.Top, widths[i] - tsi.Margin.Horizontal, button_height - tsi.Margin.Vertical)); + start_layout_pointer.X += widths[i]; + } else { + tsi.SetBounds (new Rectangle (end_layout_pointer.X - tsi.Margin.Right - tsi.Width, end_layout_pointer.Y + tsi.Margin.Top, widths[i] - tsi.Margin.Horizontal, button_height - tsi.Margin.Vertical)); + end_layout_pointer.X -= widths[i]; + } + } + + i++; + } + } + + private void LayoutVerticalToolStrip (ToolStrip ts, Rectangle bounds) + { + if (!ts.Visible) return; + + ToolStripItemOverflow[] overflow = new ToolStripItemOverflow[ts.Items.Count]; + ToolStripItemPlacement[] placement = new ToolStripItemPlacement[ts.Items.Count]; + Size proposedSize = new Size (bounds.Width, 0); + int[] heights = new int[ts.Items.Count]; + int[] widths = new int[ts.Items.Count]; // needed if ts.LayoutStyle == ToolStripLayoutStyle.Table + int total_height = 0; + int toolstrip_height = bounds.Height; + int i = 0; + bool can_overflow = ts.CanOverflow & !(ts is MenuStrip) & !(ts is StatusStrip); + + foreach (ToolStripItem tsi in ts.Items) { + overflow[i] = tsi.Overflow; + placement[i] = tsi.Overflow == ToolStripItemOverflow.Always ? ToolStripItemPlacement.Overflow : ToolStripItemPlacement.Main; + var size = tsi.GetPreferredSize (proposedSize); + heights[i] = size.Height + tsi.Margin.Vertical; + widths[i] = size.Width + tsi.Margin.Horizontal; + if (!tsi.Available) + placement[i] = ToolStripItemPlacement.None; + total_height += placement[i] == ToolStripItemPlacement.Main ? heights[i] : 0; + i++; + } + + ts.OverflowButton.Visible = false; + + while (total_height > toolstrip_height) { + // If we can overflow, get our overflow button setup, and subtract it's width + // from our available width + if (can_overflow && !ts.OverflowButton.Visible) { + ts.OverflowButton.Visible = true; + ts.OverflowButton.SetBounds (new Rectangle (0, ts.Height - 16, ts.Width, 16)); + toolstrip_height -= ts.OverflowButton.Height; + } + + bool removed_one = false; + + // Start at the right, removing Overflow.AsNeeded first + for (int j = heights.Length - 1; j >= 0; j--) + if (overflow[j] == ToolStripItemOverflow.AsNeeded && placement[j] == ToolStripItemPlacement.Main) { + placement[j] = ToolStripItemPlacement.Overflow; + total_height -= heights[j]; + removed_one = true; + break; + } + + // If we didn't remove any AsNeeded ones, we have to start removing Never ones + // These are not put on the Overflow, they are simply not shown + if (!removed_one) + for (int j = heights.Length - 1; j >= 0; j--) + if (overflow[j] == ToolStripItemOverflow.Never && placement[j] == ToolStripItemPlacement.Main) { + placement[j] = ToolStripItemPlacement.None; + total_height -= heights[j]; + removed_one = true; + break; + } + + // There's nothing left to remove, break or we will loop forever + if (!removed_one) + break; + } + + i = 0; + Point start_layout_pointer = new Point (ts.DisplayRectangle.Left, ts.DisplayRectangle.Top); + Point end_layout_pointer = new Point (ts.DisplayRectangle.Left, ts.DisplayRectangle.Bottom); + int button_width = ts.DisplayRectangle.Width; + + // Now we should know where everything goes, so lay everything out + foreach (ToolStripItem tsi in ts.Items) { + tsi.SetPlacement (placement[i]); + // Table layout is defined to lay out items flush left. + if (ts.LayoutStyle == ToolStripLayoutStyle.Table) + button_width = widths[i]; + + if (placement[i] == ToolStripItemPlacement.Main) { + if (tsi.Alignment == ToolStripItemAlignment.Left) { + tsi.SetBounds (new Rectangle (start_layout_pointer.X + tsi.Margin.Left, start_layout_pointer.Y + tsi.Margin.Top, button_width - tsi.Margin.Horizontal, heights[i] - tsi.Margin.Vertical)); + start_layout_pointer.Y += heights[i]; + } else { + tsi.SetBounds (new Rectangle (end_layout_pointer.X + tsi.Margin.Left, end_layout_pointer.Y - tsi.Margin.Bottom - tsi.Height, button_width - tsi.Margin.Horizontal, heights[i] - tsi.Margin.Vertical)); + start_layout_pointer.Y += heights[i]; + } + } + + i++; + } + } + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripStatusLabel.cs b/source/ShiftUI/ToolStrip/ToolStripStatusLabel.cs new file mode 100644 index 0000000..83236d3 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripStatusLabel.cs @@ -0,0 +1,129 @@ +// +// StatusStrip.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Drawing; +using System.ComponentModel; +using System.Runtime.InteropServices; +using ShiftUI.Design; + +namespace ShiftUI +{ + [ToolStripItemDesignerAvailability (ToolStripItemDesignerAvailability.StatusStrip)] + public class ToolStripStatusLabel : ToolStripLabel + { + private ToolStripStatusLabelBorderSides border_sides; + private Border3DStyle border_style; + private bool spring; + + #region Public Constructors + public ToolStripStatusLabel () + : this (String.Empty, null, null, String.Empty) + { + } + + public ToolStripStatusLabel (Image image) + : this (String.Empty, image, null, String.Empty) + { + } + + public ToolStripStatusLabel (string text) + : this (text, null, null, String.Empty) + { + } + + public ToolStripStatusLabel (string text, Image image) + : this (text, image, null, String.Empty) + { + } + + public ToolStripStatusLabel (string text, Image image, EventHandler onClick) + : this (text, image, onClick, String.Empty) + { + } + + public ToolStripStatusLabel (string text, Image image, EventHandler onClick, string name) + : base (text, image, false, onClick, name) + { + this.border_style = Border3DStyle.Flat; + } + #endregion + + #region Public Properties + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public new ToolStripItemAlignment Alignment { + get { return base.Alignment; } + set { base.Alignment = value; } + } + + [DefaultValue (ToolStripStatusLabelBorderSides.None)] + public ToolStripStatusLabelBorderSides BorderSides { + get { return this.border_sides; } + set { this.border_sides = value; } + } + + [DefaultValue (Border3DStyle.Flat)] + public Border3DStyle BorderStyle { + get { return this.border_style; } + set { this.border_style = value; } + } + + [DefaultValue (false)] + public bool Spring { + get { return this.spring; } + set { + if (this.spring != value) { + this.spring = value; + CalculateAutoSize (); + } + } + } + #endregion + + #region Protected Properties + protected internal override Padding DefaultMargin { + get { return new Padding (0, 3, 0, 2); } + } + #endregion + + #region Public Methods + public override Size GetPreferredSize (Size constrainingSize) + { + return base.GetPreferredSize (constrainingSize); + } + #endregion + + #region Protected Methods + protected override void OnPaint (PaintEventArgs e) + { + base.OnPaint (e); + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripStatusLabelBorderSides.cs b/source/ShiftUI/ToolStrip/ToolStripStatusLabelBorderSides.cs new file mode 100644 index 0000000..1a500cb --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripStatusLabelBorderSides.cs @@ -0,0 +1,49 @@ +// +// ToolStripStatusLabelBorderSides.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +using System.Runtime.InteropServices; +using System.ComponentModel; +using System; + +namespace ShiftUI +{ + [Flags] + [ComVisible(true)] + //[Editor ("ShiftUI.Design.BorderSidesEditor, " + Consts.AssemblySystem_Design, + //"System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)] + public enum ToolStripStatusLabelBorderSides + { + None = 0, + Left = 1, + Top = 2, + Right = 4, + Bottom = 8, + All = 15 + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripSystemRenderer.cs b/source/ShiftUI/ToolStrip/ToolStripSystemRenderer.cs new file mode 100644 index 0000000..beccd13 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripSystemRenderer.cs @@ -0,0 +1,130 @@ +// +// ToolStripSystemRenderer.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using ShiftUI.Theming; + +namespace ShiftUI +{ + public class ToolStripSystemRenderer : ToolStripRenderer + { + #region Public Constructor + public ToolStripSystemRenderer () + { + } + #endregion + + #region Protected Methods + protected override void OnRenderButtonBackground (ToolStripItemRenderEventArgs e) + { + ThemeElements.CurrentTheme.ToolStripPainter.OnRenderButtonBackground (e); + + base.OnRenderButtonBackground (e); + } + + protected override void OnRenderDropDownButtonBackground (ToolStripItemRenderEventArgs e) + { + ThemeElements.CurrentTheme.ToolStripPainter.OnRenderDropDownButtonBackground (e); + + base.OnRenderDropDownButtonBackground (e); + } + + protected override void OnRenderGrip (ToolStripGripRenderEventArgs e) + { + ThemeElements.CurrentTheme.ToolStripPainter.OnRenderGrip (e); + + base.OnRenderGrip (e); + } + + protected override void OnRenderImageMargin (ToolStripRenderEventArgs e) + { + base.OnRenderImageMargin (e); + } + + protected override void OnRenderItemBackground (ToolStripItemRenderEventArgs e) + { + base.OnRenderItemBackground (e); + } + + protected override void OnRenderLabelBackground (ToolStripItemRenderEventArgs e) + { + base.OnRenderLabelBackground (e); + } + + protected override void OnRenderMenuItemBackground (ToolStripItemRenderEventArgs e) + { + ThemeElements.CurrentTheme.ToolStripPainter.OnRenderMenuItemBackground (e); + + base.OnRenderMenuItemBackground (e); + } + + protected override void OnRenderOverflowButtonBackground (ToolStripItemRenderEventArgs e) + { + ThemeElements.CurrentTheme.ToolStripPainter.OnRenderOverflowButtonBackground (e); + + base.OnRenderOverflowButtonBackground (e); + } + + protected override void OnRenderSeparator (ToolStripSeparatorRenderEventArgs e) + { + ThemeElements.CurrentTheme.ToolStripPainter.OnRenderSeparator (e); + + base.OnRenderSeparator (e); + } + + protected override void OnRenderSplitButtonBackground (ToolStripItemRenderEventArgs e) + { + ThemeElements.CurrentTheme.ToolStripPainter.OnRenderSplitButtonBackground (e); + + base.OnRenderSplitButtonBackground (e); + } + + protected override void OnRenderToolStripBackground (ToolStripRenderEventArgs e) + { + ThemeElements.CurrentTheme.ToolStripPainter.OnRenderToolStripBackground (e); + + base.OnRenderToolStripBackground (e); + } + + protected override void OnRenderToolStripBorder (ToolStripRenderEventArgs e) + { + ThemeElements.CurrentTheme.ToolStripPainter.OnRenderToolStripBorder (e); + + base.OnRenderToolStripBorder (e); + } + + protected override void OnRenderToolStripStatusLabelBackground (ToolStripItemRenderEventArgs e) + { + base.OnRenderToolStripStatusLabelBackground (e); + } + #endregion + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripTextBox.cs b/source/ShiftUI/ToolStrip/ToolStripTextBox.cs new file mode 100644 index 0000000..eeabbba --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripTextBox.cs @@ -0,0 +1,590 @@ +// +// ToolStripTextBox.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System.ComponentModel; +using ShiftUI.Design; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI +{ + [ToolStripItemDesignerAvailability (ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.MenuStrip | ToolStripItemDesignerAvailability.ContextMenuStrip)] + public class ToolStripTextBox : ToolStripWidgetHost + { + private BorderStyle border_style; + + #region Public Constructors + public ToolStripTextBox () : base (new ToolStripTextBoxWidget ()) + { + ToolStripTextBoxWidget text_box = TextBox as ToolStripTextBoxWidget; + text_box.OwnerItem = this; + text_box.border_style = BorderStyle.None; + text_box.TopMargin = 3; // need to explicitly set the margin + text_box.Border = BorderStyle.Fixed3D; // ToolStripTextBoxWidget impl, not TextBox + this.border_style = BorderStyle.Fixed3D; + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public ToolStripTextBox (Widget c) : base (c) + { + throw new NotSupportedException ("This construtor cannot be used."); + } + + public ToolStripTextBox (string name) : this () + { + base.Name = name; + } + #endregion + + #region Public Properties + [DefaultValue (false)] + public bool AcceptsReturn { + get { return this.TextBox.AcceptsReturn; } + set { this.TextBox.AcceptsReturn = value; } + } + + [DefaultValue (false)] + public bool AcceptsTab { + get { return this.TextBox.AcceptsTab; } + set { this.TextBox.AcceptsTab = value; } + } + + [MonoTODO ("AutoCompletion algorithm is currently not implemented.")] + [Browsable (true)] + [Localizable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + //[Editor ("ShiftUI.Design.ListWidgetStringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + public AutoCompleteStringCollection AutoCompleteCustomSource { + get { return this.TextBox.AutoCompleteCustomSource; } + set { this.TextBox.AutoCompleteCustomSource = value; } + } + + [MonoTODO("AutoCompletion algorithm is currently not implemented.")] + [Browsable (true)] + [DefaultValue (AutoCompleteMode.None)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public AutoCompleteMode AutoCompleteMode { + get { return this.TextBox.AutoCompleteMode; } + set { this.TextBox.AutoCompleteMode = value; } + } + + [MonoTODO("AutoCompletion algorithm is currently not implemented.")] + [Browsable (true)] + [DefaultValue (AutoCompleteSource.None)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public AutoCompleteSource AutoCompleteSource { + get { return this.TextBox.AutoCompleteSource; } + set { this.TextBox.AutoCompleteSource = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override Image BackgroundImage { + get { return base.BackgroundImage; } + set { base.BackgroundImage = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + [DefaultValue (BorderStyle.Fixed3D)] + [DispId (-504)] + public BorderStyle BorderStyle { + get { return this.border_style; } + set { + if (this.border_style != value) { + this.border_style = value; + (base.Widget as ToolStripTextBoxWidget).Border = value; + this.OnBorderStyleChanged (EventArgs.Empty); + } + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public bool CanUndo { + get { return this.TextBox.CanUndo; } + } + + [DefaultValue (CharacterCasing.Normal)] + public CharacterCasing CharacterCasing { + get { return this.TextBox.CharacterCasing; } + set { this.TextBox.CharacterCasing = value; } + } + + [DefaultValue (true)] + public bool HideSelection { + get { return this.TextBox.HideSelection; } + set { this.TextBox.HideSelection = value; } + } + + [Localizable (true)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[Editor ("ShiftUI.Design.StringArrayEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + public string[] Lines { + get { return this.TextBox.Lines; } + set { this.TextBox.Lines = value; } + } + + [Localizable (true)] + [DefaultValue (32767)] + public int MaxLength { + get { return this.TextBox.MaxLength; } + set { this.TextBox.MaxLength = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public bool Modified { + get { return this.TextBox.Modified; } + set { this.TextBox.Modified = value; } + } + + [Localizable (true)] + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + [DefaultValue (false)] + [RefreshProperties (RefreshProperties.All)] + public bool Multiline { + get { return this.TextBox.Multiline; } + set { this.TextBox.Multiline = value; } + } + + [DefaultValue (false)] + public bool ReadOnly { + get { return this.TextBox.ReadOnly; } + set { this.TextBox.ReadOnly = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public string SelectedText { + get { return this.TextBox.SelectedText; } + set { this.TextBox.SelectedText = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public int SelectionLength { + get { return this.TextBox.SelectionLength == -1 ? 0 : this.TextBox.SelectionLength; } + set { this.TextBox.SelectionLength = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public int SelectionStart { + get { return this.TextBox.SelectionStart; } + set { this.TextBox.SelectionStart = value; } + } + + [DefaultValue (true)] + public bool ShortcutsEnabled { + get { return this.TextBox.ShortcutsEnabled; } + set { this.TextBox.ShortcutsEnabled = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public TextBox TextBox { + get { return (TextBox)base.Widget; } + } + + [Localizable (true)] + [DefaultValue (HorizontalAlignment.Left)] + public HorizontalAlignment TextBoxTextAlign { + get { return this.TextBox.TextAlign; } + set { this.TextBox.TextAlign = value; } + } + + [Browsable (false)] + public int TextLength { + get { return this.TextBox.TextLength; } + } + + [Localizable (true)] + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + [DefaultValue (true)] + public bool WordWrap { + get { return this.TextBox.WordWrap; } + set { this.TextBox.WordWrap = value; } + } + #endregion + + #region Protected Properties + protected internal override Padding DefaultMargin { get { return new Padding (1, 0, 1, 0); } } + protected override Size DefaultSize { get { return new Size (100, 22); } } + #endregion + + #region Public Methods + public void AppendText (string text) + { + this.TextBox.AppendText (text); + } + + public void Clear () + { + this.TextBox.Clear (); + } + + public void ClearUndo () + { + this.TextBox.ClearUndo (); + } + + public void Copy () + { + this.TextBox.Copy (); + } + + public void Cut () + { + this.TextBox.Cut (); + } + + public void DeselectAll () + { + this.TextBox.DeselectAll (); + } + + public char GetCharFromPosition (Point pt) + { + return this.TextBox.GetCharFromPosition (pt); + } + + public int GetCharIndexFromPosition (Point pt) + { + return this.TextBox.GetCharIndexFromPosition (pt); + } + + public int GetFirstCharIndexFromLine (int lineNumber) + { + return this.TextBox.GetFirstCharIndexFromLine (lineNumber); + } + + public int GetFirstCharIndexOfCurrentLine () + { + return this.TextBox.GetFirstCharIndexOfCurrentLine (); + } + + public int GetLineFromCharIndex (int index) + { + return this.TextBox.GetLineFromCharIndex (index); + } + + public Point GetPositionFromCharIndex (int index) + { + return this.TextBox.GetPositionFromCharIndex (index); + } + + public override Size GetPreferredSize (Size constrainingSize) + { + return base.GetPreferredSize (constrainingSize); + } + + public void Paste () + { + this.TextBox.Paste (); + } + + public void ScrollToCaret () + { + this.TextBox.ScrollToCaret (); + } + + public void Select (int start, int length) + { + this.TextBox.Select (start, length); + } + + public void SelectAll () + { + this.TextBox.SelectAll (); + } + + public void Undo () + { + this.TextBox.Undo (); + } + #endregion + + #region Protected Methods + protected virtual void OnAcceptsTabChanged (EventArgs e) + { + EventHandler eh = (EventHandler)Events [AcceptsTabChangedEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnBorderStyleChanged (EventArgs e) + { + EventHandler eh = (EventHandler)Events [BorderStyleChangedEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnHideSelectionChanged (EventArgs e) + { + EventHandler eh = (EventHandler)Events [HideSelectionChangedEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnModifiedChanged (EventArgs e) + { + EventHandler eh = (EventHandler)Events [ModifiedChangedEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnMultilineChanged (EventArgs e) + { + EventHandler eh = (EventHandler)Events [MultilineChangedEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnReadOnlyChanged (EventArgs e) + { + EventHandler eh = (EventHandler)Events [ReadOnlyChangedEvent]; + if (eh != null) + eh (this, e); + } + + protected override void OnSubscribeWidgetEvents (Widget Widget) + { + base.OnSubscribeWidgetEvents (Widget); + + this.TextBox.AcceptsTabChanged += new EventHandler (HandleAcceptsTabChanged); + this.TextBox.HideSelectionChanged += new EventHandler (HandleHideSelectionChanged); + this.TextBox.ModifiedChanged += new EventHandler (HandleModifiedChanged); + this.TextBox.MultilineChanged += new EventHandler (HandleMultilineChanged); + this.TextBox.ReadOnlyChanged += new EventHandler (HandleReadOnlyChanged); + this.TextBox.TextAlignChanged += new EventHandler (HandleTextAlignChanged); + this.TextBox.TextChanged += new EventHandler (HandleTextChanged); + } + + protected override void OnUnsubscribeWidgetEvents (Widget Widget) + { + base.OnUnsubscribeWidgetEvents (Widget); + } + #endregion + + #region Public Events + static object AcceptsTabChangedEvent = new object (); + static object BorderStyleChangedEvent = new object (); + static object HideSelectionChangedEvent = new object (); + static object ModifiedChangedEvent = new object (); + static object MultilineChangedEvent = new object (); + static object ReadOnlyChangedEvent = new object (); + static object TextBoxTextAlignChangedEvent = new object (); + + public event EventHandler AcceptsTabChanged { + add { Events.AddHandler (AcceptsTabChangedEvent, value); } + remove {Events.RemoveHandler (AcceptsTabChangedEvent, value); } + } + public event EventHandler BorderStyleChanged { + add { Events.AddHandler (BorderStyleChangedEvent, value); } + remove {Events.RemoveHandler (BorderStyleChangedEvent, value); } + } + public event EventHandler HideSelectionChanged { + add { Events.AddHandler (HideSelectionChangedEvent, value); } + remove {Events.RemoveHandler (HideSelectionChangedEvent, value); } + } + public event EventHandler ModifiedChanged { + add { Events.AddHandler (ModifiedChangedEvent, value); } + remove {Events.RemoveHandler (ModifiedChangedEvent, value); } + } + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public event EventHandler MultilineChanged { + add { Events.AddHandler (MultilineChangedEvent, value); } + remove {Events.RemoveHandler (MultilineChangedEvent, value); } + } + public event EventHandler ReadOnlyChanged { + add { Events.AddHandler (ReadOnlyChangedEvent, value); } + remove {Events.RemoveHandler (ReadOnlyChangedEvent, value); } + } + public event EventHandler TextBoxTextAlignChanged { + add { Events.AddHandler (TextBoxTextAlignChangedEvent, value); } + remove {Events.RemoveHandler (TextBoxTextAlignChangedEvent, value); } + } + #endregion + + #region Private Methods + private void HandleTextAlignChanged (object sender, EventArgs e) + { + EventHandler eh = (EventHandler)(Events [TextBoxTextAlignChangedEvent]); + if (eh != null) + eh (this, e); + } + + private void HandleReadOnlyChanged (object sender, EventArgs e) + { + OnReadOnlyChanged (e); + } + + private void HandleMultilineChanged (object sender, EventArgs e) + { + OnMultilineChanged (e); + } + + private void HandleModifiedChanged (object sender, EventArgs e) + { + OnModifiedChanged (e); + } + + private void HandleHideSelectionChanged (object sender, EventArgs e) + { + OnHideSelectionChanged (e); + } + + private void HandleAcceptsTabChanged (object sender, EventArgs e) + { + OnAcceptsTabChanged (e); + } + + private void HandleTextChanged (object sender, EventArgs e) + { + OnTextChanged (e); + } + #endregion + + private class ToolStripTextBoxWidget : TextBox + { + private BorderStyle border; + private Timer tooltip_timer; + private ToolTip tooltip_window; + private ToolStripItem owner_item; + + public ToolStripTextBoxWidget () : base () + { + } + + protected override void OnLostFocus (EventArgs e) + { + base.OnLostFocus (e); + Invalidate (); + } + + protected override void OnMouseEnter (EventArgs e) + { + base.OnMouseEnter (e); + Invalidate (); + + if (ShowToolTips) + ToolTipTimer.Start (); + + } + + protected override void OnMouseLeave (EventArgs e) + { + base.OnMouseLeave (e); + Invalidate (); + + ToolTipTimer.Stop (); + ToolTipWindow.Hide (this); + } + + internal override void OnPaintInternal (PaintEventArgs e) + { + base.OnPaintInternal (e); + + if ((this.Focused || this.Entered || border == BorderStyle.FixedSingle) && border != BorderStyle.None) { + ToolStripRenderer tsr = (this.Parent as ToolStrip).Renderer; + + if (tsr is ToolStripProfessionalRenderer) + using (Pen p = new Pen ((tsr as ToolStripProfessionalRenderer).ColorTable.ButtonSelectedBorder)) + e.Graphics.DrawRectangle (p, new Rectangle (0, 0, this.Width - 1, this.Height - 1)); + } + } + + internal BorderStyle Border { + set { + border = value; + Invalidate (); + } + } + + internal ToolStripItem OwnerItem { + set { owner_item = value; } + } + + #region Stuff for ToolTips + private bool ShowToolTips { + get { + if (Parent == null) + return false; + + return (Parent as ToolStrip).ShowItemToolTips; + } + } + + private Timer ToolTipTimer { + get { + if (tooltip_timer == null) { + tooltip_timer = new Timer (); + tooltip_timer.Enabled = false; + tooltip_timer.Interval = 500; + tooltip_timer.Tick += new EventHandler (ToolTipTimer_Tick); + } + + return tooltip_timer; + } + } + + private ToolTip ToolTipWindow { + get { + if (tooltip_window == null) + tooltip_window = new ToolTip (); + + return tooltip_window; + } + } + + private void ToolTipTimer_Tick (object o, EventArgs args) + { + string tooltip = owner_item.GetToolTip (); + + if (!string.IsNullOrEmpty (tooltip)) + ToolTipWindow.Present (this, tooltip); + + ToolTipTimer.Stop (); + } + #endregion + } + } +} diff --git a/source/ShiftUI/ToolStrip/ToolStripTextDirection.cs b/source/ShiftUI/ToolStrip/ToolStripTextDirection.cs new file mode 100644 index 0000000..4670889 --- /dev/null +++ b/source/ShiftUI/ToolStrip/ToolStripTextDirection.cs @@ -0,0 +1,39 @@ +// +// ToolStripTextDirection.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + + +namespace ShiftUI +{ + public enum ToolStripTextDirection + { + Inherit = 0, + Horizontal = 1, + Vertical90 = 2, + Vertical270 = 3 + } +} diff --git a/source/ShiftUI/Widget.cs b/source/ShiftUI/Widget.cs new file mode 100644 index 0000000..ebd6709 --- /dev/null +++ b/source/ShiftUI/Widget.cs @@ -0,0 +1,6728 @@ +// The "Widget" class is based off the Windows Forms "Widget" class in +// the Mono framework. As some elements are unchanged, here's a +// copyright statement. + +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// Partially based on work by: +// Aleksey Ryabchuk ryabchuk@yahoo.com +// Alexandre Pigolkine pigolkine@gmx.de +// Dennis Hayes dennish@raytek.com +// Jaak Simm jaaksimm@firm.ee +// John Sohn jsohn@columbus.rr.com +// + +#undef DebugRecreate +#undef DebugFocus +#undef DebugMessages + +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.ComponentModel.Design.Serialization; +using System.Collections; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security; +using System.Threading; +using ShiftUI; +using System.Collections.Generic; +using System.Linq; + +namespace ShiftUI +{ + public class ToolboxWidgetAttribute : Attribute + { + public ToolboxWidgetAttribute() + { + + } + } + + [ComVisible(true)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [DefaultProperty("Text")] + [DefaultEvent("Click")] + [ToolboxItemFilter("ShiftUI")] + public class Widget : Component, ISynchronizeInvoke, IWin32Window + , IBindableComponent, IDropTarget, IBounds + { + #region Local Variables + + public static List GetAllToolboxWidgets() + { + var widget_list = new List(); + var typesWithToolboxAttribute = + from a in AppDomain.CurrentDomain.GetAssemblies() + from t in a.GetTypes() + let attributes = t.GetCustomAttributes(typeof(ToolboxWidgetAttribute), true) + where attributes != null && attributes.Length > 0 + select new { Type = t, Attributes = attributes.Cast() }; + foreach (var t in typesWithToolboxAttribute) + { + widget_list.Add(t.Type); + } + return widget_list; + } + + // Basic + internal Rectangle bounds; // bounding rectangle for Widget (client area + decorations) + Rectangle explicit_bounds; // explicitly set bounds + internal object creator_thread; // thread that created the Widget + internal WidgetNativeWindow window; // object for native window handle + private IWindowTarget window_target; + string name; // for object naming + + // State + bool is_created; // true if OnCreateWidget has been sent + internal bool has_focus; // true if Widget has focus + internal bool is_visible; // true if Widget is visible + internal bool is_entered; // is the mouse inside the Widget? + internal bool is_enabled; // true if Widget is enabled (usable/not grayed out) + bool is_accessible; // true if the Widget is visible to accessibility applications + bool is_captured; // tracks if the Widget has captured the mouse + internal bool is_toplevel; // tracks if the Widget is a toplevel window + bool is_recreating; // tracks if the handle for the Widget is being recreated + bool causes_validation; // tracks if validation is executed on changes + bool is_focusing; // tracks if Focus has been called on the Widget and has not yet finished + int tab_index; // position in tab order of siblings + bool tab_stop; // is the Widget a tab stop? + bool is_disposed; // has the window already been disposed? + bool is_disposing; // is the window getting disposed? + Size client_size; // size of the client area (window excluding decorations) + Rectangle client_rect; // rectangle with the client area (window excluding decorations) + Widgetstyles Widget_style; // rather win32-specific, style bits for Widget + ImeMode ime_mode; + object Widget_tag; // object that contains data about our Widget + internal int mouse_clicks; // Counter for mouse clicks + Cursor cursor; // Cursor for the window + internal bool allow_drop; // true if the Widget accepts droping objects on it + Region clip_region; // User-specified clip region for the window + + // Visuals + internal Color foreground_color; // foreground color for Widget + internal Color background_color; // background color for Widget + Image background_image; // background image for Widget + internal Font font; // font for Widget + string text; // window/title text for Widget + internal BorderStyle border_style; // Border style of Widget + bool show_keyboard_cues; // Current keyboard cues + internal bool show_focus_cues; // Current focus cues + internal bool force_double_buffer; // Always doublebuffer regardless of Widgetstyle + + // Layout + internal enum LayoutType { + Anchor, + Dock + } + Layout.LayoutEngine layout_engine; + internal int layout_suspended; + bool layout_pending; // true if our parent needs to re-layout us + internal AnchorStyles anchor_style; // anchoring requirements for our Widget + internal DockStyle dock_style; // docking requirements for our Widget + LayoutType layout_type; + private bool recalculate_distances = true; // Delay anchor calculations + + // Please leave the next 2 as internal until DefaultLayout (2.0) is rewritten + internal int dist_right; // distance to the right border of the parent + internal int dist_bottom; // distance to the bottom border of the parent + + // to be categorized... + WidgetCollection child_Widgets; // our children + Widget parent; // our parent Widget + BindingContext binding_context; + RightToLeft right_to_left; // drawing direction for Widget + //ContextMenu context_menu; // FIXME: No. + internal bool use_compatible_text_rendering; + private bool use_wait_cursor; + + //accessibility + string accessible_name; + string accessible_description; + string accessible_default_action; + AccessibleRole accessible_role = AccessibleRole.Default; + AccessibleObject accessibility_object; // object that contains accessibility information about our Widget + + // double buffering + DoubleBuffer backbuffer; + + WidgetBindingsCollection data_bindings; + + static bool verify_thread_handle; + Padding padding; + ImageLayout backgroundimage_layout; + Size maximum_size; + Size minimum_size; + Padding margin; + private ContextMenuStrip context_menu_strip; + private bool nested_layout = false; + Point auto_scroll_offset; + private AutoSizeMode auto_size_mode; + private bool suppressing_key_press; + private ContentAlignment alignment; + + #endregion // Local Variables + + public ContentAlignment Alignment { + get { + return alignment; + } + set { + alignment = value; + } + } + + #region Private Classes + // This helper class allows us to dispatch messages to Widget.WndProc + internal class WidgetNativeWindow : NativeWindow { + private Widget owner; + + public WidgetNativeWindow(Widget Widget) : base() { + this.owner=Widget; + } + + + public Widget Owner { + get { + return owner; + } + } + + protected override void OnHandleChange() + { + this.owner.WindowTarget.OnHandleChange(this.owner.Handle); + } + + static internal Widget WidgetFromHandle(IntPtr hWnd) { + WidgetNativeWindow window; + + window = (WidgetNativeWindow)NativeWindow.FromHandle (hWnd); + if (window != null) { + return window.owner; + } + + return null; + } + + static internal Widget WidgetFromChildHandle (IntPtr handle) { + WidgetNativeWindow window; + + Hwnd hwnd = Hwnd.ObjectFromHandle (handle); + while (hwnd != null) { + window = (WidgetNativeWindow)NativeWindow.FromHandle (handle); + if (window != null) { + return window.owner; + } + hwnd = hwnd.Parent; + } + + return null; + } + + protected override void WndProc(ref Message m) { + owner.WindowTarget.OnMessage(ref m); + } + } + + private class WidgetWindowTarget : IWindowTarget + { + private Widget Widget; + + public WidgetWindowTarget(Widget Widget) + { + this.Widget = Widget; + } + + public void OnHandleChange(IntPtr newHandle) + { + } + + public void OnMessage(ref Message m) + { + Widget.WndProc(ref m); + } + } + #endregion + + #region Public Classes + [ComVisible(true)] + public class WidgetAccessibleObject : AccessibleObject { + IntPtr handle; + + #region WidgetAccessibleObject Constructors + public WidgetAccessibleObject(Widget ownerWidget) + : base (ownerWidget) + { + if (ownerWidget == null) + throw new ArgumentNullException ("owner"); + + handle = ownerWidget.Handle; + } + #endregion // WidgetAccessibleObject Constructors + + #region WidgetAccessibleObject Public Instance Properties + public override string DefaultAction { + get { + return base.DefaultAction; + } + } + + public override string Description { + get { + return base.Description; + } + } + + public IntPtr Handle { + get { + return handle; + } + + set { + // We don't want to let them set it + } + } + + public override string Help { + get { + return base.Help; + } + } + + public override string KeyboardShortcut { + get { + return base.KeyboardShortcut; + } + } + + public override string Name { + get { + return base.Name; + } + + set { + base.Name = value; + } + } + + public Widget Owner { + get { + return base.owner; + } + } + + public override AccessibleObject Parent { + get { + return base.Parent; + } + } + + + public override AccessibleRole Role { + get { + return base.Role; + } + } + #endregion // WidgetAccessibleObject Public Instance Properties + + #region WidgetAccessibleObject Public Instance Methods + public override int GetHelpTopic (out string fileName) + { + return base.GetHelpTopic (out fileName); + } + + [MonoTODO ("Stub, does nothing")] + public void NotifyClients (AccessibleEvents accEvent) + { + } + + [MonoTODO ("Stub, does nothing")] + public void NotifyClients (AccessibleEvents accEvent, int childID) + { + } + + [MonoTODO ("Stub, does nothing")] + public void NotifyClients (AccessibleEvents accEvent, int objectID, int childID) + { + } + + public override string ToString() { + return "WidgetAccessibleObject: Owner = " + owner.ToString() + ", Text: " + owner.text; + } + + #endregion // WidgetAccessibleObject Public Instance Methods + } + + private class DoubleBuffer : IDisposable + { + public Region InvalidRegion; + private Stack real_graphics; + private object back_buffer; + private Widget parent; + private bool pending_disposal; + + public DoubleBuffer (Widget parent) { + this.parent = parent; + real_graphics = new Stack (); + int width = parent.Width; + int height = parent.Height; + + if (width < 1) width = 1; + if (height < 1) height = 1; + + XplatUI.CreateOffscreenDrawable (parent.Handle, width, height, out back_buffer); + Invalidate (); + } + + public void Blit (PaintEventArgs pe) { + Graphics buffered_graphics; + buffered_graphics = XplatUI.GetOffscreenGraphics (back_buffer); + XplatUI.BlitFromOffscreen (parent.Handle, pe.Graphics, back_buffer, buffered_graphics, pe.ClipRectangle); + buffered_graphics.Dispose (); + } + + public void Start (PaintEventArgs pe) { + // We need to get the graphics for every paint. + real_graphics.Push(pe.SetGraphics (XplatUI.GetOffscreenGraphics (back_buffer))); + } + + public void End (PaintEventArgs pe) { + Graphics buffered_graphics; + buffered_graphics = pe.SetGraphics ((Graphics) real_graphics.Pop ()); + + if (pending_disposal) + Dispose (); + else { + XplatUI.BlitFromOffscreen (parent.Handle, pe.Graphics, back_buffer, buffered_graphics, pe.ClipRectangle); + InvalidRegion.Exclude (pe.ClipRectangle); + } + buffered_graphics.Dispose (); + } + + public void Invalidate () + { + if (InvalidRegion != null) + InvalidRegion.Dispose (); + InvalidRegion = new Region (parent.ClientRectangle); + } + + public void Dispose () { + if (real_graphics.Count > 0) { + pending_disposal = true; + return; + } + + XplatUI.DestroyOffscreenDrawable (back_buffer); + + if (InvalidRegion != null) + InvalidRegion.Dispose (); + InvalidRegion = null; + back_buffer = null; + GC.SuppressFinalize (this); + } + + #region IDisposable Members + void IDisposable.Dispose () { + Dispose (); + } + #endregion + + ~DoubleBuffer () { + Dispose (); + } + } + + [ListBindable (false)] + [ComVisible (false)] + public class WidgetCollection : Layout.ArrangedElementCollection, IList, ICollection, ICloneable, IEnumerable { + #region WidgetCollection Local Variables + ArrayList impl_list; + Widget [] all_Widgets; + Widget owner; + #endregion // WidgetCollection Local Variables + + #region WidgetCollection Public Constructor + public WidgetCollection (Widget owner) + { + this.owner = owner; + } + #endregion + + #region WidgetCollection Public Instance Properties + + + public Widget Owner { + get { return this.owner; } + } + + public virtual Widget this[string key] { + get { + int index = IndexOfKey (key); + + if (index >= 0) + return this[index]; + + return null; + } + } + + new public virtual Widget this[int index] { + get { + if (index < 0 || index >= list.Count) { + throw new ArgumentOutOfRangeException("index", index, "WidgetCollection does not have that many Widgets"); + } + return (Widget)list[index]; + } + + + } + + #endregion // WidgetCollection Public Instance Properties + + #region WidgetCollection Instance Methods + + public virtual void Add (Widget value) + { + if (value == null) + return; + + Form form_value = value as Form; + Form form_owner = owner as Form; + bool owner_permits_toplevels = (owner is MdiClient) || (form_owner != null && form_owner.IsMdiContainer); + bool child_is_toplevel = value.GetTopLevel(); + bool child_is_mdichild = form_value != null && form_value.IsMdiChild; + + if (child_is_toplevel && !(owner_permits_toplevels && child_is_mdichild)) + throw new ArgumentException("Cannot add a top level Widget to a Widget.", "value"); + + if (child_is_mdichild && form_value.MdiParent != null && form_value.MdiParent != owner && form_value.MdiParent != owner.Parent) { + throw new ArgumentException ("Form cannot be added to the Widgets collection that has a valid MDI parent.", "value"); + } + + value.recalculate_distances = true; + + if (Contains (value)) { + owner.PerformLayout(); + return; + } + + if (value.tab_index == -1) { + int end; + int index; + int use; + + use = 0; + end = owner.child_Widgets.Count; + for (int i = 0; i < end; i++) { + index = owner.child_Widgets[i].tab_index; + if (index >= use) { + use = index + 1; + } + } + value.tab_index = use; + } + + if (value.parent != null) { + value.parent.Widgets.Remove(value); + } + + all_Widgets = null; + list.Add (value); + + value.ChangeParent(owner); + + value.InitLayout(); + + if (owner.Visible) + owner.UpdateChildrenZOrder(); + owner.PerformLayout(value, "Parent"); + owner.OnWidgetAdded(new WidgetEventArgs(value)); + } + + internal void AddToList (Widget c) + { + all_Widgets = null; + list.Add (c); + } + + internal virtual void AddImplicit (Widget Widget) + { + if (impl_list == null) + impl_list = new ArrayList (); + + if (AllContains (Widget)) { + owner.PerformLayout (); + return; + } + + if (Widget.parent != null) { + Widget.parent.Widgets.Remove(Widget); + } + + all_Widgets = null; + impl_list.Add (Widget); + + Widget.ChangeParent (owner); + Widget.InitLayout (); + if (owner.Visible) + owner.UpdateChildrenZOrder (); + + // If we are adding a new Widget that isn't + // visible, don't trigger a layout + if (Widget.VisibleInternal) + owner.PerformLayout (Widget, "Parent"); + } + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public virtual void AddRange (Widget[] Widgets) + { + if (Widgets == null) + throw new ArgumentNullException ("Widgets"); + + owner.SuspendLayout (); + + try { + for (int i = 0; i < Widgets.Length; i++) + Add (Widgets[i]); + } finally { + owner.ResumeLayout (); + } + } + + internal virtual void AddRangeImplicit (Widget [] Widgets) + { + if (Widgets == null) + throw new ArgumentNullException ("Widgets"); + + owner.SuspendLayout (); + + try { + for (int i = 0; i < Widgets.Length; i++) + AddImplicit (Widgets [i]); + } finally { + owner.ResumeLayout (false); + } + } + + new + public virtual void Clear () + { + all_Widgets = null; + + // MS sends remove events in reverse order + while (list.Count > 0) { + Remove((Widget)list[list.Count - 1]); + } + } + + internal virtual void ClearImplicit () + { + if (impl_list == null) + return; + all_Widgets = null; + impl_list.Clear (); + } + + public bool Contains (Widget Widget) + { + return list.Contains (Widget); + } + + internal bool ImplicitContains (Widget value) { + if (impl_list == null) + return false; + + return impl_list.Contains (value); + } + + internal bool AllContains (Widget value) { + return Contains (value) || ImplicitContains (value); + } + + + public virtual bool ContainsKey (string key) + { + return IndexOfKey (key) >= 0; + } + + + // LAMESPEC: MSDN says AE, MS implementation throws ANE + public Widget[] Find (string key, bool searchAllChildren) + { + if (string.IsNullOrEmpty (key)) + throw new ArgumentNullException ("key"); + + ArrayList al = new ArrayList (); + + foreach (Widget c in list) { + if (c.Name.Equals (key, StringComparison.CurrentCultureIgnoreCase)) + al.Add (c); + + if (searchAllChildren) + al.AddRange (c.Widgets.Find (key, true)); + } + + return (Widget[])al.ToArray (typeof (Widget)); + } + + public int GetChildIndex(Widget child) { + return GetChildIndex(child, false); + } + + public virtual int GetChildIndex(Widget child, bool throwException) { + int index; + + index=list.IndexOf(child); + + if (index==-1 && throwException) { + throw new ArgumentException("Not a child Widget", "child"); + } + return index; + } + + public override IEnumerator + GetEnumerator () { + return new WidgetCollectionEnumerator (list); + } + + internal IEnumerator GetAllEnumerator () { + Widget [] res = GetAllWidgets (); + return res.GetEnumerator (); + } + + internal ArrayList ImplicitWidgets { + get { return impl_list; } + } + + internal Widget [] GetAllWidgets () { + if (all_Widgets != null) + return all_Widgets; + + if (impl_list == null) { + all_Widgets = (Widget []) list.ToArray (typeof (Widget)); + return all_Widgets; + } + + all_Widgets = new Widget [list.Count + impl_list.Count]; + impl_list.CopyTo (all_Widgets); + list.CopyTo (all_Widgets, impl_list.Count); + + return all_Widgets; + } + + public int IndexOf (Widget Widget) + { + return list.IndexOf (Widget); + } + + public virtual int IndexOfKey (string key) + { + if (string.IsNullOrEmpty (key)) + return -1; + + for (int i = 0; i < list.Count; i++) + if (((Widget)list[i]).Name.Equals (key, StringComparison.CurrentCultureIgnoreCase)) + return i; + + return -1; + } + + public virtual void Remove (Widget value) + { + if (value == null || !list.Contains(value)) + return; + + all_Widgets = null; + list.Remove(value); + + owner.PerformLayout(value, "Parent"); + owner.OnWidgetRemoved(new WidgetEventArgs(value)); + + ContainerWidget container = owner.InternalGetContainerWidget (); + if (container != null) { + // Inform any container Widgets about the loss of a child Widget + // so that they can update their active Widget + container.ChildWidgetRemoved (value); + } + + value.ChangeParent(null); + + owner.UpdateChildrenZOrder(); + } + + internal virtual void RemoveImplicit (Widget Widget) + { + if (impl_list != null) { + all_Widgets = null; + impl_list.Remove (Widget); + owner.PerformLayout (Widget, "Parent"); + owner.OnWidgetRemoved (new WidgetEventArgs (Widget)); + } + Widget.ChangeParent (null); + owner.UpdateChildrenZOrder (); + } + + public void RemoveAt (int index) + { + if (index < 0 || index >= list.Count) + throw new ArgumentOutOfRangeException("index", index, "WidgetCollection does not have that many Widgets"); + + Remove ((Widget) list [index]); + } + + public virtual void RemoveByKey (string key) + { + int index = IndexOfKey (key); + + if (index >= 0) + RemoveAt (index); + } + + public virtual void SetChildIndex(Widget child, int newIndex) + { + if (child == null) + throw new ArgumentNullException ("child"); + + int old_index; + + old_index=list.IndexOf(child); + if (old_index==-1) { + throw new ArgumentException("Not a child Widget", "child"); + } + + if (old_index==newIndex) { + return; + } + + all_Widgets = null; + list.RemoveAt(old_index); + + if (newIndex>list.Count) { + list.Add(child); + } else { + list.Insert(newIndex, child); + } + child.UpdateZOrder(); + owner.PerformLayout(); + } + + #endregion // WidgetCollection Private Instance Methods + + #region WidgetCollection Interface Properties + + #endregion // WidgetCollection Interface Properties + + #region WidgetCollection Interface Methods + + int IList.Add (object Widget) + { + if (!(Widget is Widget)) + throw new ArgumentException ("Object of type Widget required", "Widget"); + + if (Widget == null) + throw new ArgumentException ("Widget", "Cannot add null Widgets"); + + this.Add ((Widget)Widget); + return this.IndexOf ((Widget)Widget); + } + + void IList.Remove (object Widget) + { + if (!(Widget is Widget)) + throw new ArgumentException ("Object of type Widget required", "Widget"); + + this.Remove ((Widget)Widget); + } + + Object ICloneable.Clone () + { + WidgetCollection clone = new WidgetCollection (this.owner); + clone.list = (ArrayList)list.Clone (); // FIXME: Do we need this? + return clone; + } + + #endregion // WidgetCollection Interface Methods + + internal class WidgetCollectionEnumerator : IEnumerator + { + private ArrayList list; + int position = -1; + + public WidgetCollectionEnumerator (ArrayList collection) + { + list = collection; + } + + #region IEnumerator Members + public object Current { + get { + try { + return list[position]; + } catch (IndexOutOfRangeException) { + throw new InvalidOperationException (); + } + } + } + + public bool MoveNext () + { + position++; + return (position < list.Count); + } + + public void Reset () + { + position = -1; + } + + #endregion + } + } + #endregion // WidgetCollection Class + + #region Public Constructors + public Widget () + { + try { + if (WindowsFormsSynchronizationContext.AutoInstall) + if (!(SynchronizationContext.Current is WindowsFormsSynchronizationContext)) + SynchronizationContext.SetSynchronizationContext (new WindowsFormsSynchronizationContext ()); + } + catch(Exception ex) { + Console.WriteLine ("[ShiftUI] Error: {0}", ex.Message); + } + layout_type = LayoutType.Anchor; + anchor_style = AnchorStyles.Top | AnchorStyles.Left; + + is_created = false; + is_visible = true; + is_captured = false; + is_disposed = false; + is_enabled = true; + is_entered = false; + layout_pending = false; + is_toplevel = false; + causes_validation = true; + has_focus = false; + layout_suspended = 0; + mouse_clicks = 1; + tab_index = -1; + cursor = null; + right_to_left = RightToLeft.Inherit; + border_style = BorderStyle.None; + background_color = Color.Empty; + dist_right = 0; + dist_bottom = 0; + tab_stop = true; + ime_mode = ImeMode.Inherit; + use_compatible_text_rendering = true; + show_keyboard_cues = false; + show_focus_cues = SystemInformation.MenuAccessKeysUnderlined; + use_wait_cursor = false; + + backgroundimage_layout = ImageLayout.Tile; + use_compatible_text_rendering = Application.use_compatible_text_rendering; + padding = this.DefaultPadding; + maximum_size = new Size(); + minimum_size = new Size(); + margin = this.DefaultMargin; + auto_size_mode = AutoSizeMode.GrowOnly; + + Widget_style = Widgetstyles.UserPaint | Widgetstyles.AllPaintingInWmPaint | + Widgetstyles.Selectable | Widgetstyles.StandardClick | + Widgetstyles.StandardDoubleClick; + Widget_style |= Widgetstyles.UseTextForAccessibility; + + parent = null; + background_image = null; + text = string.Empty; + name = string.Empty; + + window_target = new WidgetWindowTarget(this); + window = new WidgetNativeWindow(this); + child_Widgets = CreateWidgetsInstance(); + + bounds.Size = DefaultSize; + client_size = ClientSizeFromSize (bounds.Size); + client_rect = new Rectangle (Point.Empty, client_size); + explicit_bounds = bounds; + } + + public Widget (Widget parent, string text) : this() + { + Text=text; + Parent=parent; + } + + public Widget (Widget parent, string text, int left, int top, int width, int height) : this() + { + Parent=parent; + SetBounds(left, top, width, height, BoundsSpecified.All); + Text=text; + } + + public Widget (string text) : this() + { + Text=text; + } + + public Widget (string text, int left, int top, int width, int height) : this() + { + SetBounds(left, top, width, height, BoundsSpecified.All); + Text=text; + } + + private delegate void RemoveDelegate(object c); + + protected override void Dispose (bool disposing) + { + if (!is_disposed && disposing) { + is_disposing = true; + Capture = false; + + DisposeBackBuffer (); + + if (this.InvokeRequired) { + if (Application.MessageLoop && IsHandleCreated) { + this.BeginInvokeInternal(new MethodInvoker(DestroyHandle), null); + } + } else { + DestroyHandle(); + } + + if (parent != null) + parent.Widgets.Remove(this); + + Widget [] children = child_Widgets.GetAllWidgets (); + for (int i=0; i0) { + SetChildColor(child); + } + } + } + + internal bool Select(Widget Widget) { + IContainerWidget container; + + if (Widget == null) { + return false; + } + + container = GetContainerWidget(); + if (container != null && (Widget)container != Widget) { + container.ActiveWidget = Widget; + if (container.ActiveWidget == Widget && !Widget.has_focus && Widget.IsHandleCreated) + XplatUI.SetFocus(Widget.window.Handle); + } + else if (Widget.IsHandleCreated) { + XplatUI.SetFocus(Widget.window.Handle); + } + return true; + } + + internal virtual void DoDefaultAction() { + // Only here to be overriden by our actual Widgets; this is needed by the accessibility class + } + + internal static IntPtr MakeParam (int low, int high){ + return new IntPtr (high << 16 | low & 0xffff); + } + + internal static int LowOrder (int param) { + return ((int)(short)(param & 0xffff)); + } + + internal static int HighOrder (long param) { + return ((int)(short)(param >> 16)); + } + + // This method exists so Widgets overriding OnPaintBackground can have default background painting done + internal virtual void PaintWidgetBackground (PaintEventArgs pevent) { + + bool tbstyle_flat = ((CreateParams.Style & (int) ToolBarStyles.TBSTYLE_FLAT) != 0); + + // If we have transparent background + if (((BackColor.A != 0xff) && GetStyle(Widgetstyles.SupportsTransparentBackColor)) || tbstyle_flat) { + if (parent != null) { + PaintEventArgs parent_pe; + GraphicsState state; + + parent_pe = new PaintEventArgs(pevent.Graphics, new Rectangle(pevent.ClipRectangle.X + Left, pevent.ClipRectangle.Y + Top, pevent.ClipRectangle.Width, pevent.ClipRectangle.Height)); + + state = parent_pe.Graphics.Save(); + parent_pe.Graphics.TranslateTransform(-Left, -Top); + parent.OnPaintBackground(parent_pe); + parent_pe.Graphics.Restore(state); + + state = parent_pe.Graphics.Save(); + parent_pe.Graphics.TranslateTransform(-Left, -Top); + parent.OnPaint(parent_pe); + parent_pe.Graphics.Restore(state); + parent_pe.SetGraphics(null); + } + } + + if ((clip_region != null) && (XplatUI.UserClipWontExposeParent)) { + if (parent != null) { + PaintEventArgs parent_pe; + Region region; + GraphicsState state; + Hwnd hwnd; + + hwnd = Hwnd.ObjectFromHandle(Handle); + + if (hwnd != null) { + parent_pe = new PaintEventArgs(pevent.Graphics, new Rectangle(pevent.ClipRectangle.X + Left, pevent.ClipRectangle.Y + Top, pevent.ClipRectangle.Width, pevent.ClipRectangle.Height)); + + region = new Region (); + region.MakeEmpty(); + region.Union(ClientRectangle); + + foreach (Rectangle r in hwnd.ClipRectangles) { + region.Union (r); + } + + state = parent_pe.Graphics.Save(); + parent_pe.Graphics.Clip = region; + + parent_pe.Graphics.TranslateTransform(-Left, -Top); + parent.OnPaintBackground(parent_pe); + parent_pe.Graphics.Restore(state); + + state = parent_pe.Graphics.Save(); + parent_pe.Graphics.Clip = region; + + parent_pe.Graphics.TranslateTransform(-Left, -Top); + parent.OnPaint(parent_pe); + parent_pe.Graphics.Restore(state); + parent_pe.SetGraphics(null); + + region.Intersect(clip_region); + pevent.Graphics.Clip = region; + } + } + } + + if (background_image == null) { + if (!tbstyle_flat) { + Rectangle paintRect = pevent.ClipRectangle; + Brush pen = ThemeEngine.Current.ResPool.GetSolidBrush(BackColor); + pevent.Graphics.FillRectangle(pen, paintRect); + } + return; + } + + DrawBackgroundImage (pevent.Graphics); + } + + void DrawBackgroundImage (Graphics g) { + Rectangle drawing_rectangle = new Rectangle (); + g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), ClientRectangle); + + switch (backgroundimage_layout) + { + case ImageLayout.Tile: + using (TextureBrush b = new TextureBrush (background_image, WrapMode.Tile)) { + g.FillRectangle (b, ClientRectangle); + } + return; + case ImageLayout.Center: + drawing_rectangle.Location = new Point (ClientSize.Width / 2 - background_image.Width / 2, ClientSize.Height / 2 - background_image.Height / 2); + drawing_rectangle.Size = background_image.Size; + break; + case ImageLayout.None: + drawing_rectangle.Location = Point.Empty; + drawing_rectangle.Size = background_image.Size; + break; + case ImageLayout.Stretch: + drawing_rectangle = ClientRectangle; + break; + case ImageLayout.Zoom: + drawing_rectangle = ClientRectangle; + if ((float)background_image.Width / (float)background_image.Height < (float)drawing_rectangle.Width / (float) drawing_rectangle.Height) { + drawing_rectangle.Width = (int) (background_image.Width * ((float)drawing_rectangle.Height / (float)background_image.Height)); + drawing_rectangle.X = (ClientRectangle.Width - drawing_rectangle.Width) / 2; + } else { + drawing_rectangle.Height = (int) (background_image.Height * ((float)drawing_rectangle.Width / (float)background_image.Width)); + drawing_rectangle.Y = (ClientRectangle.Height - drawing_rectangle.Height) / 2; + } + break; + default: + return; + } + + g.DrawImage (background_image, drawing_rectangle); + + } + + internal virtual void DndEnter (DragEventArgs e) { + try { + OnDragEnter (e); + } catch { } + } + + internal virtual void DndOver (DragEventArgs e) { + try { + OnDragOver (e); + } catch { } + } + + internal virtual void DndDrop (DragEventArgs e) { + try { + OnDragDrop (e); + } catch (Exception exc) { + Console.Error.WriteLine ("MWF: Exception while dropping:"); + Console.Error.WriteLine (exc); + } + } + + internal virtual void DndLeave (EventArgs e) { + try { + OnDragLeave (e); + } catch { } + } + + internal virtual void DndFeedback(GiveFeedbackEventArgs e) { + try { + OnGiveFeedback(e); + } catch { } + } + + internal virtual void DndContinueDrag(QueryContinueDragEventArgs e) { + try { + OnQueryContinueDrag(e); + } catch { } + } + + internal static MouseButtons FromParamToMouseButtons (long param) { + MouseButtons buttons = MouseButtons.None; + + if ((param & (long) MsgButtons.MK_LBUTTON) != 0) + buttons |= MouseButtons.Left; + + if ((param & (long)MsgButtons.MK_MBUTTON) != 0) + buttons |= MouseButtons.Middle; + + if ((param & (long)MsgButtons.MK_RBUTTON) != 0) + buttons |= MouseButtons.Right; + + return buttons; + } + + internal virtual void FireEnter () { + OnEnter (EventArgs.Empty); + } + + internal virtual void FireLeave () { + OnLeave (EventArgs.Empty); + } + + internal virtual void FireValidating (CancelEventArgs ce) { + OnValidating (ce); + } + + internal virtual void FireValidated () { + OnValidated (EventArgs.Empty); + } + + internal virtual bool ProcessWidgetMnemonic(char charCode) { + return ProcessMnemonic(charCode); + } + + private static Widget FindFlatForward(Widget container, Widget start) { + Widget found; + int index; + int end; + bool hit; + + found = null; + end = container.child_Widgets.Count; + hit = false; + + if (start != null) { + index = start.tab_index; + } else { + index = -1; + } + + for (int i = 0; i < end; i++) { + if (start == container.child_Widgets[i]) { + hit = true; + continue; + } + + if (found == null || found.tab_index > container.child_Widgets[i].tab_index) { + if (container.child_Widgets[i].tab_index > index || (hit && container.child_Widgets[i].tab_index == index)) { + found = container.child_Widgets[i]; + } + } + } + return found; + } + + private static Widget FindWidgetForward(Widget container, Widget start) { + Widget found; + + found = null; + + if (start == null) { + return FindFlatForward(container, start); + } + + if (start.child_Widgets != null && start.child_Widgets.Count > 0 && + (start == container || !((start is IContainerWidget) && start.GetStyle(Widgetstyles.ContainerWidget)))) { + return FindWidgetForward(start, null); + } + else { + while (start != container) { + found = FindFlatForward(start.parent, start); + if (found != null) { + return found; + } + start = start.parent; + } + } + return null; + } + + private static Widget FindFlatBackward(Widget container, Widget start) { + Widget found; + int index; + int end; + bool hit; + + found = null; + end = container.child_Widgets.Count; + hit = false; + + if (start != null) { + index = start.tab_index; + } else { + index = int.MaxValue; + } + + for (int i = end - 1; i >= 0; i--) { + if (start == container.child_Widgets[i]) { + hit = true; + continue; + } + + if (found == null || found.tab_index < container.child_Widgets[i].tab_index) { + if (container.child_Widgets[i].tab_index < index || (hit && container.child_Widgets[i].tab_index == index)) + found = container.child_Widgets[i]; + + } + } + return found; + } + + private static Widget FindWidgetBackward(Widget container, Widget start) { + + Widget found = null; + + if (start == null) { + found = FindFlatBackward(container, start); + } + else if (start != container) { + if (start.parent != null) { + found = FindFlatBackward(start.parent, start); + + if (found == null) { + if (start.parent != container) + return start.parent; + return null; + } + } + } + + if (found == null || start.parent == null) + found = start; + + while (found != null && (found == container || (!((found is IContainerWidget) && found.GetStyle(Widgetstyles.ContainerWidget))) && + found.child_Widgets != null && found.child_Widgets.Count > 0)) { + // while (ctl.child_Widgets != null && ctl.child_Widgets.Count > 0 && + // (ctl == this || (!((ctl is IContainerWidget) && ctl.GetStyle(Widgetstyles.ContainerWidget))))) { + found = FindFlatBackward(found, null); + } + + return found; + + /* + Widget found; + + found = null; + + if (start != null) { + found = FindFlatBackward(start.parent, start); + if (found == null) { + if (start.parent != container) { + return start.parent; + } + } + } + if (found == null) { + found = FindFlatBackward(container, start); + } + + if (container != start) { + while ((found != null) && (!found.Contains(start)) && found.child_Widgets != null && found.child_Widgets.Count > 0 && !(found is IContainerWidget)) {// || found.GetStyle(Widgetstyles.ContainerWidget))) { + found = FindWidgetBackward(found, null); + if (found != null) { + return found; + } + } + } + return found; +*/ + } + + internal virtual void HandleClick(int clicks, MouseEventArgs me) { + bool standardclick = GetStyle (Widgetstyles.StandardClick); + bool standardclickclick = GetStyle (Widgetstyles.StandardDoubleClick); + if ((clicks > 1) && standardclick && standardclickclick) { + OnDoubleClick (me); + OnMouseDoubleClick (me); + } else if (clicks == 1 && standardclick && !ValidationFailed) { + OnClick (me); + OnMouseClick (me); + } + } + + internal void CaptureWithConfine (Widget ConfineWindow) { + if (this.IsHandleCreated && !is_captured) { + is_captured = true; + XplatUI.GrabWindow (this.window.Handle, ConfineWindow.Handle); + } + } + + private void CheckDataBindings () { + if (data_bindings == null) + return; + + foreach (Binding binding in data_bindings) { + binding.Check (); + } + } + + private void ChangeParent(Widget new_parent) { + bool pre_enabled; + bool pre_visible; + Font pre_font; + Color pre_fore_color; + Color pre_back_color; + RightToLeft pre_rtl; + + // These properties are inherited from our parent + // Get them pre parent-change and then send events + // if they are changed after we have our new parent + pre_enabled = Enabled; + pre_visible = Visible; + pre_font = Font; + pre_fore_color = ForeColor; + pre_back_color = BackColor; + pre_rtl = RightToLeft; + // MS doesn't seem to send a CursorChangedEvent + + parent = new_parent; + + Form frm = this as Form; + if (frm != null) { + frm.ChangingParent (new_parent); + } else if (IsHandleCreated) { + IntPtr parent_handle = IntPtr.Zero; + if (new_parent != null && new_parent.IsHandleCreated) + parent_handle = new_parent.Handle; + XplatUI.SetParent (Handle, parent_handle); + } + + OnParentChanged(EventArgs.Empty); + + if (pre_enabled != Enabled) { + OnEnabledChanged(EventArgs.Empty); + } + + if (pre_visible != Visible) { + OnVisibleChanged(EventArgs.Empty); + } + + if (pre_font != Font) { + OnFontChanged(EventArgs.Empty); + } + + if (pre_fore_color != ForeColor) { + OnForeColorChanged(EventArgs.Empty); + } + + if (pre_back_color != BackColor) { + OnBackColorChanged(EventArgs.Empty); + } + + if (pre_rtl != RightToLeft) { + // MS sneaks a OnCreateWidget and OnHandleCreated in here, I guess + // because when RTL changes they have to recreate the win32 Widget + // We don't really need that (until someone runs into compatibility issues) + OnRightToLeftChanged(EventArgs.Empty); + } + + if ((new_parent != null) && new_parent.Created && is_visible && !Created) { + CreateWidget(); + } + + if ((binding_context == null) && Created) { + OnBindingContextChanged(EventArgs.Empty); + } + } + + // Sometimes we need to do this calculation without it being virtual (constructor) + internal Size InternalSizeFromClientSize (Size clientSize) + { + Rectangle ClientRect; + Rectangle WindowRect; + CreateParams cp; + + ClientRect = new Rectangle (0, 0, clientSize.Width, clientSize.Height); + cp = this.CreateParams; + + if (XplatUI.CalculateWindowRect (ref ClientRect, cp, null, out WindowRect)) + return new Size (WindowRect.Width, WindowRect.Height); + + return Size.Empty; + } + + internal Size ClientSizeFromSize (Size size) + { + // Calling this gives us the difference in Size and ClientSize. + // We just have to apply that difference to our given size. + Size client_size = this.InternalSizeFromClientSize (size); + + if (client_size == Size.Empty) + return Size.Empty; + + return new Size (size.Width - (client_size.Width - size.Width), size.Height - (client_size.Height - size.Height)); + } + + internal CreateParams GetCreateParams () + { + return CreateParams; + } + + internal virtual Size GetPreferredSizeCore (Size proposedSize) + { + return this.explicit_bounds.Size; + } + + private void UpdateDistances() { + if (parent != null) { + if (bounds.Width >= 0) + dist_right = parent.ClientSize.Width - bounds.X - bounds.Width; + if (bounds.Height >= 0) + dist_bottom = parent.ClientSize.Height - bounds.Y - bounds.Height; + + recalculate_distances = false; + } + } + + private Cursor GetAvailableCursor () + { + if (Cursor != null && Enabled) { + return Cursor; + } + + if (Parent != null) { + return Parent.GetAvailableCursor (); + } + + return Cursors.Default; + } + + private void UpdateCursor () + { + if (!IsHandleCreated) + return; + + if (!Enabled) { + XplatUI.SetCursor (window.Handle, GetAvailableCursor ().handle); + return; + } + + Point pt = PointToClient (Cursor.Position); + + if (!bounds.Contains (pt) && !Capture) + return; + + if (cursor != null || use_wait_cursor) { + XplatUI.SetCursor (window.Handle, Cursor.handle); + } else { + XplatUI.SetCursor (window.Handle, GetAvailableCursor ().handle); + } + } + + private bool UseDoubleBuffering { + get { + if (!ThemeEngine.Current.DoubleBufferingSupported) + return false; + + // Since many of .Net's Widgets are unmanaged, they are doublebuffered + // even though their bits may not be set in managed land. This allows + // us to doublebuffer as well without affecting public style bits. + if (force_double_buffer) + return true; + + if (DoubleBuffered) + return true; + return (Widget_style & Widgetstyles.DoubleBuffer) != 0; + } + } + + internal void OnSizeInitializedOrChanged () + { + Form form = this as Form; + if (form != null && form.WindowManager != null) + ThemeEngine.Current.ManagedWindowOnSizeInitializedOrChanged (form); + } + #endregion // Private & Internal Methods + + #region Public Static Properties + public static Color DefaultBackColor { + get { + return ThemeEngine.Current.DefaultControlBackColor; + } + } + + public static Font DefaultFont { + get { + return ThemeEngine.Current.DefaultFont; + } + } + + public static Color DefaultForeColor { + get { + return ThemeEngine.Current.DefaultControlForeColor; + } + } + + public static Keys ModifierKeys { + get { + return XplatUI.State.ModifierKeys; + } + } + + public static MouseButtons MouseButtons { + get { + return XplatUI.State.MouseButtons; + } + } + + public static Point MousePosition { + get { + return Cursor.Position; + } + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + [Browsable (false)] + [MonoTODO ("Stub, value is not used")] + public static bool CheckForIllegalCrossThreadCalls + { + get { + return verify_thread_handle; + } + + set { + verify_thread_handle = value; + } + } + #endregion // Public Static Properties + + #region Public Instance Properties + [EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public AccessibleObject AccessibilityObject { + get { + if (accessibility_object==null) { + accessibility_object=CreateAccessibilityInstance(); + } + return accessibility_object; + } + } + + [EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string AccessibleDefaultActionDescription { + get { + return accessible_default_action; + } + + set { + accessible_default_action = value; + } + } + + [Localizable(true)] + [DefaultValue(null)] + [MWFCategory("Accessibility")] + public string AccessibleDescription { + get { + return accessible_description; + } + + set { + accessible_description = value; + } + } + + [Localizable(true)] + [DefaultValue(null)] + [MWFCategory("Accessibility")] + public string AccessibleName { + get { + return accessible_name; + } + + set { + accessible_name = value; + } + } + + [DefaultValue(AccessibleRole.Default)] + [MWFDescription("Role of the Widget"), MWFCategory("Accessibility")] + public AccessibleRole AccessibleRole { + get { + return accessible_role; + } + + set { + accessible_role = value; + } + } + + [DefaultValue(false)] + [MWFCategory("Behavior")] + public virtual bool AllowDrop { + get { + return allow_drop; + } + + set { + if (allow_drop == value) + return; + allow_drop = value; + if (IsHandleCreated) { + UpdateStyles(); + XplatUI.SetAllowDrop (Handle, value); + } + } + } + + [Localizable(true)] + [RefreshProperties(RefreshProperties.Repaint)] + [DefaultValue(AnchorStyles.Top | AnchorStyles.Left)] + [MWFCategory("Layout")] + [MWFDescription("The sides of the parent widget that this one will bind to.")] + public virtual AnchorStyles Anchor { + get { + return anchor_style; + } + + set { + layout_type = LayoutType.Anchor; + + if (anchor_style == value) + return; + + anchor_style=value; + dock_style = DockStyle.None; + + UpdateDistances (); + + if (parent != null) + parent.PerformLayout(this, "Anchor"); + } + } + + [Browsable (false)] + [DefaultValue (typeof (Point), "0, 0")] + [EditorBrowsable (EditorBrowsableState.Advanced)] + public virtual Point AutoScrollOffset { + get { + return auto_scroll_offset; + } + + set { + this.auto_scroll_offset = value; + } + } + + // XXX: Implement me! + bool auto_size; + + [RefreshProperties (RefreshProperties.All)] + [Localizable (true)] + [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + [Browsable (false)] + [EditorBrowsable (EditorBrowsableState.Never)] + [DefaultValue (false)] + public virtual bool AutoSize { + get { return auto_size; } + set { + if (this.auto_size != value) { + auto_size = value; + + // If we're turning this off, reset our size + if (!value) { + Size = explicit_bounds.Size; + } else { + if (Parent != null) + Parent.PerformLayout (this, "AutoSize"); + } + + OnAutoSizeChanged (EventArgs.Empty); + } + } + } + + [AmbientValue ("{Width=0, Height=0}")] + [MWFCategory("Layout")] + public virtual Size MaximumSize { + get { + return maximum_size; + } + set { + if (maximum_size != value) { + maximum_size = value; + Size = PreferredSize; + } + } + } + + internal bool ShouldSerializeMaximumSize () + { + return this.MaximumSize != DefaultMaximumSize; + } + + [MWFCategory("Layout")] + public virtual Size MinimumSize { + get { + return minimum_size; + } + set { + if (minimum_size != value) { + minimum_size = value; + Size = PreferredSize; + } + } + } + + internal bool ShouldSerializeMinimumSize () + { + return this.MinimumSize != DefaultMinimumSize; + } + + [DispId(-501)] + [MWFCategory("Appearance")] + public virtual Color BackColor { + get { + if (background_color.IsEmpty) { + if (parent!=null) { + Color pcolor = parent.BackColor; + if (pcolor.A == 0xff || GetStyle(Widgetstyles.SupportsTransparentBackColor)) + return pcolor; + } + return DefaultBackColor; + } + return background_color; + } + + set { + if (!value.IsEmpty && (value.A != 0xff) && !GetStyle(Widgetstyles.SupportsTransparentBackColor)) { + throw new ArgumentException("Transparent background colors are not supported on this Widget"); + } + + if (background_color != value) { + background_color=value; + SetChildColor(this); + OnBackColorChanged(EventArgs.Empty); + Invalidate(); + } + } + } + + internal bool ShouldSerializeBackColor () + { + return this.BackColor != DefaultBackColor; + } + + [Localizable(true)] + [DefaultValue(null)] + [MWFCategory("Appearance")] + public virtual Image BackgroundImage { + get { + return background_image; + } + + set { + if (background_image!=value) { + background_image=value; + OnBackgroundImageChanged(EventArgs.Empty); + Invalidate (); + } + } + } + + [DefaultValue (ImageLayout.Tile)] + [Localizable (true)] + [MWFCategory("Appearance")] + public virtual ImageLayout BackgroundImageLayout { + get { + return backgroundimage_layout; + } + set { + if (Array.IndexOf (Enum.GetValues (typeof (ImageLayout)), value) == -1) + throw new InvalidEnumArgumentException ("value", (int) value, typeof(ImageLayout)); + + if (value != backgroundimage_layout) { + backgroundimage_layout = value; + Invalidate (); + OnBackgroundImageLayoutChanged (EventArgs.Empty); + } + + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public virtual BindingContext BindingContext { + get { + if (binding_context != null) + return binding_context; + if (Parent == null) + return null; + binding_context = Parent.BindingContext; + return binding_context; + } + set { + if (binding_context != value) { + binding_context = value; + OnBindingContextChanged(EventArgs.Empty); + } + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int Bottom { + get { + return this.bounds.Bottom; + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Rectangle Bounds { + get { + return this.bounds; + } + + set { + SetBounds(value.Left, value.Top, value.Width, value.Height, BoundsSpecified.All); + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool CanFocus { + get { + if (IsHandleCreated && Visible && Enabled) { + return true; + } + return false; + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool CanSelect { + get { + Widget parent; + + if (!GetStyle(Widgetstyles.Selectable)) { + return false; + } + + parent = this; + while (parent != null) { + if (!parent.is_visible || !parent.is_enabled) { + return false; + } + + parent = parent.parent; + } + return true; + } + } + + internal virtual bool InternalCapture { + get { + return Capture; + } + + set { + Capture = value; + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool Capture { + get { + return this.is_captured; + } + + set { + // Call OnMouseCaptureChanged when we get WM_CAPTURECHANGED. + if (value != is_captured) { + if (value) { + is_captured = true; + XplatUI.GrabWindow(Handle, IntPtr.Zero); + } else { + if (IsHandleCreated) + XplatUI.UngrabWindow(Handle); + is_captured = false; + } + } + } + } + + [DefaultValue(true)] + [MWFCategory("Focus")] + public bool CausesValidation { + get { + return this.causes_validation; + } + + set { + if (this.causes_validation != value) { + causes_validation = value; + OnCausesValidationChanged(EventArgs.Empty); + } + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Rectangle ClientRectangle { + get { + client_rect.Width = client_size.Width; + client_rect.Height = client_size.Height; + return client_rect; + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Size ClientSize { + get { + #if notneeded + if ((this is Form) && (((Form)this).form_parent_window != null)) { + return ((Form)this).form_parent_window.ClientSize; + } + #endif + + return client_size; + } + + set { + this.SetClientSizeCore(value.Width, value.Height); + this.OnClientSizeChanged (EventArgs.Empty); + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [DescriptionAttribute("WidgetCompanyNameDescr")] + public String CompanyName { + get { + return "Mono Project, Novell, Inc."; + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool ContainsFocus { + get { + IntPtr focused_window; + + focused_window = XplatUI.GetFocus(); + if (IsHandleCreated) { + if (focused_window == Handle) { + return true; + } + + for (int i=0; i < child_Widgets.Count; i++) { + if (child_Widgets[i].ContainsFocus) { + return true; + } + } + } + return false; + } + } + + [DefaultValue (null)] + [MWFCategory("Behavior")] + public virtual ContextMenuStrip ContextMenuStrip { + get { return this.context_menu_strip; } + set { + if (this.context_menu_strip != value) { + this.context_menu_strip = value; + if (value != null) + value.container = this; + OnContextMenuStripChanged (EventArgs.Empty); + } + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public WidgetCollection Widgets { + get { + return this.child_Widgets; + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool Created { + get { + return (!is_disposed && is_created); + } + } + + [AmbientValue(null)] + [MWFCategory("Appearance")] + public virtual Cursor Cursor { + get { + if (use_wait_cursor) + return Cursors.WaitCursor; + + if (cursor != null) { + return cursor; + } + + if (parent != null) { + return parent.Cursor; + } + + return Cursors.Default; + } + + set { + if (cursor == value) { + return; + } + + cursor = value; + UpdateCursor (); + + OnCursorChanged (EventArgs.Empty); + } + } + + internal bool ShouldSerializeCursor () + { + return this.Cursor != Cursors.Default; + } + + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + [ParenthesizePropertyName(true)] + [RefreshProperties(RefreshProperties.All)] + [MWFCategory("Data")] + public WidgetBindingsCollection DataBindings { + get { + if (data_bindings == null) + data_bindings = new WidgetBindingsCollection (this); + return data_bindings; + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public virtual Rectangle DisplayRectangle { + get { + // for the Widget class the DisplayRectangle == ClientRectangle + return ClientRectangle; + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool Disposing { + get { + return is_disposed; + } + } + + [Localizable(true)] + [RefreshProperties(RefreshProperties.Repaint)] + [DefaultValue(DockStyle.None)] + [MWFCategory("Layout")] + public virtual DockStyle Dock { + get { + return dock_style; + } + + set { + // If the user sets this to None, we need to still use Anchor layout + if (value != DockStyle.None) + layout_type = LayoutType.Dock; + + if (dock_style == value) { + return; + } + + if (!Enum.IsDefined (typeof (DockStyle), value)) { + throw new InvalidEnumArgumentException ("value", (int) value, + typeof (DockStyle)); + } + + dock_style = value; + anchor_style = AnchorStyles.Top | AnchorStyles.Left; + + if (dock_style == DockStyle.None) { + bounds = explicit_bounds; + layout_type = LayoutType.Anchor; + } + + if (parent != null) + parent.PerformLayout(this, "Dock"); + else if (Widgets.Count > 0) + PerformLayout (); + + OnDockChanged(EventArgs.Empty); + } + } + + protected virtual bool DoubleBuffered { + get { + return (Widget_style & Widgetstyles.OptimizedDoubleBuffer) != 0; + } + + set { + if (value == DoubleBuffered) + return; + if (value) { + SetStyle (Widgetstyles.OptimizedDoubleBuffer | Widgetstyles.AllPaintingInWmPaint, true); + } else { + SetStyle (Widgetstyles.OptimizedDoubleBuffer, false); + } + + } + } + + public void DrawToBitmap (Bitmap bitmap, Rectangle targetBounds) + { + Graphics g = Graphics.FromImage (bitmap); + + // Only draw within the target bouds, and up to the size of the Widget + g.IntersectClip (targetBounds); + g.IntersectClip (Bounds); + + // Logic copied from WmPaint + PaintEventArgs pea = new PaintEventArgs (g, targetBounds); + + if (!GetStyle (Widgetstyles.Opaque)) + OnPaintBackground (pea); + + OnPaintBackgroundInternal (pea); + + OnPaintInternal (pea); + + if (!pea.Handled) + OnPaint (pea); + + g.Dispose (); + } + + [DispId(-514)] + [Localizable(true)] + [MWFCategory("Behavior")] + public bool Enabled { + get { + if (!is_enabled) { + return false; + } + + if (parent != null) { + return parent.Enabled; + } + + return true; + } + + set { + if (this.is_enabled == value) + return; + + bool old_value = is_enabled; + + is_enabled = value; + + if (!value) + UpdateCursor (); + + if (old_value != value && !value && this.has_focus) + SelectNextWidget(this, true, true, true, true); + + OnEnabledChanged (EventArgs.Empty); + } + } + + internal bool ShouldSerializeEnabled () + { + return this.Enabled != true; + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public virtual bool Focused { + get { + return this.has_focus; + } + } + + [DispId(-512)] + [AmbientValue(null)] + [Localizable(true)] + [MWFCategory("Appearance")] + public virtual Font Font { + [return: MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (Font))] + get { + if (font != null) + return font; + + if (parent != null) { + Font f = parent.Font; + + if (f != null) + return f; + } + + return DefaultFont; + } + + [param:MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Font))] + set { + if (font != null && font == value) { + return; + } + + font = value; + Invalidate(); + OnFontChanged (EventArgs.Empty); + PerformLayout (); + } + } + + internal bool ShouldSerializeFont () + { + return !this.Font.Equals (DefaultFont); + } + + [DispId(-513)] + [MWFCategory("Appearance")] + public virtual Color ForeColor { + get { + if (foreground_color.IsEmpty) { + if (parent!=null) { + return parent.ForeColor; + } + return DefaultForeColor; + } + return foreground_color; + } + + set { + if (foreground_color != value) { + foreground_color=value; + Invalidate(); + OnForeColorChanged(EventArgs.Empty); + } + } + } + + internal bool ShouldSerializeForeColor () + { + return this.ForeColor != DefaultForeColor; + } + + [DispId(-515)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IntPtr Handle { // IWin32Window + get { + if (verify_thread_handle) { + if (this.InvokeRequired) { + throw new InvalidOperationException("Cross-thread access of handle detected. Handle access only valid on thread that created the Widget"); + } + } + if (!IsHandleCreated) { + CreateHandle(); + } + return window.Handle; + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool HasChildren { + get { + if (this.child_Widgets.Count>0) { + return true; + } + return false; + } + } + + //[EditorBrowsable(EditorBrowsableState.Always)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int Height { + get { return this.bounds.Height; } + set { SetBounds(bounds.X, bounds.Y, bounds.Width, value, BoundsSpecified.Height); } + } + + [AmbientValue(ImeMode.Inherit)] + [Localizable(true)] + [MWFCategory("Behavior")] + public ImeMode ImeMode { + get { + if (ime_mode == ImeMode.Inherit) { + if (parent != null) + return parent.ImeMode; + else + return ImeMode.NoControl; // default value + } + return ime_mode; + } + + set { + if (ime_mode != value) { + ime_mode = value; + + OnImeModeChanged(EventArgs.Empty); + } + } + } + + internal bool ShouldSerializeImeMode () + { + return this.ImeMode != ImeMode.NoControl; + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool InvokeRequired { // ISynchronizeInvoke + get { + if (creator_thread != null && creator_thread!=Thread.CurrentThread) { + return true; + } + return false; + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsAccessible { + get { + return is_accessible; + } + + set { + is_accessible = value; + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsDisposed { + get { + return this.is_disposed; + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsHandleCreated { + get { + if (window == null || window.Handle == IntPtr.Zero) + return false; + + Hwnd hwnd = Hwnd.ObjectFromHandle (window.Handle); + if (hwnd != null && hwnd.zombie) + return false; + + return true; + } + } + + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + [MonoNotSupported ("RTL is not supported")] + public bool IsMirrored { + get { return false; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public virtual Layout.LayoutEngine LayoutEngine { + get { + if (layout_engine == null) + layout_engine = new Layout.DefaultLayout (); + return layout_engine; + } + } + + //[EditorBrowsable(EditorBrowsableState.Always)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int Left { + get { + return this.bounds.Left; + } + + set { + SetBounds(value, bounds.Y, bounds.Width, bounds.Height, BoundsSpecified.X); + } + } + + [Localizable(true)] + [MWFCategory("Layout")] + public Point Location { + get { + return this.bounds.Location; + } + + set { + SetBounds(value.X, value.Y, bounds.Width, bounds.Height, BoundsSpecified.Location); + } + } + + internal bool ShouldSerializeLocation () + { + return this.Location != new Point (0, 0); + } + + [Localizable (true)] + [MWFCategory("Layout")] + public Padding Margin { + get { return this.margin; } + set { + if (this.margin != value) { + this.margin = value; + if (Parent != null) + Parent.PerformLayout (this, "Margin"); + OnMarginChanged (EventArgs.Empty); + } + } + } + + internal bool ShouldSerializeMargin () + { + return this.Margin != DefaultMargin; + } + + [Browsable(false)] + public string Name { + get { + return name; + } + + set { + name = value; + } + } + + [Localizable(true)] + [MWFCategory("Layout")] + public Padding Padding { + get { + return padding; + } + + set { + if (padding != value) { + padding = value; + OnPaddingChanged (EventArgs.Empty); + + // Changing padding generally requires a new size + if (this.AutoSize && this.Parent != null) + parent.PerformLayout (this, "Padding"); + else + PerformLayout (this, "Padding"); + } + } + } + + internal bool ShouldSerializePadding () + { + return this.Padding != DefaultPadding; + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Widget Parent { + get { + return this.parent; + } + + set { + if (value == this) { + throw new ArgumentException("A circular Widget reference has been made. A Widget cannot be owned or parented to itself."); + } + + if (parent!=value) { + if (value==null) { + parent.Widgets.Remove(this); + parent = null; + return; + } + + value.Widgets.Add(this); + } + } + } + + [Browsable (false)] + public Size PreferredSize { + get { return this.GetPreferredSize (Size.Empty); } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string ProductName { + get { + Type t = typeof (AssemblyProductAttribute); + Assembly assembly = GetType().Module.Assembly; + object [] attrs = assembly.GetCustomAttributes (t, false); + AssemblyProductAttribute a = null; + // On MS we get a NullRefException if product attribute is not + // set. + if (attrs != null && attrs.Length > 0) + a = (AssemblyProductAttribute) attrs [0]; + if (a == null) { + return GetType ().Namespace; + } + return a.Product; + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string ProductVersion { + get { + Type t = typeof (AssemblyVersionAttribute); + Assembly assembly = GetType().Module.Assembly; + object [] attrs = assembly.GetCustomAttributes (t, false); + if (attrs == null || attrs.Length < 1) + return "1.0.0.0"; + return ((AssemblyVersionAttribute)attrs [0]).Version; + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool RecreatingHandle { + get { + return is_recreating; + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Region Region { + get { + return clip_region; + } + + set { + if (clip_region != value) { + if (IsHandleCreated) + XplatUI.SetClipRegion(Handle, value); + + clip_region = value; + + OnRegionChanged (EventArgs.Empty); + } + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int Right { + get { + return this.bounds.Right; + } + } + + [AmbientValue(RightToLeft.Inherit)] + [Localizable(true)] + [MWFCategory("Appearance")] + public virtual RightToLeft RightToLeft { + get { + if (right_to_left == RightToLeft.Inherit) { + if (parent != null) + return parent.RightToLeft; + else + return RightToLeft.No; // default value + } + return right_to_left; + } + + set { + if (value != right_to_left) { + right_to_left = value; + OnRightToLeftChanged(EventArgs.Empty); + PerformLayout (); + } + } + } + + internal bool ShouldSerializeRightToLeft () + { + return this.RightToLeft != RightToLeft.No; + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public override ISite Site { + get { + return base.Site; + } + + set { + base.Site = value; + + if (value != null) { + AmbientProperties ap = (AmbientProperties) value.GetService (typeof (AmbientProperties)); + if (ap != null) { + BackColor = ap.BackColor; + ForeColor = ap.ForeColor; + Cursor = ap.Cursor; + Font = ap.Font; + } + } + } + } + + internal bool ShouldSerializeSite () + { + return false; + } + + [Localizable(true)] + [MWFCategory("Layout")] + public Size Size { + get { + return new Size(Width, Height); + } + + set { + SetBounds(bounds.X, bounds.Y, value.Width, value.Height, BoundsSpecified.Size); + } + } + + internal virtual bool ShouldSerializeSize () + { + return this.Size != DefaultSize; + } + + [Localizable(true)] + [MergableProperty(false)] + [MWFCategory("Behavior")] + public int TabIndex { + get { + if (tab_index != -1) { + return tab_index; + } + return 0; + } + + set { + if (tab_index != value) { + tab_index = value; + OnTabIndexChanged(EventArgs.Empty); + } + } + } + + [DispId(-516)] + [DefaultValue(true)] + [MWFCategory("Behavior")] + public bool TabStop { + get { + return tab_stop; + } + + set { + if (tab_stop != value) { + tab_stop = value; + OnTabStopChanged(EventArgs.Empty); + } + } + } + + [Localizable(false)] + [Bindable(true)] + [TypeConverter(typeof(StringConverter))] + [DefaultValue(null)] + [MWFCategory("Data")] + public object Tag { + get { + return Widget_tag; + } + + set { + Widget_tag = value; + } + } + + [DispId(-517)] + [Localizable(true)] + [BindableAttribute(true)] + [MWFCategory("Appearance")] + public virtual string Text { + get { + // Our implementation ignores Widgetstyles.CacheText - we always cache + return this.text; + } + + set { + if (value == null) { + value = String.Empty; + } + + if (text!=value) { + text=value; + UpdateWindowText (); + OnTextChanged (EventArgs.Empty); + + // Label has its own AutoSize implementation + if (AutoSize && Parent != null && (!(this is Label))) + Parent.PerformLayout (this, "Text"); + } + } + } + + internal virtual void UpdateWindowText () + { + if (!IsHandleCreated) { + return; + } + XplatUI.Text (Handle, text); + } + + //[EditorBrowsable(EditorBrowsableState.Always)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int Top { + get { + return this.bounds.Top; + } + + set { + SetBounds(bounds.X, value, bounds.Width, bounds.Height, BoundsSpecified.Y); + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Widget TopLevelWidget { + get { + Widget p = this; + + while (p.parent != null) { + p = p.parent; + } + + return p is Form ? p : null; + } + } + + //[EditorBrowsable(EditorBrowsableState.Always)] + [Browsable(true)] + [DefaultValue (false)] + [MWFCategory("Appearance")] + public bool UseWaitCursor { + get { return use_wait_cursor; } + set { + if (use_wait_cursor != value) { + use_wait_cursor = value; + UpdateCursor (); + OnCursorChanged (EventArgs.Empty); + } + } + } + + [Localizable(true)] + [MWFCategory("Behavior")] + public bool Visible { + get { + if (!is_visible) { + return false; + } else if (parent != null) { + return parent.Visible; + } + + return true; + } + + set { + if (this.is_visible != value) { + SetVisibleCore(value); + + if (parent != null) + parent.PerformLayout (this, "Visible"); + } + } + } + + internal bool ShouldSerializeVisible () + { + return this.Visible != true; + } + + //[EditorBrowsable(EditorBrowsableState.Always)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int Width { + get { + return this.bounds.Width; + } + + set { + SetBounds(bounds.X, bounds.Y, value, bounds.Height, BoundsSpecified.Width); + } + } + + //[EditorBrowsable(EditorBrowsableState.Never)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IWindowTarget WindowTarget { + get { return window_target; } + set { window_target = value; } + } + #endregion // Public Instance Properties + + #region Protected Instance Properties + protected virtual bool CanEnableIme { + get { return false; } + } + + // Is only false in some ActiveX contexts + protected override bool CanRaiseEvents { + get { return true; } + } + + protected virtual CreateParams CreateParams { + get { + CreateParams create_params = new CreateParams(); + + try { + create_params.Caption = Text; + } + catch { + create_params.Caption = text; + } + + try { + create_params.X = Left; + } + catch { + create_params.X = this.bounds.X; + } + + try { + create_params.Y = Top; + } + catch { + create_params.Y = this.bounds.Y; + } + + try { + create_params.Width = Width; + } + catch { + create_params.Width = this.bounds.Width; + } + + try { + create_params.Height = Height; + } + catch { + create_params.Height = this.bounds.Height; + } + + + create_params.ClassName = XplatUI.GetDefaultClassName (GetType ()); + create_params.ClassStyle = (int)(XplatUIWin32.ClassStyle.CS_OWNDC | XplatUIWin32.ClassStyle.CS_DBLCLKS); + create_params.ExStyle = 0; + create_params.Param = 0; + + if (allow_drop) { + create_params.ExStyle |= (int)WindowExStyles.WS_EX_ACCEPTFILES; + } + + if ((parent!=null) && (parent.IsHandleCreated)) { + create_params.Parent = parent.Handle; + } + + create_params.Style = (int)WindowStyles.WS_CHILD | (int)WindowStyles.WS_CLIPCHILDREN | (int)WindowStyles.WS_CLIPSIBLINGS; + + if (is_visible) { + create_params.Style |= (int)WindowStyles.WS_VISIBLE; + } + + if (!is_enabled) { + create_params.Style |= (int)WindowStyles.WS_DISABLED; + } + + switch (border_style) { + case BorderStyle.FixedSingle: + create_params.Style |= (int) WindowStyles.WS_BORDER; + break; + case BorderStyle.Fixed3D: + create_params.ExStyle |= (int) WindowExStyles.WS_EX_CLIENTEDGE; + break; + } + + create_params.control = this; + + return create_params; + } + } + + protected virtual Cursor DefaultCursor { get { return Cursors.Default; } } + + protected virtual ImeMode DefaultImeMode { + get { + return ImeMode.Inherit; + } + } + + protected virtual Padding DefaultMargin { + get { return new Padding (3); } + } + + protected virtual Size DefaultMaximumSize { get { return new Size (); } } + protected virtual Size DefaultMinimumSize { get { return new Size (); } } + protected virtual Padding DefaultPadding { get { return new Padding (); } } + + protected virtual Size DefaultSize { + get { + return new Size(0, 0); + } + } + + protected int FontHeight { + get { + return Font.Height; + } + + set { + ;; // Nothing to do + } + } + [Obsolete ()] + protected bool RenderRightToLeft { + get { + return (this.right_to_left == RightToLeft.Yes); + } + } + + protected bool ResizeRedraw { + get { + return GetStyle(Widgetstyles.ResizeRedraw); + } + + set { + SetStyle(Widgetstyles.ResizeRedraw, value); + } + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual bool ScaleChildren { + get { return ScaleChildrenInternal; } + } + + internal virtual bool ScaleChildrenInternal { + get { return true; } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + protected internal virtual bool ShowFocusCues { + get { + if (this is Form) + return show_focus_cues; + + if (this.parent == null) + return false; + + Form f = this.FindForm (); + + if (f != null) + return f.show_focus_cues; + + return false; + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + internal virtual protected bool ShowKeyboardCues { + get { + return ShowKeyboardCuesInternal; + } + } + + internal bool ShowKeyboardCuesInternal { + get { + if (SystemInformation.MenuAccessKeysUnderlined || DesignMode) + return true; + + return show_keyboard_cues; + } + } + + #endregion // Protected Instance Properties + + #region Public Static Methods + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public static Widget FromChildHandle(IntPtr handle) { + return Widget.WidgetNativeWindow.WidgetFromChildHandle (handle); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public static Widget FromHandle(IntPtr handle) { + return Widget.WidgetNativeWindow.WidgetFromHandle(handle); + } + + [MonoTODO ("Only implemented for Win32, others always return false")] + public static bool IsKeyLocked (Keys keyVal) + { + switch (keyVal) { + case Keys.CapsLock: + case Keys.NumLock: + case Keys.Scroll: + return XplatUI.IsKeyLocked ((VirtualKeys)keyVal); + default: + throw new NotSupportedException ("keyVal must be CapsLock, NumLock, or ScrollLock"); + } + } + + public static bool IsMnemonic(char charCode, string text) { + int amp; + + amp = text.IndexOf('&'); + + if (amp != -1) { + if (amp + 1 < text.Length) { + if (text[amp + 1] != '&') { + if (Char.ToUpper(charCode) == Char.ToUpper(text.ToCharArray(amp + 1, 1)[0])) { + return true; + } + } + } + } + return false; + } + #endregion + + #region Protected Static Methods + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected static bool ReflectMessage(IntPtr hWnd, ref Message m) { + Widget c; + + c = Widget.FromHandle(hWnd); + + if (c != null) { + c.WndProc(ref m); + return true; + } + return false; + } + #endregion + + #region Public Instance Methods + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public IAsyncResult BeginInvoke(Delegate method) { + object [] prms = null; + if (method is EventHandler) + prms = new object [] { this, EventArgs.Empty }; + return BeginInvokeInternal(method, prms); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public IAsyncResult BeginInvoke (Delegate method, params object[] args) + { + return BeginInvokeInternal (method, args); + } + + public void BringToFront() { + if (parent != null) { + parent.child_Widgets.SetChildIndex(this, 0); + } + else if (IsHandleCreated) { + XplatUI.SetZOrder(Handle, IntPtr.Zero, false, false); + } + } + + public bool Contains(Widget ctl) { + while (ctl != null) { + ctl = ctl.parent; + if (ctl == this) { + return true; + } + } + return false; + } + + public void CreateWidget () { + if (is_created) { + return; + } + + if (is_disposing) { + return; + } + + if (!is_visible) { + return; + } + + if (parent != null && !parent.Created) { + return; + } + + if (!IsHandleCreated) { + CreateHandle(); + } + + if (!is_created) { + is_created = true; + + // Create all of our children (implicit ones as well) when we are created. + // The child should fire it's OnLoad before the parents, however + // if the child checks Parent.Created in it's OnCreateWidget, the + // parent is already created. + foreach (Widget c in Widgets.GetAllWidgets ()) + if (!c.Created && !c.IsDisposed) + c.CreateWidget (); + + OnCreateWidget(); + } + } + + public Graphics CreateGraphics() { + if (!IsHandleCreated) { + this.CreateHandle(); + } + return Graphics.FromHwnd(this.window.Handle); + } + + public DragDropEffects DoDragDrop(object data, DragDropEffects allowedEffects) { + DragDropEffects result = DragDropEffects.None; + if (IsHandleCreated) + result = XplatUI.StartDrag(Handle, data, allowedEffects); + OnDragDropEnd (result); + return result; + } + + internal virtual void OnDragDropEnd (DragDropEffects effects) + { + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public object EndInvoke (IAsyncResult asyncResult) { + AsyncMethodResult result = (AsyncMethodResult) asyncResult; + return result.EndInvoke (); + } + + internal Widget FindRootParent () + { + Widget c = this; + + while (c.Parent != null) + c = c.Parent; + + return c; + } + + public Form FindForm() { + Widget c; + + c = this; + while (c != null) { + if (c is Form) { + return (Form)c; + } + c = c.Parent; + } + return null; + } + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public bool Focus() { + return FocusInternal (false); + } + + internal virtual bool FocusInternal (bool skip_check) { + if (skip_check || (CanFocus && IsHandleCreated && !has_focus && !is_focusing)) { + is_focusing = true; + Select(this); + is_focusing = false; + } + return has_focus; + } + + internal Widget GetRealChildAtPoint (Point pt) { + if (!IsHandleCreated) + CreateHandle (); + + foreach (Widget Widget in child_Widgets.GetAllWidgets ()) { + if (Widget.Bounds.Contains (PointToClient (pt))) { + Widget child = Widget.GetRealChildAtPoint (pt); + if (child == null) + return Widget; + else + return child; + } + } + + return null; + } + + public Widget GetChildAtPoint(Point pt) + { + return GetChildAtPoint (pt, GetChildAtPointSkip.None); + } + + public Widget GetChildAtPoint (Point pt, GetChildAtPointSkip skipValue) + { + // MS's version causes the handle to be created. The stack trace shows that get_Handle is called here, but + // we'll just call CreateHandle instead. + if (!IsHandleCreated) + CreateHandle (); + + // Microsoft's version of this function doesn't seem to work, so I can't check + // if we only consider children or also grandchildren, etc. + // I'm gonna say 'children only' + foreach (Widget child in Widgets) { + if ((skipValue & GetChildAtPointSkip.Disabled) == GetChildAtPointSkip.Disabled && !child.Enabled) + continue; + else if ((skipValue & GetChildAtPointSkip.Invisible) == GetChildAtPointSkip.Invisible && !child.Visible) + continue; + else if ((skipValue & GetChildAtPointSkip.Transparent) == GetChildAtPointSkip.Transparent && child.BackColor.A == 0x0) + continue; + else if (child.Bounds.Contains (pt)) + return child; + } + + return null; + } + + public IContainerWidget GetContainerWidget() { + Widget current = this; + + while (current!=null) { + if ((current is IContainerWidget) && ((current.Widget_style & Widgetstyles.ContainerWidget)!=0)) { + return (IContainerWidget)current; + } + current = current.parent; + } + return null; + } + + internal ContainerWidget InternalGetContainerWidget() { + Widget current = this; + + while (current!=null) { + if ((current is ContainerWidget) && ((current.Widget_style & Widgetstyles.ContainerWidget)!=0)) { + return current as ContainerWidget; + } + current = current.parent; + } + return null; + } + + public Widget GetNextWidget(Widget ctl, bool forward) { + + if (!this.Contains(ctl)) { + ctl = this; + } + + if (forward) { + ctl = FindWidgetForward(this, ctl); + } + else { + ctl = FindWidgetBackward(this, ctl); + } + + if (ctl != this) { + return ctl; + } + return null; + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public virtual Size GetPreferredSize (Size proposedSize) { + Size retsize = GetPreferredSizeCore (proposedSize); + + // If we're bigger than the MaximumSize, fix that + if (this.maximum_size.Width != 0 && retsize.Width > this.maximum_size.Width) + retsize.Width = this.maximum_size.Width; + if (this.maximum_size.Height != 0 && retsize.Height > this.maximum_size.Height) + retsize.Height = this.maximum_size.Height; + + // If we're smaller than the MinimumSize, fix that + if (this.minimum_size.Width != 0 && retsize.Width < this.minimum_size.Width) + retsize.Width = this.minimum_size.Width; + if (this.minimum_size.Height != 0 && retsize.Height < this.minimum_size.Height) + retsize.Height = this.minimum_size.Height; + + return retsize; + } + + public void Hide() { + this.Visible = false; + } + + public void Invalidate () + { + Invalidate (ClientRectangle, false); + } + + public void Invalidate (bool invalidateChildren) + { + Invalidate (ClientRectangle, invalidateChildren); + } + + public void Invalidate (Rectangle rc) + { + Invalidate (rc, false); + } + + public void Invalidate (Rectangle rc, bool invalidateChildren) + { + // Win32 invalidates Widget including when Width and Height is equal 0 + // or is not visible, only Paint event must be care about this. + if (!IsHandleCreated) + return; + + if (rc.IsEmpty) + rc = ClientRectangle; + + if (rc.Width > 0 && rc.Height > 0) { + + NotifyInvalidate(rc); + + XplatUI.Invalidate(Handle, rc, false); + + if (invalidateChildren) { + Widget [] Widgets = child_Widgets.GetAllWidgets (); + for (int i=0; i 0) { + layout_pending = true; + return; + } + + layout_pending = false; + + // Prevent us from getting messed up + layout_suspended++; + + // Perform all Dock and Anchor calculations + try { + OnLayout(levent); + } + + // Need to make sure we decremend layout_suspended + finally { + layout_suspended--; + } + } + + public Point PointToClient (Point p) { + int x = p.X; + int y = p.Y; + + XplatUI.ScreenToClient (Handle, ref x, ref y); + + return new Point (x, y); + } + + public Point PointToScreen(Point p) { + int x = p.X; + int y = p.Y; + + XplatUI.ClientToScreen(Handle, ref x, ref y); + + return new Point(x, y); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public PreProcessWidgetstate PreProcessWidgetMessage (ref Message msg) + { + return PreProcessWidgetMessageInternal (ref msg); + } + + internal PreProcessWidgetstate PreProcessWidgetMessageInternal (ref Message msg) + { + switch ((Msg)msg.Msg) { + case Msg.WM_KEYDOWN: + case Msg.WM_SYSKEYDOWN: + PreviewKeyDownEventArgs e = new PreviewKeyDownEventArgs ((Keys)msg.WParam.ToInt32 () | XplatUI.State.ModifierKeys); + OnPreviewKeyDown (e); + + if (e.IsInputKey) + return PreProcessWidgetstate.MessageNeeded; + + if (PreProcessMessage (ref msg)) + return PreProcessWidgetstate.MessageProcessed; + + if (IsInputKey ((Keys)msg.WParam.ToInt32 () | XplatUI.State.ModifierKeys)) + return PreProcessWidgetstate.MessageNeeded; + + break; + case Msg.WM_CHAR: + case Msg.WM_SYSCHAR: + if (PreProcessMessage (ref msg)) + return PreProcessWidgetstate.MessageProcessed; + + if (IsInputChar ((char)msg.WParam)) + return PreProcessWidgetstate.MessageNeeded; + + break; + default: + break; + } + + return PreProcessWidgetstate.MessageNotNeeded; + } + + public virtual bool PreProcessMessage (ref Message msg) + { + return InternalPreProcessMessage (ref msg); + } + + internal virtual bool InternalPreProcessMessage (ref Message msg) { + Keys key_data; + + if ((msg.Msg == (int)Msg.WM_KEYDOWN) || (msg.Msg == (int)Msg.WM_SYSKEYDOWN)) { + key_data = (Keys)msg.WParam.ToInt32() | XplatUI.State.ModifierKeys; + + if (!ProcessCmdKey(ref msg, key_data)) { + if (IsInputKey(key_data)) { + return false; + } + + return ProcessDialogKey(key_data); + } + + return true; + } else if (msg.Msg == (int)Msg.WM_CHAR) { + if (IsInputChar((char)msg.WParam)) { + return false; + } + return ProcessDialogChar((char)msg.WParam); + } else if (msg.Msg == (int)Msg.WM_SYSCHAR) { + if (ProcessDialogChar((char)msg.WParam)) + return true; + else + return ToolStripManager.ProcessMenuKey (ref msg); + } + return false; + } + + public Rectangle RectangleToClient(Rectangle r) { + return new Rectangle(PointToClient(r.Location), r.Size); + } + + public Rectangle RectangleToScreen(Rectangle r) { + return new Rectangle(PointToScreen(r.Location), r.Size); + } + + public virtual void Refresh() { + if (IsHandleCreated && Visible) { + Invalidate(true); + Update (); + } + } + + //[EditorBrowsable(EditorBrowsableState.Never)] + public virtual void ResetBackColor() { + BackColor = Color.Empty; + } + + //[EditorBrowsable(EditorBrowsableState.Never)] + public void ResetBindings() { + if (data_bindings != null) + data_bindings.Clear(); + } + + //[EditorBrowsable(EditorBrowsableState.Never)] + public virtual void ResetCursor() { + Cursor = null; + } + + //[EditorBrowsable(EditorBrowsableState.Never)] + public virtual void ResetFont() { + font = null; + } + + //[EditorBrowsable(EditorBrowsableState.Never)] + public virtual void ResetForeColor() { + foreground_color = Color.Empty; + } + + //[EditorBrowsable(EditorBrowsableState.Never)] + public void ResetImeMode() { + ime_mode = DefaultImeMode; + } + + //[EditorBrowsable(EditorBrowsableState.Never)] + public virtual void ResetRightToLeft() { + right_to_left = RightToLeft.Inherit; + } + + public virtual void ResetText() { + Text = String.Empty; + } + + public void ResumeLayout() { + ResumeLayout (true); + } + + public void ResumeLayout(bool performLayout) { + if (layout_suspended > 0) { + layout_suspended--; + } + + if (layout_suspended == 0) { + if (this is ContainerWidget) + (this as ContainerWidget).PerformDelayedAutoScale(); + + if (!performLayout) + foreach (Widget c in Widgets.GetAllWidgets ()) + c.UpdateDistances (); + + if (performLayout && layout_pending) { + PerformLayout(); + } + } + } + //[EditorBrowsable (EditorBrowsableState.Never)] + [Obsolete ()] + public void Scale(float ratio) { + ScaleCore(ratio, ratio); + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Obsolete ()] + public void Scale(float dx, float dy) { + ScaleCore(dx, dy); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public void Scale (SizeF factor) + { + BoundsSpecified bounds_spec = BoundsSpecified.All; + + SuspendLayout (); + + if (this is ContainerWidget) { + if ((this as ContainerWidget).IsAutoScaling) + bounds_spec = BoundsSpecified.Size; + else if (IsContainerAutoScaling (this.Parent)) + bounds_spec = BoundsSpecified.Location; + } + + ScaleWidget (factor, bounds_spec); + + // Scale children + if ((bounds_spec != BoundsSpecified.Location) && ScaleChildren) { + foreach (Widget c in Widgets.GetAllWidgets ()) { + c.Scale (factor); + if (c is ContainerWidget) { + ContainerWidget cc = c as ContainerWidget; + if ((cc.AutoScaleMode == AutoScaleMode.Inherit) && IsContainerAutoScaling (this)) + cc.PerformAutoScale (true); + } + } + } + + ResumeLayout (); + } + + internal ContainerWidget FindContainer (Widget c) + { + while ((c != null) && !(c is ContainerWidget)) + c = c.Parent; + return c as ContainerWidget; + } + + private bool IsContainerAutoScaling (Widget c) + { + ContainerWidget cc = FindContainer (c); + return (cc != null) && cc.IsAutoScaling; + } + + public void Select() { + Select(false, false); + } + + #if DebugFocus + private void printTree(Widget c, string t) { + foreach(Widget i in c.child_Widgets) { + Console.WriteLine ("{2}{0}.TabIndex={1}", i, i.tab_index, t); + printTree (i, t+"\t"); + } + } + #endif + public bool SelectNextWidget(Widget ctl, bool forward, bool tabStopOnly, bool nested, bool wrap) { + Widget c; + + #if DebugFocus + Console.WriteLine("{0}", this.FindForm()); + printTree(this, "\t"); + #endif + + if (!this.Contains(ctl) || (!nested && (ctl.parent != this))) { + ctl = null; + } + c = ctl; + do { + c = GetNextWidget(c, forward); + if (c == null) { + if (wrap) { + wrap = false; + continue; + } + break; + } + + #if DebugFocus + Console.WriteLine("{0} {1}", c, c.CanSelect); + #endif + if (c.CanSelect && ((c.parent == this) || nested) && (c.tab_stop || !tabStopOnly)) { + c.Select (true, true); + return true; + } + } while (c != ctl); // If we wrap back to ourselves we stop + + return false; + } + + public void SendToBack() { + if (parent != null) { + parent.child_Widgets.SetChildIndex(this, parent.child_Widgets.Count); + } + } + + public void SetBounds(int x, int y, int width, int height) { + SetBounds(x, y, width, height, BoundsSpecified.All); + } + + public void SetBounds(int x, int y, int width, int height, BoundsSpecified specified) { + // Fill in the values that were not specified + if ((specified & BoundsSpecified.X) == 0) + x = Left; + if ((specified & BoundsSpecified.Y) == 0) + y = Top; + if ((specified & BoundsSpecified.Width) == 0) + width = Width; + if ((specified & BoundsSpecified.Height) == 0) + height = Height; + + SetBoundsInternal (x, y, width, height, specified); + } + + internal void SetBoundsInternal (int x, int y, int width, int height, BoundsSpecified specified) + { + // SetBoundsCore is really expensive to call, so we want to avoid it if we can. + // We can avoid it if: + // - The requested dimensions are the same as our current dimensions + // AND + // - Any BoundsSpecified is the same as our current explicit_size + if (bounds.X != x || (explicit_bounds.X != x && (specified & BoundsSpecified.X) == BoundsSpecified.X)) + SetBoundsCore (x, y, width, height, specified); + else if (bounds.Y != y || (explicit_bounds.Y != y && (specified & BoundsSpecified.Y) == BoundsSpecified.Y)) + SetBoundsCore (x, y, width, height, specified); + else if (bounds.Width != width || (explicit_bounds.Width != width && (specified & BoundsSpecified.Width) == BoundsSpecified.Width)) + SetBoundsCore (x, y, width, height, specified); + else if (bounds.Height != height || (explicit_bounds.Height != height && (specified & BoundsSpecified.Height) == BoundsSpecified.Height)) + SetBoundsCore (x, y, width, height, specified); + else + return; + + // If the user explicitly moved or resized us, recalculate our anchor distances + if (specified != BoundsSpecified.None) + UpdateDistances (); + + if (parent != null) + parent.PerformLayout(this, "Bounds"); + } + + public void Show () { + this.Visible = true; + } + + public void SuspendLayout() { + layout_suspended++; + } + + public void Update() { + if (IsHandleCreated) { + XplatUI.UpdateWindow(window.Handle); + } + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected void AccessibilityNotifyClients(AccessibleEvents accEvent, int childID) { + // turns out this method causes handle + // creation in 1.1. at first I thought this + // would be accomplished just by using + // get_AccessibilityObject, which would route + // through CreateAccessibilityInstance, which + // calls CreateWidget. This isn't the case, + // though (as overriding + // CreateAccessibilityInstance and adding a + // CWL shows nothing. So we fudge it and put + // a CreateHandle here. + + + if (accessibility_object != null && accessibility_object is WidgetAccessibleObject) + ((WidgetAccessibleObject)accessibility_object).NotifyClients (accEvent, childID); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected void AccessibilityNotifyClients (AccessibleEvents accEvent, int objectID, int childID) + { + if (accessibility_object != null && accessibility_object is WidgetAccessibleObject) + ((WidgetAccessibleObject)accessibility_object).NotifyClients (accEvent, objectID, childID); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual AccessibleObject CreateAccessibilityInstance() { + CreateWidget (); + return new Widget.WidgetAccessibleObject(this); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual WidgetCollection CreateWidgetsInstance() { + return new WidgetCollection(this); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void CreateHandle() { + if (IsDisposed) { + throw new ObjectDisposedException(GetType().FullName); + } + + if (IsHandleCreated && !is_recreating) { + return; + } + + CreateParams create_params = CreateParams; + window.CreateHandle(create_params); + + if (window.Handle != IntPtr.Zero) { + creator_thread = Thread.CurrentThread; + + XplatUI.EnableWindow(window.Handle, is_enabled); + + if (clip_region != null) { + XplatUI.SetClipRegion(window.Handle, clip_region); + } + + // Set our handle with our parent + if ((parent != null) && (parent.IsHandleCreated)) { + XplatUI.SetParent(window.Handle, parent.Handle); + } + + UpdateStyles(); + XplatUI.SetAllowDrop (window.Handle, allow_drop); + + // Find out where the window manager placed us + if ((CreateParams.Style & (int)WindowStyles.WS_CHILD) != 0) { + // XplatUI.SetBorderStyle(window.Handle, (FormBorderStyle)border_style); + } + + Rectangle save_bounds = explicit_bounds; + UpdateBounds (); + explicit_bounds = save_bounds; + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void DefWndProc(ref Message m) { + window.DefWndProc(ref m); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void DestroyHandle() { + if (IsHandleCreated) { + if (window != null) { + window.DestroyHandle(); + } + } + } + + protected virtual AccessibleObject GetAccessibilityObjectById (int objectId) + { + // XXX need to implement this. + return null; + } + + protected internal AutoSizeMode GetAutoSizeMode () + { + return auto_size_mode; + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual Rectangle GetScaledBounds (Rectangle bounds, SizeF factor, BoundsSpecified specified) + { + // Top level Widgets do not scale location + if (!is_toplevel) { + if ((specified & BoundsSpecified.X) == BoundsSpecified.X) + bounds.X = (int)Math.Round (bounds.X * factor.Width); + if ((specified & BoundsSpecified.Y) == BoundsSpecified.Y) + bounds.Y = (int)Math.Round (bounds.Y * factor.Height); + } + + if ((specified & BoundsSpecified.Width) == BoundsSpecified.Width && !GetStyle (Widgetstyles.FixedWidth)) { + int border = (this is ComboBox) ? (ThemeEngine.Current.Border3DSize.Width * 2) : + (this.bounds.Width - this.client_size.Width); + bounds.Width = (int)Math.Round ((bounds.Width - border) * factor.Width + border); + } + if ((specified & BoundsSpecified.Height) == BoundsSpecified.Height && !GetStyle (Widgetstyles.FixedHeight)) { + int border = (this is ComboBox) ? (ThemeEngine.Current.Border3DSize.Height * 2) : + (this.bounds.Height - this.client_size.Height); + bounds.Height = (int)Math.Round ((bounds.Height - border) * factor.Height + border); + } + + return bounds; + } + + private Rectangle GetScaledBoundsOld (Rectangle bounds, SizeF factor, BoundsSpecified specified) + { + RectangleF new_bounds = new RectangleF(bounds.Location, bounds.Size); + + // Top level Widgets do not scale location + if (!is_toplevel) { + if ((specified & BoundsSpecified.X) == BoundsSpecified.X) + new_bounds.X *= factor.Width; + if ((specified & BoundsSpecified.Y) == BoundsSpecified.Y) + new_bounds.Y *= factor.Height; + } + + if ((specified & BoundsSpecified.Width) == BoundsSpecified.Width && !GetStyle (Widgetstyles.FixedWidth)) { + int border = (this is Form) ? (this.bounds.Width - this.client_size.Width) : 0; + new_bounds.Width = ((new_bounds.Width - border) * factor.Width + border); + } + if ((specified & BoundsSpecified.Height) == BoundsSpecified.Height && !GetStyle (Widgetstyles.FixedHeight)) { + int border = (this is Form) ? (this.bounds.Height - this.client_size.Height) : 0; + new_bounds.Height = ((new_bounds.Height - border) * factor.Height + border); + } + + bounds.X = (int)Math.Round (new_bounds.X); + bounds.Y = (int)Math.Round (new_bounds.Y); + bounds.Width = (int)Math.Round (new_bounds.Right) - bounds.X; + bounds.Height = (int)Math.Round (new_bounds.Bottom) - bounds.Y; + + return bounds; + } + + protected internal bool GetStyle(Widgetstyles flag) { + return (Widget_style & flag) != 0; + } + + protected bool GetTopLevel() { + return is_toplevel; + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void InitLayout() { + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected void InvokeGotFocus(Widget toInvoke, EventArgs e) { + toInvoke.OnGotFocus(e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected void InvokeLostFocus(Widget toInvoke, EventArgs e) { + toInvoke.OnLostFocus(e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected void InvokeOnClick(Widget toInvoke, EventArgs e) { + toInvoke.OnClick(e); + } + + protected void InvokePaint(Widget c, PaintEventArgs e) { + c.OnPaint (e); + } + + protected void InvokePaintBackground(Widget c, PaintEventArgs e) { + c.OnPaintBackground (e); + } + + protected virtual bool IsInputChar (char charCode) { + // XXX on MS.NET this method causes the handle to be created.. + if (!IsHandleCreated) + CreateHandle (); + + return IsInputCharInternal (charCode); + } + + internal virtual bool IsInputCharInternal (char charCode) { + return false; + } + + protected virtual bool IsInputKey (Keys keyData) { + // Doc says this one calls IsInputChar; not sure what to do with that + return false; + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void NotifyInvalidate(Rectangle invalidatedArea) { + // override me? + } + + protected virtual bool ProcessCmdKey(ref Message msg, Keys keyData) { + if (parent != null) { + return parent.ProcessCmdKey(ref msg, keyData); + } + + return false; + } + + protected virtual bool ProcessDialogChar(char charCode) { + if (parent != null) { + return parent.ProcessDialogChar (charCode); + } + + return false; + } + + protected virtual bool ProcessDialogKey (Keys keyData) { + if (parent != null) { + return parent.ProcessDialogKey (keyData); + } + + return false; + } + + protected virtual bool ProcessKeyEventArgs (ref Message m) + { + KeyEventArgs key_event; + + switch (m.Msg) { + case (int)Msg.WM_SYSKEYDOWN: + case (int)Msg.WM_KEYDOWN: { + key_event = new KeyEventArgs (((Keys) m.WParam.ToInt32 ()) | XplatUI.State.ModifierKeys); + OnKeyDown (key_event); + suppressing_key_press = key_event.SuppressKeyPress; + return key_event.Handled; + } + + case (int)Msg.WM_SYSKEYUP: + case (int)Msg.WM_KEYUP: { + key_event = new KeyEventArgs (((Keys) m.WParam.ToInt32 ()) | XplatUI.State.ModifierKeys); + OnKeyUp (key_event); + return key_event.Handled; + } + + case (int)Msg.WM_SYSCHAR: + case (int)Msg.WM_CHAR: { + if (suppressing_key_press) + return true; + KeyPressEventArgs key_press_event; + + key_press_event = new KeyPressEventArgs ((char) m.WParam); + OnKeyPress(key_press_event); + m.WParam = (IntPtr) key_press_event.KeyChar; + return key_press_event.Handled; + } + + default: { + break; + } + } + + return false; + } + + protected internal virtual bool ProcessKeyMessage (ref Message m) + { + if (parent != null) { + if (parent.ProcessKeyPreview (ref m)) + return true; + } + + return ProcessKeyEventArgs (ref m); + } + + protected virtual bool ProcessKeyPreview (ref Message m) { + if (parent != null) + return parent.ProcessKeyPreview(ref m); + + return false; + } + + protected virtual bool ProcessMnemonic(char charCode) { + // override me + return false; + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected void RaiseDragEvent(object key, DragEventArgs e) { + // MS Internal + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected void RaiseKeyEvent(object key, KeyEventArgs e) { + // MS Internal + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected void RaiseMouseEvent(object key, MouseEventArgs e) { + // MS Internal + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected void RaisePaintEvent(object key, PaintEventArgs e) { + // MS Internal + } + + private void SetIsRecreating () { + is_recreating=true; + + foreach (Widget c in Widgets.GetAllWidgets()) { + c.SetIsRecreating (); + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected void RecreateHandle() { + if (!IsHandleCreated) + return; + + #if DebugRecreate + Console.WriteLine("Recreating Widget {0}", XplatUI.Window(window.Handle)); + #endif + + SetIsRecreating (); + + if (IsHandleCreated) { + #if DebugRecreate + Console.WriteLine(" + handle is created, destroying it."); + #endif + DestroyHandle(); + // WM_DESTROY will CreateHandle for us + } else { + #if DebugRecreate + Console.WriteLine(" + handle is not created, creating it."); + #endif + if (!is_created) { + CreateWidget(); + } else { + CreateHandle(); + } + + is_recreating = false; + #if DebugRecreate + Console.WriteLine (" + new handle = {0:X}", Handle.ToInt32()); + #endif + } + + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected void ResetMouseEventArgs() { + // MS Internal + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected ContentAlignment RtlTranslateAlignment(ContentAlignment align) { + if (right_to_left == RightToLeft.No) { + return align; + } + + switch (align) { + case ContentAlignment.TopLeft: { + return ContentAlignment.TopRight; + } + + case ContentAlignment.TopRight: { + return ContentAlignment.TopLeft; + } + + case ContentAlignment.MiddleLeft: { + return ContentAlignment.MiddleRight; + } + + case ContentAlignment.MiddleRight: { + return ContentAlignment.MiddleLeft; + } + + case ContentAlignment.BottomLeft: { + return ContentAlignment.BottomRight; + } + + case ContentAlignment.BottomRight: { + return ContentAlignment.BottomLeft; + } + + default: { + // if it's center it doesn't change + return align; + } + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected HorizontalAlignment RtlTranslateAlignment(HorizontalAlignment align) { + if ((right_to_left == RightToLeft.No) || (align == HorizontalAlignment.Center)) { + return align; + } + + if (align == HorizontalAlignment.Left) { + return HorizontalAlignment.Right; + } + + // align must be HorizontalAlignment.Right + return HorizontalAlignment.Left; + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected LeftRightAlignment RtlTranslateAlignment(LeftRightAlignment align) { + if (right_to_left == RightToLeft.No) { + return align; + } + + if (align == LeftRightAlignment.Left) { + return LeftRightAlignment.Right; + } + + // align must be LeftRightAlignment.Right; + return LeftRightAlignment.Left; + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected ContentAlignment RtlTranslateContent(ContentAlignment align) { + return RtlTranslateAlignment(align); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected HorizontalAlignment RtlTranslateHorizontal(HorizontalAlignment align) { + return RtlTranslateAlignment(align); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected LeftRightAlignment RtlTranslateLeftRight(LeftRightAlignment align) { + return RtlTranslateAlignment(align); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void ScaleWidget (SizeF factor, BoundsSpecified specified) + { + Rectangle new_bounds = GetScaledBounds (bounds, factor, specified); + + SetBounds (new_bounds.X, new_bounds.Y, new_bounds.Width, new_bounds.Height, specified); + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + protected virtual void ScaleCore (float dx, float dy) + { + Rectangle new_bounds = GetScaledBoundsOld (bounds, new SizeF (dx, dy), BoundsSpecified.All); + + SuspendLayout (); + + SetBounds (new_bounds.X, new_bounds.Y, new_bounds.Width, new_bounds.Height, BoundsSpecified.All); + + if (ScaleChildrenInternal) + foreach (Widget c in Widgets.GetAllWidgets ()) + c.Scale (dx, dy); + + ResumeLayout (); + } + + protected virtual void Select(bool directed, bool forward) { + IContainerWidget container; + + container = GetContainerWidget(); + if (container != null && (Widget)container != this) + container.ActiveWidget = this; + } + + protected void SetAutoSizeMode (AutoSizeMode mode) + { + if (auto_size_mode != mode) { + auto_size_mode = mode; + PerformLayout (this, "AutoSizeMode"); + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) { + SetBoundsCoreInternal (x, y, width, height, specified); + } + + internal virtual void SetBoundsCoreInternal(int x, int y, int width, int height, BoundsSpecified specified) { + // Nasty hack for 2.0 DateTimePicker + height = OverrideHeight (height); + + Rectangle old_explicit = explicit_bounds; + Rectangle new_bounds = new Rectangle (x, y, width, height); + + // SetBoundsCore updates the Win32 Widget itself. UpdateBounds updates the Widgets variables and fires events, I'm guessing - pdb + if (IsHandleCreated) { + XplatUI.SetWindowPos(Handle, x, y, width, height); + + // Win32 automatically changes negative width/height to 0. + // The Widget has already been sent a WM_WINDOWPOSCHANGED message and it has the correct + // data, but it'll be overwritten when we call UpdateBounds unless we get the updated + // size. + int cw, ch, ix, iy; + XplatUI.GetWindowPos(Handle, this is Form, out ix, out iy, out width, out height, out cw, out ch); + } + + // BoundsSpecified tells us which variables were programatic (user-set). + // We need to store those in the explicit bounds + if ((specified & BoundsSpecified.X) == BoundsSpecified.X) + explicit_bounds.X = new_bounds.X; + else + explicit_bounds.X = old_explicit.X; + + if ((specified & BoundsSpecified.Y) == BoundsSpecified.Y) + explicit_bounds.Y = new_bounds.Y; + else + explicit_bounds.Y = old_explicit.Y; + + if ((specified & BoundsSpecified.Width) == BoundsSpecified.Width) + explicit_bounds.Width = new_bounds.Width; + else + explicit_bounds.Width = old_explicit.Width; + + if ((specified & BoundsSpecified.Height) == BoundsSpecified.Height) + explicit_bounds.Height = new_bounds.Height; + else + explicit_bounds.Height = old_explicit.Height; + + // We need to store the explicit bounds because UpdateBounds is always going + // to change it, and we have to fix it. However, UpdateBounds also calls + // OnLocationChanged, OnSizeChanged, and OnClientSizeChanged. The user can + // override those or use those events to change the size explicitly, and we + // can't undo those changes. So if the bounds after calling UpdateBounds are + // the same as the ones we sent it, we need to fix the explicit bounds. If + // it's not the same as we sent UpdateBounds, then someone else changed it, and + // we better not mess it up. Fun stuff. + Rectangle stored_explicit_bounds = explicit_bounds; + + UpdateBounds(x, y, width, height); + + if (explicit_bounds.X == x) + explicit_bounds.X = stored_explicit_bounds.X; + + if (explicit_bounds.Y == y) + explicit_bounds.Y = stored_explicit_bounds.Y; + + if (explicit_bounds.Width == width) + explicit_bounds.Width = stored_explicit_bounds.Width; + + if (explicit_bounds.Height == height) + explicit_bounds.Height = stored_explicit_bounds.Height; + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void SetClientSizeCore(int x, int y) { + Size NewSize = InternalSizeFromClientSize (new Size (x, y)); + + if (NewSize != Size.Empty) + SetBounds (bounds.X, bounds.Y, NewSize.Width, NewSize.Height, BoundsSpecified.Size); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected internal void SetStyle(Widgetstyles flag, bool value) { + if (value) { + Widget_style |= flag; + } else { + Widget_style &= ~flag; + } + } + + protected void SetTopLevel(bool value) { + if ((GetTopLevel() != value) && (parent != null)) { + throw new ArgumentException ("Cannot change toplevel style of a parented Widget."); + } + + if (this is Form) { + if (IsHandleCreated && value != Visible) { + Visible = value; + } + } else { + // XXX MS.NET causes handle to be created here + if (!IsHandleCreated) + CreateHandle (); + } + is_toplevel = value; + } + + protected virtual void SetVisibleCore(bool value) { + if (value != is_visible) { + is_visible = value; + + if (is_visible && ((window.Handle == IntPtr.Zero) || !is_created)) { + CreateWidget(); + if (!(this is Form)) + UpdateZOrder (); + } + + if (IsHandleCreated) { + XplatUI.SetVisible (Handle, is_visible, true); + if (!is_visible) { + if (parent != null && parent.IsHandleCreated) { + parent.Invalidate (bounds); + parent.Update (); + } else { + Refresh (); + } + } else if (is_visible && this is Form) { + // If we are Min or Max, we won't get a WM_SHOWWINDOW from SetWindowState, + // so we need to manually create our children, and set them visible + // (This normally happens in WmShowWindow.) + if ((this as Form).WindowState != FormWindowState.Normal) + OnVisibleChanged (EventArgs.Empty); + else + // Explicitly move Toplevel windows to where we want them; + // apparently moving unmapped toplevel windows doesn't work + XplatUI.SetWindowPos(window.Handle, bounds.X, bounds.Y, bounds.Width, bounds.Height); + } else { + // If we are becoming visible, z-order may have changed while + // we were invisible, so update our z-order position + if (parent != null) + parent.UpdateZOrderOfChild (this); + } + + if (!(this is Form)) + OnVisibleChanged (EventArgs.Empty); + } + else { + OnVisibleChanged(EventArgs.Empty); + } + } + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual Size SizeFromClientSize (Size clientSize) { + return InternalSizeFromClientSize (clientSize); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected void UpdateBounds() { + if (!IsHandleCreated) + return; + + int x; + int y; + int width; + int height; + int client_width; + int client_height; + + XplatUI.GetWindowPos(this.Handle, this is Form, out x, out y, out width, out height, out client_width, out client_height); + + UpdateBounds(x, y, width, height, client_width, client_height); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected void UpdateBounds(int x, int y, int width, int height) { + CreateParams cp; + Rectangle rect; + + // Calculate client rectangle + rect = new Rectangle(0, 0, 0, 0); + cp = CreateParams; + + XplatUI.CalculateWindowRect(ref rect, cp, cp.menu, out rect); + UpdateBounds(x, y, width, height, width - (rect.Right - rect.Left), height - (rect.Bottom - rect.Top)); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected void UpdateBounds(int x, int y, int width, int height, int clientWidth, int clientHeight) { + // UpdateBounds only seems to set our sizes and fire events but not update the GUI window to match + bool moved = false; + bool resized = false; + + // Needed to generate required notifications + if ((this.bounds.X!=x) || (this.bounds.Y!=y)) { + moved=true; + } + + if ((this.Bounds.Width!=width) || (this.Bounds.Height!=height)) { + resized=true; + } + + bounds.X=x; + bounds.Y=y; + bounds.Width=width; + bounds.Height=height; + + // Assume explicit bounds set. SetBoundsCore will restore old bounds + // if needed. + explicit_bounds = bounds; + + client_size.Width=clientWidth; + client_size.Height=clientHeight; + + if (moved) { + OnLocationChanged(EventArgs.Empty); + + if (!background_color.IsEmpty && background_color.A < byte.MaxValue) + Invalidate (); + } + + if (resized) { + OnSizeInitializedOrChanged (); + OnSizeChanged(EventArgs.Empty); + OnClientSizeChanged (EventArgs.Empty); + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected void UpdateStyles() { + if (!IsHandleCreated) { + return; + } + XplatUI.SetWindowStyle(window.Handle, CreateParams); + OnStyleChanged(EventArgs.Empty); + } + + private void UpdateZOrderOfChild(Widget child) { + if (IsHandleCreated && child.IsHandleCreated && (child.parent == this) && Hwnd.ObjectFromHandle(child.Handle).Mapped) { + // Need to take into account all Widgets + Widget [] all_Widgets = child_Widgets.GetAllWidgets (); + + int index = Array.IndexOf (all_Widgets, child); + + for (; index > 0; index--) { + if (!all_Widgets [index - 1].IsHandleCreated || !all_Widgets [index - 1].VisibleInternal || !Hwnd.ObjectFromHandle(all_Widgets [index - 1].Handle).Mapped) + continue; + break; + } + + if (index > 0) { + XplatUI.SetZOrder(child.Handle, all_Widgets [index - 1].Handle, false, false); + } else { + IntPtr after = AfterTopMostWidget (); + if (after != IntPtr.Zero && after != child.Handle) + XplatUI.SetZOrder (child.Handle, after, false, false); + else + XplatUI.SetZOrder (child.Handle, IntPtr.Zero, true, false); + } + } + } + + // Override this if there is a Widget that shall always remain on + // top of other Widgets (such as scrollbars). If there are several + // of these Widgets, the bottom-most should be returned. + internal virtual IntPtr AfterTopMostWidget () { + return IntPtr.Zero; + } + + // internal because we need to call it from ScrollableWidget.OnVisibleChanged + internal void UpdateChildrenZOrder() { + Widget [] Widgets; + + if (!IsHandleCreated) { + return; + } + + // XXX This code is severely broken. It leaks + // the "zero_sized" abstraction out of the X11 + // backend and into Widget.cs. It'll work on + // windows simply by virtue of windows never + // setting that field to true. + // + // basically what we need to guard against is + // calling XplatUI.SetZOrder on an hwnd that + // corresponds to an unmapped X window. + // + // Also, explicitly send implicit Widgets to the back. + if (child_Widgets.ImplicitWidgets == null) { + Widgets = new Widget [child_Widgets.Count]; + child_Widgets.CopyTo (Widgets, 0); + } else { + Widgets = new Widget [child_Widgets.Count + child_Widgets.ImplicitWidgets.Count]; + child_Widgets.CopyTo (Widgets, 0); + child_Widgets.ImplicitWidgets.CopyTo (Widgets, child_Widgets.Count); + } + + ArrayList children_to_order = new ArrayList (); + + for (int i = 0; i < Widgets.Length; i ++) { + if (!Widgets[i].IsHandleCreated || !Widgets[i].VisibleInternal) + continue; + + Hwnd hwnd = Hwnd.ObjectFromHandle (Widgets[i].Handle); + if (hwnd == null || hwnd.zero_sized) + continue; + + children_to_order.Add (Widgets[i]); + } + + for (int i = 1; i < children_to_order.Count; i ++) { + Widget upper = (Widget)children_to_order[i-1]; + Widget lower = (Widget)children_to_order[i]; + + XplatUI.SetZOrder(lower.Handle, upper.Handle, false, false); + } + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected void UpdateZOrder() { + if (parent != null) { + parent.UpdateZOrderOfChild(this); + } + } + + protected virtual void WndProc(ref Message m) { + #if DebugMessages + Console.WriteLine("Widget {0} received message {1}", window.Handle == IntPtr.Zero ? this.Text : XplatUI.Window(window.Handle), m.ToString ()); + #endif + if ((this.Widget_style & Widgetstyles.EnableNotifyMessage) != 0) { + OnNotifyMessage(m); + } + + switch((Msg)m.Msg) { + case Msg.WM_DESTROY: { + WmDestroy(ref m); + return; + } + + case Msg.WM_WINDOWPOSCHANGED: { + WmWindowPosChanged(ref m); + return; + } + + // Nice description of what should happen when handling WM_PAINT + // can be found here: http://pluralsight.com/wiki/default.aspx/Craig/FlickerFreeWidgetDrawing.html + // and here http://msdn.microsoft.com/msdnmag/issues/06/03/WindowsFormsPerformance/ + case Msg.WM_PAINT: { + WmPaint (ref m); + return; + } + + // The DefWndProc will never have to handle this, we always paint the background in managed code + // In theory this code would look at Widgetstyles.AllPaintingInWmPaint and and call OnPaintBackground + // here but it just makes things more complicated... + case Msg.WM_ERASEBKGND: { + WmEraseBackground (ref m); + return; + } + + case Msg.WM_LBUTTONUP: { + WmLButtonUp (ref m); + return; + } + + case Msg.WM_LBUTTONDOWN: { + WmLButtonDown (ref m); + return; + } + + case Msg.WM_LBUTTONDBLCLK: { + WmLButtonDblClick (ref m); + return; + } + + case Msg.WM_MBUTTONUP: { + WmMButtonUp (ref m); + return; + } + + case Msg.WM_MBUTTONDOWN: { + WmMButtonDown (ref m); + return; + } + + case Msg.WM_MBUTTONDBLCLK: { + WmMButtonDblClick (ref m); + return; + } + + case Msg.WM_RBUTTONUP: { + WmRButtonUp (ref m); + return; + } + + case Msg.WM_RBUTTONDOWN: { + WmRButtonDown (ref m); + return; + } + + case Msg.WM_RBUTTONDBLCLK: { + WmRButtonDblClick (ref m); + return; + } + + case Msg.WM_CONTEXTMENU: { + WmContextMenu (ref m); + return; + } + + case Msg.WM_MOUSEWHEEL: { + WmMouseWheel (ref m); + return; + } + + case Msg.WM_MOUSEMOVE: { + WmMouseMove (ref m); + return; + } + + case Msg.WM_SHOWWINDOW: { + WmShowWindow (ref m); + return; + } + + case Msg.WM_CREATE: { + WmCreate (ref m); + return; + } + + case Msg.WM_MOUSE_ENTER: { + WmMouseEnter (ref m); + return; + } + + case Msg.WM_MOUSELEAVE: { + WmMouseLeave (ref m); + return; + } + + case Msg.WM_MOUSEHOVER: { + WmMouseHover (ref m); + return; + } + + case Msg.WM_SYSKEYUP: { + WmSysKeyUp (ref m); + return; + } + + case Msg.WM_SYSKEYDOWN: + case Msg.WM_KEYDOWN: + case Msg.WM_KEYUP: + case Msg.WM_SYSCHAR: + case Msg.WM_CHAR: { + WmKeys (ref m); + return; + } + + case Msg.WM_HELP: { + WmHelp (ref m); + return; + } + + case Msg.WM_KILLFOCUS: { + WmKillFocus (ref m); + return; + } + + case Msg.WM_SETFOCUS: { + WmSetFocus (ref m); + return; + } + + case Msg.WM_SYSCOLORCHANGE: { + WmSysColorChange (ref m); + return; + } + + case Msg.WM_SETCURSOR: { + WmSetCursor (ref m); + return; + } + + case Msg.WM_CAPTURECHANGED: { + WmCaptureChanged (ref m); + return; + } + + case Msg.WM_CHANGEUISTATE: { + WmChangeUIState (ref m); + return; + } + + case Msg.WM_UPDATEUISTATE: { + WmUpdateUIState (ref m); + return; + } + + default: + DefWndProc(ref m); + return; + } + } + + #endregion // Public Instance Methods + + #region WM methods + + private void WmDestroy (ref Message m) { + OnHandleDestroyed(EventArgs.Empty); + #if DebugRecreate + IntPtr handle = window.Handle; + #endif + window.InvalidateHandle(); + + is_created = false; + if (is_recreating) { + #if DebugRecreate + Console.WriteLine ("Creating handle for {0:X}", handle.ToInt32()); + #endif + CreateHandle(); + #if DebugRecreate + Console.WriteLine (" + new handle = {0:X}", Handle.ToInt32()); + #endif + is_recreating = false; + } + + if (is_disposing) { + is_disposing = false; + is_visible = false; + } + } + + private void WmWindowPosChanged (ref Message m) { + if (Visible) { + Rectangle save_bounds = explicit_bounds; + UpdateBounds(); + explicit_bounds = save_bounds; + if (GetStyle(Widgetstyles.ResizeRedraw)) { + Invalidate(); + } + } + } + + + // Nice description of what should happen when handling WM_PAINT + // can be found here: http://pluralsight.com/wiki/default.aspx/Craig/FlickerFreeWidgetDrawing.html + // and here http://msdn.microsoft.com/msdnmag/issues/06/03/WindowsFormsPerformance/ + private void WmPaint (ref Message m) { + IntPtr handle = Handle; + + PaintEventArgs paint_event = XplatUI.PaintEventStart (ref m, handle, true); + + if (paint_event == null) + return; + + DoubleBuffer current_buffer = null; + if (UseDoubleBuffering) { + current_buffer = GetBackBuffer (); + // This optimization doesn't work when the area is invalidated + // during a paint operation because finishing the paint operation + // clears the invalidated region and then this thing keeps the new + // invalidate from working. To re-enable this, we would need a + // mechanism to allow for nested invalidates (see bug #328681) + //if (!current_buffer.InvalidRegion.IsVisible (paint_event.ClipRectangle)) { + // // Just blit the previous image + // current_buffer.Blit (paint_event); + // XplatUI.PaintEventEnd (ref m, handle, true); + // return; + //} + current_buffer.Start (paint_event); + } + // If using OptimizedDoubleBuffer, ensure the clip region gets set + if (GetStyle (Widgetstyles.OptimizedDoubleBuffer)) + paint_event.Graphics.SetClip (Rectangle.Intersect (paint_event.ClipRectangle, this.ClientRectangle)); + + if (!GetStyle(Widgetstyles.Opaque)) { + OnPaintBackground (paint_event); + } + + // Button-derived Widgets choose to ignore their Opaque style, give them a chance to draw their background anyways + OnPaintBackgroundInternal (paint_event); + + OnPaintInternal(paint_event); + if (!paint_event.Handled) { + OnPaint (paint_event); + } + + if (current_buffer != null) { + current_buffer.End (paint_event); + } + + + XplatUI.PaintEventEnd (ref m, handle, true); + } + + private void WmEraseBackground (ref Message m) { + // The DefWndProc will never have to handle this, we always paint the background in managed code + // In theory this code would look at Widgetstyles.AllPaintingInWmPaint and and call OnPaintBackground + // here but it just makes things more complicated... + m.Result = (IntPtr)1; + } + + private void WmLButtonUp (ref Message m) + { + // Menu handle. + if (XplatUI.IsEnabled (Handle) && active_tracker != null) { + ProcessActiveTracker (ref m); + return; + } + + MouseEventArgs me; + + me = new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()) | MouseButtons.Left, + mouse_clicks, + LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), + 0); + + HandleClick(mouse_clicks, me); + OnMouseUp (me); + + if (InternalCapture) { + InternalCapture = false; + } + + if (mouse_clicks > 1) { + mouse_clicks = 1; + } + } + + private void WmLButtonDown (ref Message m) + { + // Menu handle. + if (XplatUI.IsEnabled (Handle) && active_tracker != null) { + ProcessActiveTracker (ref m); + return; + } + + ValidationFailed = false; + if (CanSelect) { + Select (true, true); + } + if (!ValidationFailed) { + InternalCapture = true; + OnMouseDown (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()), + mouse_clicks, LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), + 0)); + } + } + + private void WmLButtonDblClick (ref Message m) { + InternalCapture = true; + mouse_clicks++; + OnMouseDown (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()), + mouse_clicks, LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), + 0)); + } + + private void WmMButtonUp (ref Message m) { + MouseEventArgs me; + + me = new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()) | MouseButtons.Middle, + mouse_clicks, + LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), + 0); + + HandleClick(mouse_clicks, me); + OnMouseUp (me); + if (InternalCapture) { + InternalCapture = false; + } + if (mouse_clicks > 1) { + mouse_clicks = 1; + } + } + + private void WmMButtonDown (ref Message m) { + InternalCapture = true; + OnMouseDown (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()), + mouse_clicks, LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), + 0)); + } + + private void WmMButtonDblClick (ref Message m) { + InternalCapture = true; + mouse_clicks++; + OnMouseDown (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()), + mouse_clicks, LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), + 0)); + } + + private void WmRButtonUp (ref Message m) + { + // Menu handle. + if (XplatUI.IsEnabled (Handle) && active_tracker != null) { + ProcessActiveTracker (ref m); + return; + } + + MouseEventArgs me; + Point pt; + + pt = new Point(LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ())); + pt = PointToScreen(pt); + + me = new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()) | MouseButtons.Right, + mouse_clicks, + LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), + 0); + + HandleClick(mouse_clicks, me); + + XplatUI.SendMessage(m.HWnd, Msg.WM_CONTEXTMENU, m.HWnd, (IntPtr)(pt.X + (pt.Y << 16))); + OnMouseUp (me); + + if (InternalCapture) { + InternalCapture = false; + } + + if (mouse_clicks > 1) { + mouse_clicks = 1; + } + } + + private void WmRButtonDown (ref Message m) + { + // Menu handle. + if (XplatUI.IsEnabled (Handle) && active_tracker != null) { + ProcessActiveTracker (ref m); + return; + } + + InternalCapture = true; + OnMouseDown (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()), + mouse_clicks, LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), + 0)); + } + + private void WmRButtonDblClick (ref Message m) { + InternalCapture = true; + mouse_clicks++; + OnMouseDown (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()), + mouse_clicks, LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), + 0)); + } + + private void WmContextMenu (ref Message m) { + // If there isn't a regular context menu, show the Strip version + if (context_menu_strip != null) { + Point pt; + + pt = new Point (LowOrder ((int)m.LParam.ToInt32 ()), HighOrder ((int)m.LParam.ToInt32 ())); + + if (pt.X == -1 || pt.Y == -1) { + pt.X = (this.Width / 2) + this.Left; + pt.Y = (this.Height /2) + this.Top; + pt = this.PointToScreen (pt); + } + + context_menu_strip.SetSourceWidget (this); + context_menu_strip.Show (this, PointToClient (pt)); + return; + } + DefWndProc(ref m); + } + + private void WmCreate (ref Message m) { + OnHandleCreated(EventArgs.Empty); + } + + private void WmMouseWheel (ref Message m) { + DefWndProc(ref m); + OnMouseWheel (new MouseEventArgs (FromParamToMouseButtons ((long) m.WParam), + mouse_clicks, LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), + HighOrder((long)m.WParam))); + } + + + private void WmMouseMove (ref Message m) { + if (XplatUI.IsEnabled (Handle) && active_tracker != null) { + MouseEventArgs args = new MouseEventArgs ( + FromParamToMouseButtons ((int)m.WParam.ToInt32 ()), + mouse_clicks, + Widget.MousePosition.X, + Widget.MousePosition.Y, + 0); + + active_tracker.OnMotion (args); + return; + } + + OnMouseMove (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()), + mouse_clicks, + LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()), + 0)); + } + + private void WmMouseEnter (ref Message m) { + if (is_entered) { + return; + } + is_entered = true; + OnMouseEnter(EventArgs.Empty); + } + + private void WmMouseLeave (ref Message m) { + is_entered=false; + OnMouseLeave(EventArgs.Empty); + } + + private void WmMouseHover (ref Message m) { + OnMouseHover(EventArgs.Empty); + } + + private void WmShowWindow (ref Message m) { + if (IsDisposed) + return; + + Form frm = this as Form; + if (m.WParam.ToInt32() != 0) { + if (m.LParam.ToInt32 () == 0) { + CreateWidget (); + + // Make sure all our children are properly parented to us + Widget [] Widgets = child_Widgets.GetAllWidgets (); + // bool parented = false; + for (int i=0; i + /// Summary description for CategoryGridEntry + /// + internal class CategoryGridEntry : GridEntry + { + private string label; + public CategoryGridEntry (PropertyGrid owner, string category, GridEntry parent) + : base (owner, parent) + { + label = category; + } + + public override GridItemType GridItemType { + get { return GridItemType.Category; } + } + + public override bool Expandable { + get { return GridItems.Count > 0; } + } + + public override string Label { + get { return label; } + } + + public override bool IsReadOnly { + get { return true; } + } + + public override bool IsEditable { + get { return false; } + } + + public override bool IsResetable { + get { return false; } + } + } +} diff --git a/source/ShiftUI/Widgets/CheckBox.cs b/source/ShiftUI/Widgets/CheckBox.cs new file mode 100644 index 0000000..6ed09f5 --- /dev/null +++ b/source/ShiftUI/Widgets/CheckBox.cs @@ -0,0 +1,404 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Dennis Hayes dennish@raytek.com +// Peter Bartok pbartok@novell.com +// + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace ShiftUI { + [DefaultProperty("Checked")] + [DefaultEvent("CheckedChanged")] + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [DefaultBindingProperty ("CheckState")] + [ToolboxItem ("ShiftUI.Design.AutoSizeToolboxItem," + Consts.AssemblySystem_Design)] + [ToolboxWidget] + public class CheckBox : ButtonBase { + #region Local Variables + internal Appearance appearance; + internal bool auto_check; + internal ContentAlignment check_alignment; + internal CheckState check_state; + internal bool three_state; + #endregion // Local Variables + + #region CheckBoxAccessibleObject Subclass + [ComVisible(true)] + public class CheckBoxAccessibleObject : ButtonBaseAccessibleObject { + #region CheckBoxAccessibleObject Local Variables + private new CheckBox owner; + #endregion // CheckBoxAccessibleObject Local Variables + + #region CheckBoxAccessibleObject Constructors + public CheckBoxAccessibleObject(Widget owner) : base(owner) { + this.owner = (CheckBox)owner; + } + #endregion // CheckBoxAccessibleObject Constructors + + #region CheckBoxAccessibleObject Properties + public override string DefaultAction { + get { + return "Select"; + } + } + + public override AccessibleRole Role { + get { + return AccessibleRole.CheckButton; + } + } + + public override AccessibleStates State { + get { + AccessibleStates retval; + + retval = AccessibleStates.Default; + + if (owner.check_state == CheckState.Checked) { + retval |= AccessibleStates.Checked; + } + + if (owner.Focused) { + retval |= AccessibleStates.Focused; + } + + if (owner.CanFocus) { + retval |= AccessibleStates.Focusable; + } + + return retval; + } + } + #endregion // CheckBoxAccessibleObject Properties + + #region CheckBoxAccessibleObject Methods + public override void DoDefaultAction () + { + owner.Checked = !owner.Checked; + } + #endregion // CheckBoxAccessibleObject Methods + } + #endregion // CheckBoxAccessibleObject Sub-class + + #region Public Constructors + public CheckBox() { + appearance = Appearance.Normal; + auto_check = true; + check_alignment = ContentAlignment.MiddleLeft; + TextAlign = ContentAlignment.MiddleLeft; + SetStyle(Widgetstyles.StandardDoubleClick, false); + SetAutoSizeMode (AutoSizeMode.GrowAndShrink); + } + #endregion // Public Constructors + + #region Internal Methods + internal override void Draw (PaintEventArgs pe) { + // FIXME: This should be called every time something that can affect it + // is changed, not every paint. Can only change so many things at a time. + + // Figure out where our text and image should go + Rectangle glyph_rectangle; + Rectangle text_rectangle; + Rectangle image_rectangle; + + ThemeEngine.Current.CalculateCheckBoxTextAndImageLayout (this, Point.Empty, out glyph_rectangle, out text_rectangle, out image_rectangle); + + // Draw our button + if (FlatStyle != FlatStyle.System) + ThemeEngine.Current.DrawCheckBox (pe.Graphics, this, glyph_rectangle, text_rectangle, image_rectangle, pe.ClipRectangle); + else + ThemeEngine.Current.DrawCheckBox (pe.Graphics, this.ClientRectangle, this); + } + + internal override Size GetPreferredSizeCore (Size proposedSize) + { + if (this.AutoSize) + return ThemeEngine.Current.CalculateCheckBoxAutoSize (this); + + return base.GetPreferredSizeCore (proposedSize); + } + + internal override void HaveDoubleClick() { + if (DoubleClick != null) DoubleClick(this, EventArgs.Empty); + } + #endregion // Internal Methods + + #region Public Instance Properties + [DefaultValue(Appearance.Normal)] + [Localizable(true)] + public Appearance Appearance { + get { + return appearance; + } + + set { + if (value != appearance) { + appearance = value; + OnAppearanceChanged (EventArgs.Empty); + + if (Parent != null) + Parent.PerformLayout (this, "Appearance"); + Invalidate(); + } + } + } + + [DefaultValue(true)] + public bool AutoCheck { + get { + return auto_check; + } + + set { + auto_check = value; + } + } + + [Bindable(true)] + [Localizable(true)] + [DefaultValue(ContentAlignment.MiddleLeft)] + public ContentAlignment CheckAlign { + get { + return check_alignment; + } + + set { + if (value != check_alignment) { + check_alignment = value; + if (Parent != null) + Parent.PerformLayout (this, "CheckAlign"); + Invalidate(); + } + } + } + + [Bindable(true)] + [RefreshProperties(RefreshProperties.All)] + [DefaultValue(false)] + [SettingsBindable (true)] + public bool Checked { + get { + if (check_state != CheckState.Unchecked) { + return true; + } + return false; + } + + set { + if (value && (check_state != CheckState.Checked)) { + check_state = CheckState.Checked; + Invalidate(); + OnCheckedChanged(EventArgs.Empty); + } else if (!value && (check_state != CheckState.Unchecked)) { + check_state = CheckState.Unchecked; + Invalidate(); + OnCheckedChanged(EventArgs.Empty); + } + } + } + + [DefaultValue(CheckState.Unchecked)] + [RefreshProperties(RefreshProperties.All)] + [Bindable(true)] + public CheckState CheckState { + get { + return check_state; + } + + set { + if (value != check_state) { + bool was_checked = (check_state != CheckState.Unchecked); + + check_state = value; + + if (was_checked != (check_state != CheckState.Unchecked)) { + OnCheckedChanged(EventArgs.Empty); + } + + OnCheckStateChanged(EventArgs.Empty); + Invalidate(); + } + } + } + + [DefaultValue(ContentAlignment.MiddleLeft)] + [Localizable(true)] + public override ContentAlignment TextAlign { + get { return base.TextAlign; } + set { base.TextAlign = value; } + } + + + [DefaultValue(false)] + public bool ThreeState { + get { + return three_state; + } + + set { + three_state = value; + } + } + #endregion // Public Instance Properties + + #region Protected Instance Properties + protected override CreateParams CreateParams { + get { + return base.CreateParams; + } + } + + protected override Size DefaultSize { + get { + return new Size(104, 24); + } + } + #endregion // Protected Instance Properties + + #region Public Instance Methods + public override string ToString() { + return base.ToString() + ", CheckState: " + (int)check_state; + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + protected override AccessibleObject CreateAccessibilityInstance() { + AccessibleObject ao; + + ao = base.CreateAccessibilityInstance (); + ao.role = AccessibleRole.CheckButton; + + return ao; + } + + protected virtual void OnAppearanceChanged(EventArgs e) { + EventHandler eh = (EventHandler)(Events [AppearanceChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnCheckedChanged(EventArgs e) { + EventHandler eh = (EventHandler)(Events [CheckedChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnCheckStateChanged(EventArgs e) { + EventHandler eh = (EventHandler)(Events [CheckStateChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnClick(EventArgs e) { + if (auto_check) { + switch(check_state) { + case CheckState.Unchecked: { + if (three_state) { + CheckState = CheckState.Indeterminate; + } else { + CheckState = CheckState.Checked; + } + break; + } + + case CheckState.Indeterminate: { + CheckState = CheckState.Checked; + break; + } + + case CheckState.Checked: { + CheckState = CheckState.Unchecked; + break; + } + } + } + + base.OnClick (e); + } + + protected override void OnHandleCreated(EventArgs e) { + base.OnHandleCreated (e); + } + + protected override void OnKeyDown (KeyEventArgs e) + { + base.OnKeyDown (e); + } + + protected override void OnMouseUp(MouseEventArgs mevent) { + base.OnMouseUp (mevent); + } + + protected override bool ProcessMnemonic(char charCode) { + if (IsMnemonic(charCode, Text) == true) { + Select(); + OnClick(EventArgs.Empty); + return true; + } + + return base.ProcessMnemonic(charCode); + } + #endregion // Protected Instance Methods + + #region Events + static object AppearanceChangedEvent = new object (); + static object CheckedChangedEvent = new object (); + static object CheckStateChangedEvent = new object (); + + public event EventHandler AppearanceChanged { + add { Events.AddHandler (AppearanceChangedEvent, value); } + remove { Events.RemoveHandler (AppearanceChangedEvent, value); } + } + + public event EventHandler CheckedChanged { + add { Events.AddHandler (CheckedChangedEvent, value); } + remove { Events.RemoveHandler (CheckedChangedEvent, value); } + } + + public event EventHandler CheckStateChanged { + add { Events.AddHandler (CheckStateChangedEvent, value); } + remove { Events.RemoveHandler (CheckStateChangedEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event MouseEventHandler MouseDoubleClick { + add { base.MouseDoubleClick += value; } + remove { base.MouseDoubleClick -= value; } + } + #endregion // Events + + #region Events + // XXX have a look at this and determine if it + // manipulates base.DoubleClick, and see if + // HaveDoubleClick can just call OnDoubleClick. + [Browsable(false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler DoubleClick; + #endregion // Events + } +} diff --git a/source/ShiftUI/Widgets/CheckedListBox.cs b/source/ShiftUI/Widgets/CheckedListBox.cs new file mode 100644 index 0000000..5bcdf5d --- /dev/null +++ b/source/ShiftUI/Widgets/CheckedListBox.cs @@ -0,0 +1,655 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// Mike Kestner +// +// + +using System; +using System.Drawing; +using System.Collections; +using System.ComponentModel; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + [LookupBindingPropertiesAttribute ()] + [ToolboxWidget] + public class CheckedListBox : ListBox + { + private CheckedIndexCollection checked_indices; + private CheckedItemCollection checked_items; + private Hashtable check_states = new Hashtable (); + private bool check_onclick = false; + private bool three_dcheckboxes = false; + + public CheckedListBox () + { + checked_indices = new CheckedIndexCollection (this); + checked_items = new CheckedItemCollection (this); + SetStyle (Widgetstyles.ResizeRedraw, true); + } + + #region events + static object ItemCheckEvent = new object (); + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler Click { + add { base.Click += value; } + remove { base.Click -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler DataSourceChanged { + add { base.DataSourceChanged += value; } + remove { base.DataSourceChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler DisplayMemberChanged { + add { base.DisplayMemberChanged += value; } + remove { base.DisplayMemberChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event DrawItemEventHandler DrawItem { + add { base.DrawItem += value; } + remove { base.DrawItem -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event MeasureItemEventHandler MeasureItem { + add { base.MeasureItem += value; } + remove { base.MeasureItem -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler ValueMemberChanged { + add { base.ValueMemberChanged += value; } + remove { base.ValueMemberChanged -= value; } + } + + public event ItemCheckEventHandler ItemCheck { + add { Events.AddHandler (ItemCheckEvent, value); } + remove { Events.RemoveHandler (ItemCheckEvent, value); } + } + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event MouseEventHandler MouseClick { + add { base.MouseClick += value; } + remove { base.MouseClick -= value; } + } + #endregion Events + + #region Public Properties + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public CheckedListBox.CheckedIndexCollection CheckedIndices { + get {return checked_indices; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public CheckedListBox.CheckedItemCollection CheckedItems { + get {return checked_items; } + } + + [DefaultValue (false)] + public bool CheckOnClick { + get { return check_onclick; } + set { check_onclick = value; } + } + + protected override CreateParams CreateParams { + get { return base.CreateParams;} + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public new object DataSource { + get { return base.DataSource; } + // FIXME: docs say you can't use a DataSource with this subclass + set { base.DataSource = value; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public new string DisplayMember { + get { return base.DisplayMember; } + set { base.DisplayMember = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override DrawMode DrawMode { + get { return DrawMode.Normal; } + set { /* Not an exception, but has no effect. */ } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override int ItemHeight { + get { return base.ItemHeight; } + set { /* Not an exception, but has no effect. */ } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + [Localizable (true)] + //[Editor ("ShiftUI.Design.ListWidgetstringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + public new CheckedListBox.ObjectCollection Items { + get { return (CheckedListBox.ObjectCollection) base.Items; } + } + + public override SelectionMode SelectionMode { + get { return base.SelectionMode; } + set { + if (!Enum.IsDefined (typeof (SelectionMode), value)) + throw new InvalidEnumArgumentException ("value", (int) value, typeof (SelectionMode)); + + if (value == SelectionMode.MultiSimple || value == SelectionMode.MultiExtended) + throw new ArgumentException ("Multi selection not supported on CheckedListBox"); + + base.SelectionMode = value; + } + } + + [DefaultValue (false)] + public bool ThreeDCheckBoxes { + get { return three_dcheckboxes; } + set { + if (three_dcheckboxes == value) + return; + + three_dcheckboxes = value; + Refresh (); + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new string ValueMember { + get { return base.ValueMember; } + set { base.ValueMember = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public new Padding Padding { + get { return base.Padding; } + set { base.Padding = value; } + } + #endregion Public Properties + + #region Public Methods + + protected override AccessibleObject CreateAccessibilityInstance () + { + return base.CreateAccessibilityInstance (); + } + + protected override ListBox.ObjectCollection CreateItemCollection () + { + return new ObjectCollection (this); + } + + public bool GetItemChecked (int index) + { + return check_states.Contains (Items [index]); + } + + public CheckState GetItemCheckState (int index) + { + if (index < 0 || index >= Items.Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + object o = Items [index]; + if (check_states.Contains (o)) + return (CheckState) check_states [o]; + else + return CheckState.Unchecked; + } + + protected override void OnBackColorChanged (EventArgs e) + { + base.OnBackColorChanged (e); + } + + protected override void OnClick (EventArgs e) + { + base.OnClick (e); + } + + protected override void OnDrawItem (DrawItemEventArgs e) + { + if (check_states.Contains (Items [e.Index])) { + DrawItemState state = e.State | DrawItemState.Checked; + if (((CheckState) check_states [Items [e.Index]]) == CheckState.Indeterminate) + state |= DrawItemState.Inactive; + e = new DrawItemEventArgs (e.Graphics, e.Font, e.Bounds, e.Index, state, e.ForeColor, e.BackColor); + } + ThemeEngine.Current.DrawCheckedListBoxItem (this, e); + } + + protected override void OnFontChanged (EventArgs e) + { + base.OnFontChanged (e); + } + + protected override void OnHandleCreated (EventArgs e) + { + base.OnHandleCreated (e); + } + + protected virtual void OnItemCheck (ItemCheckEventArgs ice) + { + ItemCheckEventHandler eh = (ItemCheckEventHandler)(Events [ItemCheckEvent]); + if (eh != null) + eh (this, ice); + } + + protected override void OnKeyPress (KeyPressEventArgs e) + { + base.OnKeyPress (e); + + if (e.KeyChar == ' ' && FocusedItem != -1) + SetItemChecked (FocusedItem, !GetItemChecked (FocusedItem)); + } + + protected override void OnMeasureItem (MeasureItemEventArgs e) + { + base.OnMeasureItem (e); + } + + protected override void OnSelectedIndexChanged (EventArgs e) + { + base.OnSelectedIndexChanged (e); + } + + protected override void RefreshItems () + { + base.RefreshItems (); + } + + public void SetItemChecked (int index, bool value) + { + SetItemCheckState (index, value ? CheckState.Checked : CheckState.Unchecked); + } + + public void SetItemCheckState (int index, CheckState value) + { + if (index < 0 || index >= Items.Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + if (!Enum.IsDefined (typeof (CheckState), value)) + throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for CheckState", value)); + + CheckState old_value = GetItemCheckState (index); + + if (old_value == value) + return; + + ItemCheckEventArgs icea = new ItemCheckEventArgs (index, value, old_value); + OnItemCheck (icea); + + switch (icea.NewValue) { + case CheckState.Checked: + case CheckState.Indeterminate: + check_states[Items[index]] = icea.NewValue; + break; + case CheckState.Unchecked: + check_states.Remove (Items[index]); + break; + default: + break; + } + + UpdateCollections (); + + InvalidateCheckbox (index); + } + + protected override void WmReflectCommand (ref Message m) + { + base.WmReflectCommand (ref m); + } + + protected override void WndProc (ref Message m) + { + base.WndProc (ref m); + } + + #endregion Public Methods + + #region Private Methods + + int last_clicked_index = -1; + + internal override void OnItemClick (int index) + { + if ((CheckOnClick || last_clicked_index == index) && index > -1) { + if (GetItemChecked (index)) + SetItemCheckState (index, CheckState.Unchecked); + else + SetItemCheckState (index, CheckState.Checked); + } + + last_clicked_index = index; + base.OnItemClick (index); + } + + internal override void CollectionChanged () + { + base.CollectionChanged (); + UpdateCollections (); + } + + private void InvalidateCheckbox (int index) + { + Rectangle area = GetItemDisplayRectangle (index, TopIndex); + area.X += 2; + area.Y += (area.Height - 11) / 2; + area.Width = 11; + area.Height = 11; + Invalidate (area); + } + + private void UpdateCollections () + { + CheckedItems.Refresh (); + CheckedIndices.Refresh (); + } + + #endregion Private Methods + + public new class ObjectCollection : ListBox.ObjectCollection + { + private CheckedListBox owner; + + public ObjectCollection (CheckedListBox owner) : base (owner) + { + this.owner = owner; + } + + public int Add (object item, bool isChecked) + { + return Add (item, isChecked ? CheckState.Checked : CheckState.Unchecked); + } + + public int Add (object item, CheckState check) + { + int idx = Add (item); + + ItemCheckEventArgs icea = new ItemCheckEventArgs (idx, check, CheckState.Unchecked); + + if (check == CheckState.Checked) + owner.OnItemCheck (icea); + + if (icea.NewValue != CheckState.Unchecked) + owner.check_states[item] = icea.NewValue; + + owner.UpdateCollections (); + return idx; + } + } + + public class CheckedIndexCollection : IList, ICollection, IEnumerable + { + private CheckedListBox owner; + private ArrayList indices = new ArrayList (); + + internal CheckedIndexCollection (CheckedListBox owner) + { + this.owner = owner; + } + + #region Public Properties + public int Count { + get { return indices.Count; } + } + + public bool IsReadOnly { + get { return true;} + } + + bool ICollection.IsSynchronized { + get { return false; } + } + + bool IList.IsFixedSize{ + get { return true; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int this[int index] { + get { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + return (int) indices[index]; + } + } + #endregion Public Properties + + public bool Contains (int index) + { + return indices.Contains (index); + } + + + public void CopyTo (Array dest, int index) + { + indices.CopyTo (dest, index); + } + + public IEnumerator GetEnumerator () + { + return indices.GetEnumerator (); + } + + int IList.Add (object value) + { + throw new NotSupportedException (); + } + + void IList.Clear () + { + throw new NotSupportedException (); + } + + bool IList.Contains (object index) + { + return Contains ((int)index); + } + + int IList.IndexOf (object index) + { + return IndexOf ((int) index); + } + + void IList.Insert (int index, object value) + { + throw new NotSupportedException (); + } + + void IList.Remove (object value) + { + throw new NotSupportedException (); + } + + void IList.RemoveAt (int index) + { + throw new NotSupportedException (); + } + + object IList.this[int index]{ + get {return indices[index]; } + set {throw new NotImplementedException (); } + } + + public int IndexOf (int index) + { + return indices.IndexOf (index); + } + + #region Private Methods + internal void Refresh () + { + indices.Clear (); + for (int i = 0; i < owner.Items.Count; i++) + if (owner.check_states.Contains (owner.Items [i])) + indices.Add (i); + } + #endregion Private Methods + + } + + public class CheckedItemCollection : IList, ICollection, IEnumerable + { + private CheckedListBox owner; + private ArrayList list = new ArrayList (); + + internal CheckedItemCollection (CheckedListBox owner) + { + this.owner = owner; + } + + #region Public Properties + public int Count { + get { return list.Count; } + } + + public bool IsReadOnly { + get { return true; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public object this [int index] { + get { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + return list[index]; + } + set {throw new NotSupportedException ();} + } + + bool ICollection.IsSynchronized { + get { return true; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + bool IList.IsFixedSize { + get { return true; } + } + + #endregion Public Properties + + #region Public Methods + public bool Contains (object item) + { + return list.Contains (item); + } + + public void CopyTo (Array dest, int index) + { + list.CopyTo (dest, index); + } + + int IList.Add (object value) + { + throw new NotSupportedException (); + } + + void IList.Clear () + { + throw new NotSupportedException (); + } + + void IList.Insert (int index, object value) + { + throw new NotSupportedException (); + } + + void IList.Remove (object value) + { + throw new NotSupportedException (); + } + + void IList.RemoveAt (int index) + { + throw new NotSupportedException (); + } + + public int IndexOf (object item) + { + return list.IndexOf (item); + } + + public IEnumerator GetEnumerator () + { + return list.GetEnumerator (); + } + + #endregion Public Methods + + #region Private Methods + internal void Refresh () + { + list.Clear (); + for (int i = 0; i < owner.Items.Count; i++) + if (owner.check_states.Contains (owner.Items [i])) + list.Add (owner.Items[i]); + } + #endregion Private Methods + } + [DefaultValue (false)] + public bool UseCompatibleTextRendering { + get { return use_compatible_text_rendering; } + set { use_compatible_text_rendering = value; } + } + } +} + diff --git a/source/ShiftUI/Widgets/CollectionEditor.cs b/source/ShiftUI/Widgets/CollectionEditor.cs new file mode 100644 index 0000000..07bbc51 --- /dev/null +++ b/source/ShiftUI/Widgets/CollectionEditor.cs @@ -0,0 +1,738 @@ +// +// System.ComponentModel.Design.CollectionEditor +// +// Authors: +// Martin Willemoes Hansen (mwh@sysrq.dk) +// Andreas Nahr (ClassDevelopment@A-SoftTech.com) +// Ivan N. Zlatev (contact@i-nz.net) +// +// (C) 2003 Martin Willemoes Hansen +// (C) 2007 Andreas Nahr +// (C) 2007 Ivan N. Zlatev +// (C) 2008 Novell, Inc +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + + +using System; +using System.Reflection; +using System.Collections; +using System.ComponentModel; +using System.Drawing.Design; +using ShiftUI; +using ShiftUI.Design; + +namespace System.ComponentModel.Design +{ + public class CollectionEditor : UITypeEditor + { + protected abstract class CollectionForm : Form + { + private CollectionEditor editor; + private object editValue; + + public CollectionForm (CollectionEditor editor) + { + this.editor = editor; + } + + protected Type CollectionItemType + { + get { return editor.CollectionItemType; } + } + + protected Type CollectionType + { + get { return editor.CollectionType; } + } + + protected ITypeDescriptorContext Context + { + get { return editor.Context; } + } + + public object EditValue + { + get { return editValue; } + set + { + editValue = value; + OnEditValueChanged (); + } + } + + protected object[] Items + { + get { return editor.GetItems (editValue); } + set { + if (editValue == null) { + object newEmptyCollection = null; + try { + if (typeof (Array).IsAssignableFrom (CollectionType)) + newEmptyCollection = Array.CreateInstance (CollectionItemType, 0); + else + newEmptyCollection = Activator.CreateInstance (CollectionType); + } catch {} + + object val = editor.SetItems (newEmptyCollection, value); + if (val != newEmptyCollection) + EditValue = val; + } else { + object val = editor.SetItems (editValue, value); + if (val != editValue) + EditValue = val; + } + } + } + + protected Type[] NewItemTypes + { + get { return editor.NewItemTypes; } + } + + protected bool CanRemoveInstance (object value) + { + return editor.CanRemoveInstance (value); + } + + protected virtual bool CanSelectMultipleInstances () + { + return editor.CanSelectMultipleInstances (); + } + + protected object CreateInstance (Type itemType) + { + return editor.CreateInstance (itemType); + } + + protected void DestroyInstance (object instance) + { + editor.DestroyInstance (instance); + } + + protected virtual void DisplayError (Exception e) + { + MessageBox.Show (e.Message, "Error"); + } + + protected override object GetService (Type serviceType) + { + return editor.GetService (serviceType); + } + + protected abstract void OnEditValueChanged (); + + protected internal virtual DialogResult ShowEditorDialog (IWindowsFormsEditorService edSvc) + { + return edSvc.ShowDialog (this); + } + } + + private class ConcreteCollectionForm : CollectionForm + { + internal class ObjectContainerConverter : TypeConverter + { + private class ObjectContainerPropertyDescriptor : TypeConverter.SimplePropertyDescriptor + { + private AttributeCollection attributes; + + public ObjectContainerPropertyDescriptor (Type componentType, Type propertyType) + : base (componentType, "Value", propertyType) + { + CategoryAttribute cat = new CategoryAttribute (propertyType.Name); + attributes = new AttributeCollection (new Attribute[] { cat }); + } + + public override object GetValue (object component) + { + ObjectContainer container = (ObjectContainer)component; + return container.Object; + } + + public override void SetValue (object component, object value) + { + ObjectContainer container = (ObjectContainer)component; + container.Object = value; + } + + public override AttributeCollection Attributes + { + get { return attributes; } + } + } + + public override PropertyDescriptorCollection GetProperties (ITypeDescriptorContext context, object value, Attribute[] attributes) + { + ObjectContainer container = (ObjectContainer)value; + ObjectContainerPropertyDescriptor desc = new ObjectContainerPropertyDescriptor (value.GetType (), container.editor.CollectionItemType); + PropertyDescriptor[] properties = new PropertyDescriptor[] { desc }; + PropertyDescriptorCollection pc = new PropertyDescriptorCollection (properties); + return pc; + } + + public override bool GetPropertiesSupported (ITypeDescriptorContext context) + { + return true; + } + } + + [TypeConverter (typeof (ObjectContainerConverter))] + private class ObjectContainer + { + internal object Object; + internal CollectionEditor editor; + + public ObjectContainer (object obj, CollectionEditor editor) + { + this.Object = obj; + this.editor = editor; + } + + internal string Name { + get { return editor.GetDisplayText (Object); } + } + + public override string ToString () + { + return Name; + } + } + + private class UpdateableListbox : ListBox + { + public void DoRefreshItem (int index) + { + base.RefreshItem (index); + } + } + + private CollectionEditor editor; + + private ShiftUI.Label labelMember; + private ShiftUI.Label labelProperty; + private UpdateableListbox itemsList; + private ShiftUI.PropertyGrid itemDisplay; + private ShiftUI.Button doClose; + private ShiftUI.Button moveUp; + private ShiftUI.Button moveDown; + private ShiftUI.Button doAdd; + private ShiftUI.Button doRemove; + private ShiftUI.Button doCancel; + private ShiftUI.ComboBox addType; + + public ConcreteCollectionForm (CollectionEditor editor) + : base (editor) + { + this.editor = editor; + + this.labelMember = new ShiftUI.Label (); + this.labelProperty = new ShiftUI.Label (); + this.itemsList = new UpdateableListbox (); + this.itemDisplay = new ShiftUI.PropertyGrid (); + this.doClose = new ShiftUI.Button (); + this.moveUp = new ShiftUI.Button (); + this.moveDown = new ShiftUI.Button (); + this.doAdd = new ShiftUI.Button (); + this.doRemove = new ShiftUI.Button (); + this.doCancel = new ShiftUI.Button (); + this.addType = new ShiftUI.ComboBox (); + this.SuspendLayout (); + // + // labelMember + // + this.labelMember.Location = new System.Drawing.Point (12, 9); + this.labelMember.Size = new System.Drawing.Size (55, 13); + this.labelMember.Text = "Members:"; + // + // labelProperty + // + this.labelProperty.Anchor = ((ShiftUI.AnchorStyles)(((ShiftUI.AnchorStyles.Top | ShiftUI.AnchorStyles.Left) + | ShiftUI.AnchorStyles.Right))); + this.labelProperty.Location = new System.Drawing.Point (172, 9); + this.labelProperty.Size = new System.Drawing.Size (347, 13); + this.labelProperty.Text = "Properties:"; + // + // itemsList + // + this.itemsList.Anchor = ((ShiftUI.AnchorStyles)(((ShiftUI.AnchorStyles.Top | ShiftUI.AnchorStyles.Bottom) + | ShiftUI.AnchorStyles.Left))); + this.itemsList.HorizontalScrollbar = true; + this.itemsList.Location = new System.Drawing.Point (12, 25); + this.itemsList.SelectionMode = ShiftUI.SelectionMode.MultiExtended; + this.itemsList.Size = new System.Drawing.Size (120, 290); + this.itemsList.TabIndex = 0; + this.itemsList.SelectedIndexChanged += new System.EventHandler (this.itemsList_SelectedIndexChanged); + // + // itemDisplay + // + this.itemDisplay.Anchor = ((ShiftUI.AnchorStyles)((((ShiftUI.AnchorStyles.Top | ShiftUI.AnchorStyles.Bottom) + | ShiftUI.AnchorStyles.Left) + | ShiftUI.AnchorStyles.Right))); + this.itemDisplay.HelpVisible = false; + this.itemDisplay.Location = new System.Drawing.Point (175, 25); + this.itemDisplay.Size = new System.Drawing.Size (344, 314); + this.itemDisplay.TabIndex = 6; + this.itemDisplay.PropertyValueChanged += new ShiftUI.PropertyValueChangedEventHandler (this.itemDisplay_PropertyValueChanged); + // + // doClose + // + this.doClose.Anchor = ((ShiftUI.AnchorStyles)((ShiftUI.AnchorStyles.Bottom | ShiftUI.AnchorStyles.Right))); + this.doClose.Location = new System.Drawing.Point (341, 345); + this.doClose.Size = new System.Drawing.Size (86, 26); + this.doClose.TabIndex = 7; + this.doClose.Text = "OK"; + this.doClose.Click += new System.EventHandler (this.doClose_Click); + // + // moveUp + // + this.moveUp.Location = new System.Drawing.Point (138, 25); + this.moveUp.Size = new System.Drawing.Size (31, 28); + this.moveUp.TabIndex = 4; + this.moveUp.Enabled = false; + this.moveUp.Text = "Up"; + this.moveUp.Click += new System.EventHandler (this.moveUp_Click); + // + // moveDown + // + this.moveDown.Location = new System.Drawing.Point (138, 59); + this.moveDown.Size = new System.Drawing.Size (31, 28); + this.moveDown.TabIndex = 5; + this.moveDown.Enabled = false; + this.moveDown.Text = "Dn"; + this.moveDown.Click += new System.EventHandler (this.moveDown_Click); + // + // doAdd + // + this.doAdd.Anchor = ((ShiftUI.AnchorStyles)((ShiftUI.AnchorStyles.Bottom | ShiftUI.AnchorStyles.Left))); + this.doAdd.Location = new System.Drawing.Point (12, 346); + this.doAdd.Size = new System.Drawing.Size (59, 25); + this.doAdd.TabIndex = 1; + this.doAdd.Text = "Add"; + this.doAdd.Click += new System.EventHandler (this.doAdd_Click); + // + // doRemove + // + this.doRemove.Anchor = ((ShiftUI.AnchorStyles)((ShiftUI.AnchorStyles.Bottom | ShiftUI.AnchorStyles.Left))); + this.doRemove.Location = new System.Drawing.Point (77, 346); + this.doRemove.Size = new System.Drawing.Size (55, 25); + this.doRemove.TabIndex = 2; + this.doRemove.Text = "Remove"; + this.doRemove.Click += new System.EventHandler (this.doRemove_Click); + // + // doCancel + // + this.doCancel.Anchor = ((ShiftUI.AnchorStyles)((ShiftUI.AnchorStyles.Bottom | ShiftUI.AnchorStyles.Right))); + this.doCancel.DialogResult = ShiftUI.DialogResult.Cancel; + this.doCancel.Location = new System.Drawing.Point (433, 345); + this.doCancel.Size = new System.Drawing.Size (86, 26); + this.doCancel.TabIndex = 8; + this.doCancel.Text = "Cancel"; + this.doCancel.Click += new System.EventHandler (this.doCancel_Click); + // + // addType + // + this.addType.Anchor = ((ShiftUI.AnchorStyles)((ShiftUI.AnchorStyles.Bottom | ShiftUI.AnchorStyles.Left))); + this.addType.DropDownStyle = ShiftUI.ComboBoxStyle.DropDownList; + this.addType.Location = new System.Drawing.Point (12, 319); + this.addType.Size = new System.Drawing.Size (120, 21); + this.addType.TabIndex = 3; + // + // DesignerForm + // + this.AcceptButton = this.doClose; + this.CancelButton = this.doCancel; + this.ClientSize = new System.Drawing.Size (531, 381); + this.WidgetBox = false; + this.Widgets.Add (this.addType); + this.Widgets.Add (this.doCancel); + this.Widgets.Add (this.doRemove); + this.Widgets.Add (this.doAdd); + this.Widgets.Add (this.moveDown); + this.Widgets.Add (this.moveUp); + this.Widgets.Add (this.doClose); + this.Widgets.Add (this.itemDisplay); + this.Widgets.Add (this.itemsList); + this.Widgets.Add (this.labelProperty); + this.Widgets.Add (this.labelMember); + this.HelpButton = true; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.MinimumSize = new System.Drawing.Size (400, 300); + this.ShowInTaskbar = false; + this.StartPosition = ShiftUI.FormStartPosition.CenterScreen; + this.ResumeLayout (false); + + if (editor.CollectionType.IsGenericType) + this.Text = editor.CollectionItemType.Name + " Collection Editor"; + else + this.Text = editor.CollectionType.Name + " Collection Editor"; + foreach (Type type in editor.NewItemTypes) + addType.Items.Add (type.Name); + if (addType.Items.Count > 0) + addType.SelectedIndex = 0; + } + + private void UpdateItems () + { + object[] items = editor.GetItems (EditValue); + if (items != null) { + itemsList.BeginUpdate (); + itemsList.Items.Clear (); + foreach (object o in items) + this.itemsList.Items.Add (new ObjectContainer (o, editor)); + if (itemsList.Items.Count > 0) + itemsList.SelectedIndex = 0; + itemsList.EndUpdate (); + } + } + + private void doClose_Click (object sender, EventArgs e) + { + SetEditValue (); + this.Close (); + } + + private void SetEditValue () + { + object[] items = new object[itemsList.Items.Count]; + for (int i = 0; i < itemsList.Items.Count; i++) + items[i] = ((ObjectContainer)itemsList.Items[i]).Object; + this.Items = items; + } + + private void doCancel_Click (object sender, EventArgs e) + { + editor.CancelChanges (); + this.Close (); + } + + private void itemsList_SelectedIndexChanged (object sender, EventArgs e) + { + if (itemsList.SelectedIndex == -1) { + itemDisplay.SelectedObject = null; + return; + } + + if (itemsList.SelectedIndex <= 0 || itemsList.SelectedItems.Count > 1) + moveUp.Enabled = false; + else + moveUp.Enabled = true; + if (itemsList.SelectedIndex > itemsList.Items.Count - 2 || itemsList.SelectedItems.Count > 1) + moveDown.Enabled = false; + else + moveDown.Enabled = true; + + if (itemsList.SelectedItems.Count == 1) + { + ObjectContainer o = (ObjectContainer)itemsList.SelectedItem; + if (Type.GetTypeCode (o.Object.GetType ()) != TypeCode.Object) + itemDisplay.SelectedObject = o; + else + itemDisplay.SelectedObject = o.Object; + } + else + { + object[] items = new object[itemsList.SelectedItems.Count]; + for (int i = 0; i < itemsList.SelectedItems.Count; i++) + { + ObjectContainer o = (ObjectContainer)itemsList.SelectedItem; + if (Type.GetTypeCode (o.Object.GetType ()) != TypeCode.Object) + items[i] = ((ObjectContainer)itemsList.SelectedItems[i]); + else + items[i] = ((ObjectContainer)itemsList.SelectedItems[i]).Object; + } + itemDisplay.SelectedObjects = items; + } + labelProperty.Text = ((ObjectContainer)itemsList.SelectedItem).Name + " properties:"; + } + + private void itemDisplay_PropertyValueChanged (object sender, EventArgs e) + { + int[] selected = new int[itemsList.SelectedItems.Count]; + for (int i = 0; i < itemsList.SelectedItems.Count; i++) + selected[i] = itemsList.Items.IndexOf (itemsList.SelectedItems[i]); + + // The list might be repopulated if a new instance of the collection edited + // is created during the update. This happen for example for Arrays. + SetEditValue (); + + // Restore current selection in case the list gets repopulated. + // Refresh the item after that to reflect possible value change. + // + itemsList.BeginUpdate (); + itemsList.ClearSelected (); + foreach (int index in selected) { + itemsList.DoRefreshItem (index); + itemsList.SetSelected (index, true); + } + itemsList.SelectedIndex = selected[0]; + itemsList.EndUpdate (); + } + + private void moveUp_Click (object sender, EventArgs e) + { + if (itemsList.SelectedIndex <= 0) + return; + + object selected = itemsList.SelectedItem; + int index = itemsList.SelectedIndex; + itemsList.Items.RemoveAt (index); + itemsList.Items.Insert (index - 1, selected); + itemsList.SelectedIndex = index - 1; + } + + private void moveDown_Click (object sender, EventArgs e) + { + if (itemsList.SelectedIndex > itemsList.Items.Count - 2) + return; + + object selected = itemsList.SelectedItem; + int index = itemsList.SelectedIndex; + itemsList.Items.RemoveAt (index); + itemsList.Items.Insert (index + 1, selected); + itemsList.SelectedIndex = index + 1; + } + + private void doAdd_Click (object sender, EventArgs e) + { + object o; + try { + o = editor.CreateInstance (editor.NewItemTypes[addType.SelectedIndex]); + } catch (Exception ex) { + DisplayError (ex); + return; + } + itemsList.Items.Add (new ObjectContainer (o, editor)); + itemsList.SelectedIndex = -1; + itemsList.SelectedIndex = itemsList.Items.Count - 1; + } + + private void doRemove_Click (object sender, EventArgs e) + { + if (itemsList.SelectedIndex != -1) { + int[] selected = new int[itemsList.SelectedItems.Count]; + for (int i=0; i < itemsList.SelectedItems.Count; i++) + selected[i] = itemsList.Items.IndexOf (itemsList.SelectedItems[i]); + + for (int i = selected.Length - 1; i >= 0; i--) + itemsList.Items.RemoveAt (selected[i]); + + itemsList.SelectedIndex = Math.Min (selected[0], itemsList.Items.Count-1); + } + } + + // OnEditValueChanged is called only if the EditValue has changed, + // which is only in the case when a new instance of the collection is + // required, e.g for arrays. + // + protected override void OnEditValueChanged () + { + UpdateItems (); + } + } + + private Type type; + private Type collectionItemType; + private Type[] newItemTypes; + private ITypeDescriptorContext context; + private IServiceProvider provider; + private IWindowsFormsEditorService editorService; + + public CollectionEditor (Type type) + { + this.type = type; + this.collectionItemType = CreateCollectionItemType (); + this.newItemTypes = CreateNewItemTypes (); + } + + protected Type CollectionItemType + { + get { return collectionItemType; } + } + + protected Type CollectionType + { + get { return type; } + } + + protected ITypeDescriptorContext Context + { + get { return context; } + } + + protected virtual string HelpTopic + { + get { return "CollectionEditor"; } + } + + protected Type[] NewItemTypes + { + get { return newItemTypes; } + } + + protected virtual void CancelChanges () + { + } + + protected virtual bool CanRemoveInstance (object value) + { + return true; + } + + protected virtual bool CanSelectMultipleInstances () + { + return true; + } + + protected virtual CollectionEditor.CollectionForm CreateCollectionForm () + { + return new ConcreteCollectionForm (this); + } + + protected virtual Type CreateCollectionItemType () + { + PropertyInfo[] properties = type.GetProperties (); + foreach (PropertyInfo property in properties) + if (property.Name == "Item") + return property.PropertyType; + return typeof (object); + } + + protected virtual object CreateInstance (Type itemType) + { + object instance = null; + if (typeof (IComponent).IsAssignableFrom (itemType)) { + IDesignerHost host = GetService (typeof (IDesignerHost)) as IDesignerHost; + if (host != null) + instance = host.CreateComponent (itemType); + } + + if (instance == null) { + instance = TypeDescriptor.CreateInstance (provider, itemType, null, null); + } + return instance; + } + + protected virtual Type[] CreateNewItemTypes () + { + return new Type[] { collectionItemType }; + } + + protected virtual void DestroyInstance (object instance) + { + IComponent component = instance as IComponent; + if (component != null) { + IDesignerHost host = GetService (typeof (IDesignerHost)) as IDesignerHost; + if (host != null) + host.DestroyComponent (component); + } + } + + public override object EditValue (ITypeDescriptorContext context, IServiceProvider provider, object value) + { + this.context = context; + this.provider = provider; + + if (context != null && provider != null) + { + editorService = (IWindowsFormsEditorService)provider.GetService (typeof (IWindowsFormsEditorService)); + if (editorService != null) + { + CollectionForm editorForm = CreateCollectionForm (); + editorForm.EditValue = value; + editorForm.ShowEditorDialog (editorService); + return editorForm.EditValue; + } + } + return base.EditValue (context, provider, value); + } + + protected virtual string GetDisplayText (object value) + { + if (value == null) + return string.Empty; + + PropertyInfo nameProperty = value.GetType ().GetProperty ("Name"); + if (nameProperty != null) + { + string data = (nameProperty.GetValue (value, null)) as string; + if (data != null) + if (data.Length != 0) + return data; + } + + if (Type.GetTypeCode (value.GetType ()) == TypeCode.Object) + return value.GetType ().Name; + else + return value.ToString (); + } + + public override UITypeEditorEditStyle GetEditStyle (ITypeDescriptorContext context) + { + return UITypeEditorEditStyle.Modal; + } + + protected virtual object[] GetItems (object editValue) + { + if (editValue == null) + return new object[0]; + ICollection collection = editValue as ICollection; + if (collection == null) + return new object[0]; + + object[] result = new object[collection.Count]; + collection.CopyTo (result, 0); + return result; + } + + protected virtual IList GetObjectsFromInstance (object instance) + { + ArrayList list = new ArrayList (); + list.Add (instance); + return list; + } + + protected object GetService (Type serviceType) + { + return context.GetService (serviceType); + } + + protected virtual object SetItems (object editValue, object[] value) + { + IList list = (IList) editValue; + if (list == null) + return null; + + list.Clear (); + foreach (object o in value) + list.Add (o); + + return list; + } + + protected virtual void ShowHelp () + { + //TODO: Fixme No help provider. + } + } +} diff --git a/source/ShiftUI/Widgets/ComboBox.cs b/source/ShiftUI/Widgets/ComboBox.cs new file mode 100644 index 0000000..88bcbec --- /dev/null +++ b/source/ShiftUI/Widgets/ComboBox.cs @@ -0,0 +1,2825 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// Mike Kestner +// Daniel Nauck (dna(at)mono-project(dot)de) + +using System; +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.ComponentModel.Design.Serialization; +using System.Drawing; +using System.Globalization; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Diagnostics; + +namespace ShiftUI +{ + [DefaultProperty("Items")] + [DefaultEvent("SelectedIndexChanged")] + //[Designer ("ShiftUI.Design.ComboBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [DefaultBindingProperty ("Text")] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible(true)] + [ToolboxWidget] + public class ComboBox : ListWidget + { + private DrawMode draw_mode = DrawMode.Normal; + private ComboBoxStyle dropdown_style; + private int dropdown_width = -1; + private int selected_index = -1; + private ObjectCollection items; + private bool suspend_ctrlupdate; + private int maxdrop_items = 8; + private bool integral_height = true; + private bool sorted; + private int max_length; + private ComboListBox listbox_ctrl; + private ComboTextBox textbox_ctrl; + private bool process_textchanged_event = true; + private bool process_texchanged_autoscroll = true; + private bool item_height_specified; + private int item_height; + private int requested_height = -1; + private Hashtable item_heights; + private bool show_dropdown_button; + private ButtonState button_state = ButtonState.Normal; + private bool dropped_down; + private Rectangle text_area; + private Rectangle button_area; + private Rectangle listbox_area; + private const int button_width = 16; + bool drop_down_button_entered; + private AutoCompleteStringCollection auto_complete_custom_source = null; + private AutoCompleteMode auto_complete_mode = AutoCompleteMode.None; + private AutoCompleteSource auto_complete_source = AutoCompleteSource.None; + private FlatStyle flat_style; + private int drop_down_height; + const int default_drop_down_height = 106; + + [ComVisible(true)] + public class ChildAccessibleObject : AccessibleObject { + + public ChildAccessibleObject (ComboBox owner, IntPtr handle) + : base (owner) + { + } + + public override string Name { + get { + return base.Name; + } + } + } + + public ComboBox () + { + items = new ObjectCollection (this); + DropDownStyle = ComboBoxStyle.DropDown; + item_height = FontHeight + 2; + background_color = ThemeEngine.Current.ColorControl; + border_style = BorderStyle.None; + + drop_down_height = default_drop_down_height; + flat_style = FlatStyle.Standard; + + /* Events */ + MouseDown += new MouseEventHandler (OnMouseDownCB); + MouseUp += new MouseEventHandler (OnMouseUpCB); + MouseMove += new MouseEventHandler (OnMouseMoveCB); + MouseWheel += new MouseEventHandler (OnMouseWheelCB); + MouseEnter += new EventHandler (OnMouseEnter); + MouseLeave += new EventHandler (OnMouseLeave); + KeyDown +=new KeyEventHandler(OnKeyDownCB); + } + + #region events + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageChanged { + add { base.BackgroundImageChanged += value; } + remove { base.BackgroundImageChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageLayoutChanged + { + add { base.BackgroundImageLayoutChanged += value; } + remove { base.BackgroundImageLayoutChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler DoubleClick + { + add { base.DoubleClick += value; } + remove { base.DoubleClick -= value; } + } + + static object DrawItemEvent = new object (); + static object DropDownEvent = new object (); + static object DropDownStyleChangedEvent = new object (); + static object MeasureItemEvent = new object (); + static object SelectedIndexChangedEvent = new object (); + static object SelectionChangeCommittedEvent = new object (); + static object DropDownClosedEvent = new object (); + static object TextUpdateEvent = new object (); + + public event DrawItemEventHandler DrawItem { + add { Events.AddHandler (DrawItemEvent, value); } + remove { Events.RemoveHandler (DrawItemEvent, value); } + } + + public event EventHandler DropDown { + add { Events.AddHandler (DropDownEvent, value); } + remove { Events.RemoveHandler (DropDownEvent, value); } + } + public event EventHandler DropDownClosed + { + add { Events.AddHandler (DropDownClosedEvent, value); } + remove { Events.RemoveHandler (DropDownClosedEvent, value); } + } + + public event EventHandler DropDownStyleChanged { + add { Events.AddHandler (DropDownStyleChangedEvent, value); } + remove { Events.RemoveHandler (DropDownStyleChangedEvent, value); } + } + + public event MeasureItemEventHandler MeasureItem { + add { Events.AddHandler (MeasureItemEvent, value); } + remove { Events.RemoveHandler (MeasureItemEvent, value); } + } + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler PaddingChanged + { + add { base.PaddingChanged += value; } + remove { base.PaddingChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event PaintEventHandler Paint { + add { base.Paint += value; } + remove { base.Paint -= value; } + } + + public event EventHandler SelectedIndexChanged { + add { Events.AddHandler (SelectedIndexChangedEvent, value); } + remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); } + } + + public event EventHandler SelectionChangeCommitted { + add { Events.AddHandler (SelectionChangeCommittedEvent, value); } + remove { Events.RemoveHandler (SelectionChangeCommittedEvent, value); } + } + public event EventHandler TextUpdate + { + add { Events.AddHandler (TextUpdateEvent, value); } + remove { Events.RemoveHandler (TextUpdateEvent, value); } + } + + #endregion Events + + #region Public Properties + [MonoTODO("AutoCompletion algorithm is currently not implemented.")] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + [Localizable (true)] + //[Editor ("ShiftUI.Design.ListWidgetStringCollectionEditor, " + Consts.AssemblySystem_Design, + //"System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)] + public AutoCompleteStringCollection AutoCompleteCustomSource { + get { + if(auto_complete_custom_source == null) { + auto_complete_custom_source = new AutoCompleteStringCollection (); + auto_complete_custom_source.CollectionChanged += new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged); + } + return auto_complete_custom_source; + } + set { + if(auto_complete_custom_source == value) + return; + + if(auto_complete_custom_source != null) //remove eventhandler from old collection + auto_complete_custom_source.CollectionChanged -= new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged); + + auto_complete_custom_source = value; + + if(auto_complete_custom_source != null) + auto_complete_custom_source.CollectionChanged += new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged); + + SetTextBoxAutoCompleteData (); + } + } + + [MonoTODO("AutoCompletion algorithm is currently not implemented.")] + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + [DefaultValue (AutoCompleteMode.None)] + public AutoCompleteMode AutoCompleteMode { + get { return auto_complete_mode; } + set { + if(auto_complete_mode == value) + return; + + if((value < AutoCompleteMode.None) || (value > AutoCompleteMode.SuggestAppend)) + throw new InvalidEnumArgumentException (String.Format("Enum argument value '{0}' is not valid for AutoCompleteMode", value)); + + auto_complete_mode = value; + SetTextBoxAutoCompleteData (); + } + } + + [MonoTODO("AutoCompletion algorithm is currently not implemented.")] + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + [DefaultValue (AutoCompleteSource.None)] + public AutoCompleteSource AutoCompleteSource { + get { return auto_complete_source; } + set { + if(auto_complete_source == value) + return; + + if(!Enum.IsDefined (typeof (AutoCompleteSource), value)) + throw new InvalidEnumArgumentException (String.Format ("Enum argument value '{0}' is not valid for AutoCompleteSource", value)); + + auto_complete_source = value; + SetTextBoxAutoCompleteData (); + } + } + + void SetTextBoxAutoCompleteData () + { + if (textbox_ctrl == null) + return; + + textbox_ctrl.AutoCompleteMode = auto_complete_mode; + + if (auto_complete_source == AutoCompleteSource.ListItems) { + textbox_ctrl.AutoCompleteSource = AutoCompleteSource.CustomSource; + textbox_ctrl.AutoCompleteCustomSource = null; + textbox_ctrl.AutoCompleteInternalSource = this; + } else { + textbox_ctrl.AutoCompleteSource = auto_complete_source; + textbox_ctrl.AutoCompleteCustomSource = auto_complete_custom_source; + textbox_ctrl.AutoCompleteInternalSource = null; + } + } + public override Color BackColor { + get { return base.BackColor; } + set { + if (base.BackColor == value) + return; + base.BackColor = value; + Refresh (); + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override Image BackgroundImage { + get { return base.BackgroundImage; } + set { + if (base.BackgroundImage == value) + return; + base.BackgroundImage = value; + Refresh (); + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + protected override CreateParams CreateParams { + get { return base.CreateParams;} + } + + [DefaultValue ((string)null)] + [AttributeProvider (typeof (IListSource))] + [RefreshProperties (RefreshProperties.Repaint)] + [MWFCategory("Data")] + public new object DataSource { + get { return base.DataSource; } + set { base.DataSource = value; } + } + + protected override Size DefaultSize { + get { return new Size (121, 21); } + } + + [RefreshProperties(RefreshProperties.Repaint)] + [DefaultValue (DrawMode.Normal)] + [MWFCategory("Behavior")] + public DrawMode DrawMode { + get { return draw_mode; } + set { + if (!Enum.IsDefined (typeof (DrawMode), value)) + throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for DrawMode", value)); + + if (draw_mode == value) + return; + + if (draw_mode == DrawMode.OwnerDrawVariable) + item_heights = null; + draw_mode = value; + if (draw_mode == DrawMode.OwnerDrawVariable) + item_heights = new Hashtable (); + Refresh (); + } + } + + [Browsable (true)] + [DefaultValue (106)] + //[EditorBrowsable (EditorBrowsableState.Always)] + [MWFCategory("Behavior")] + public int DropDownHeight { + get { + return drop_down_height; + } + set { + if (value < 1) + throw new ArgumentOutOfRangeException ("DropDownHeight", "DropDownHeight must be greater than 0."); + + if (value == drop_down_height) + return; + + drop_down_height = value; + IntegralHeight = false; + } + } + + [DefaultValue (ComboBoxStyle.DropDown)] + [RefreshProperties(RefreshProperties.Repaint)] + [MWFCategory("Appearance")] + public ComboBoxStyle DropDownStyle { + get { return dropdown_style; } + set { + if (!Enum.IsDefined (typeof (ComboBoxStyle), value)) + throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for ComboBoxStyle", value)); + + if (dropdown_style == value) + return; + + SuspendLayout (); + + if (dropdown_style == ComboBoxStyle.Simple) { + if (listbox_ctrl != null) { + Widgets.RemoveImplicit (listbox_ctrl); + listbox_ctrl.Dispose (); + listbox_ctrl = null; + } + } + + dropdown_style = value; + + if (dropdown_style == ComboBoxStyle.DropDownList && textbox_ctrl != null) { + Widgets.RemoveImplicit (textbox_ctrl); + textbox_ctrl.Dispose (); + textbox_ctrl = null; + } + + if (dropdown_style == ComboBoxStyle.Simple) { + show_dropdown_button = false; + + CreateComboListBox (); + Widgets.AddImplicit (listbox_ctrl); + listbox_ctrl.Visible = true; + + // This should give us a 150 default height + // for Simple mode if size hasn't been set + // (DefaultSize doesn't work for us in this case) + if (requested_height == -1) + requested_height = 150; + } else { + show_dropdown_button = true; + button_state = ButtonState.Normal; + } + + if (dropdown_style != ComboBoxStyle.DropDownList && textbox_ctrl == null) { + textbox_ctrl = new ComboTextBox (this); + object selected_item = SelectedItem; + if (selected_item != null) + textbox_ctrl.Text = GetItemText (selected_item); + textbox_ctrl.BorderStyle = BorderStyle.None; + textbox_ctrl.TextChanged += new EventHandler (OnTextChangedEdit); + textbox_ctrl.KeyPress += new KeyPressEventHandler (OnTextKeyPress); + textbox_ctrl.Click += new EventHandler (OnTextBoxClick); + textbox_ctrl.TopMargin = 1; // since we don't have borders, adjust manually the top + + if (IsHandleCreated == true) + Widgets.AddImplicit (textbox_ctrl); + SetTextBoxAutoCompleteData (); + } + + ResumeLayout (); + OnDropDownStyleChanged (EventArgs.Empty); + + LayoutComboBox (); + UpdateComboBoxBounds (); + Refresh (); + } + } + + [MWFCategory("Behavior")] + public int DropDownWidth { + get { + if (dropdown_width == -1) + return Width; + + return dropdown_width; + } + set { + if (dropdown_width == value) + return; + + if (value < 1) + throw new ArgumentOutOfRangeException ("DropDownWidth", + "The DropDownWidth value is less than one."); + + dropdown_width = value; + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public bool DroppedDown { + get { + if (dropdown_style == ComboBoxStyle.Simple) + return true; + + return dropped_down; + } + set { + if (dropdown_style == ComboBoxStyle.Simple || dropped_down == value) + return; + + if (value) + DropDownListBox (); + else + listbox_ctrl.HideWindow (); + } + } + + [DefaultValue (FlatStyle.Standard)] + [Localizable (true)] + [MWFCategory("Appearance")] + public FlatStyle FlatStyle { + get { return flat_style; } + set { + if (!Enum.IsDefined (typeof (FlatStyle), value)) + throw new InvalidEnumArgumentException ("FlatStyle", (int) value, typeof (FlatStyle)); + + flat_style = value; + LayoutComboBox (); + Invalidate (); + } + } + + public override bool Focused { + get { return base.Focused; } + } + + public override Color ForeColor { + get { return base.ForeColor; } + set { + if (base.ForeColor == value) + return; + base.ForeColor = value; + Refresh (); + } + } + + [DefaultValue (true)] + [Localizable (true)] + [MWFCategory("Behavior")] + public bool IntegralHeight { + get { return integral_height; } + set { + if (integral_height == value) + return; + integral_height = value; + UpdateComboBoxBounds (); + Refresh (); + } + } + + [Localizable (true)] + [MWFCategory("Behavior")] + public int ItemHeight { + get { + if (item_height == -1) { + SizeF sz = TextRenderer.MeasureString ("The quick brown Fox", Font); + item_height = (int) sz.Height; + } + return item_height; + } + set { + if (value < 1) + throw new ArgumentOutOfRangeException ("ItemHeight", + "The item height value is less than one."); + + item_height_specified = true; + item_height = value; + if (IntegralHeight) + UpdateComboBoxBounds (); + LayoutComboBox (); + Refresh (); + } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + [Localizable (true)] + //[Editor ("ShiftUI.Design.ListWidgetStringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + [MergableProperty (false)] + [MWFCategory("Data")] + public ComboBox.ObjectCollection Items { + get { return items; } + } + + [DefaultValue (8)] + [Localizable (true)] + [MWFCategory("Behavior")] + public int MaxDropDownItems { + get { return maxdrop_items; } + set { + if (maxdrop_items == value) + return; + maxdrop_items = value; + } + } + + public override Size MaximumSize { + get { return base.MaximumSize; } + set { + base.MaximumSize = new Size (value.Width, 0); + } + } + + [DefaultValue (0)] + [Localizable (true)] + [MWFCategory("Behavior")] + public int MaxLength { + get { return max_length; } + set { + if (max_length == value) + return; + + max_length = value; + + if (dropdown_style != ComboBoxStyle.DropDownList) { + if (value < 0) { + value = 0; + } + textbox_ctrl.MaxLength = value; + } + } + } + + public override Size MinimumSize { + get { return base.MinimumSize; } + set { + base.MinimumSize = new Size (value.Width, 0); + } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public new Padding Padding { + get { return base.Padding; } + set { base.Padding = value; } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + [Browsable (false)] + public int PreferredHeight { + get { return Font.Height + 8; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override int SelectedIndex { + get { return selected_index; } + set { + SetSelectedIndex (value, false); + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + [Bindable(true)] + public object SelectedItem { + get { return selected_index == -1 ? null : Items [selected_index]; } + set { + object item = selected_index == -1 ? null : Items [selected_index]; + if (item == value) + return; + + if (value == null) + SelectedIndex = -1; + else + SelectedIndex = Items.IndexOf (value); + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public string SelectedText { + get { + if (dropdown_style == ComboBoxStyle.DropDownList) + return string.Empty; + + string retval = textbox_ctrl.SelectedText; + + return retval; + } + set { + if (dropdown_style == ComboBoxStyle.DropDownList) + return; + textbox_ctrl.SelectedText = value; + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public int SelectionLength { + get { + if (dropdown_style == ComboBoxStyle.DropDownList) + return 0; + + int result = textbox_ctrl.SelectionLength; + return result == -1 ? 0 : result; + } + set { + if (dropdown_style == ComboBoxStyle.DropDownList) + return; + if (textbox_ctrl.SelectionLength == value) + return; + textbox_ctrl.SelectionLength = value; + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public int SelectionStart { + get { + if (dropdown_style == ComboBoxStyle.DropDownList) + return 0; + return textbox_ctrl.SelectionStart; + } + set { + if (dropdown_style == ComboBoxStyle.DropDownList) + return; + if (textbox_ctrl.SelectionStart == value) + return; + textbox_ctrl.SelectionStart = value; + } + } + + [DefaultValue (false)] + [MWFCategory("Behavior")] + public bool Sorted { + get { return sorted; } + set { + if (sorted == value) + return; + sorted = value; + SelectedIndex = -1; + if (sorted) { + Items.Sort (); + LayoutComboBox (); + } + } + } + + [Bindable (true)] + [Localizable (true)] + public override string Text { + get { + if (dropdown_style != ComboBoxStyle.DropDownList) { + if (textbox_ctrl != null) { + return textbox_ctrl.Text; + } + } + + if (SelectedItem != null) + return GetItemText (SelectedItem); + + return base.Text; + } + set { + if (value == null) { + if (SelectedIndex == -1) { + if (dropdown_style != ComboBoxStyle.DropDownList) + SetWidgetText (string.Empty, false); + } else { + SelectedIndex = -1; + } + return; + } + + // don't set the index if value exactly matches text of selected item + if (SelectedItem == null || string.Compare (value, GetItemText (SelectedItem), false, CultureInfo.CurrentCulture) != 0) + { + // find exact match using case-sensitive comparison, and if does + // not result in any match then use case-insensitive comparison + int index = FindStringExact (value, -1, false); + if (index == -1) { + index = FindStringExact (value, -1, true); + } + if (index != -1) { + SelectedIndex = index; + return; + } + } + + // set directly the passed value + if (dropdown_style != ComboBoxStyle.DropDownList) + textbox_ctrl.Text = value; + } + } + + #endregion Public Properties + + #region Internal Properties + internal Rectangle ButtonArea { + get { return button_area; } + } + + internal Rectangle TextArea { + get { return text_area; } + } + #endregion + + #region UIA Framework Properties + + internal TextBox UIATextBox { + get { return textbox_ctrl; } + } + + internal ComboListBox UIAComboListBox { + get { return listbox_ctrl; } + } + + #endregion UIA Framework Properties + + #region Public Methods + [Obsolete ("This method has been deprecated")] + protected virtual void AddItemsCore (object[] value) + { + + } + + public void BeginUpdate () + { + suspend_ctrlupdate = true; + } + + protected override AccessibleObject CreateAccessibilityInstance () + { + return base.CreateAccessibilityInstance (); + } + + protected override void CreateHandle () + { + base.CreateHandle (); + } + + protected override void Dispose (bool disposing) + { + if (disposing) { + if (listbox_ctrl != null) { + listbox_ctrl.Dispose (); + Widgets.RemoveImplicit (listbox_ctrl); + listbox_ctrl = null; + } + + if (textbox_ctrl != null) { + Widgets.RemoveImplicit (textbox_ctrl); + textbox_ctrl.Dispose (); + textbox_ctrl = null; + } + } + + base.Dispose (disposing); + } + + public void EndUpdate () + { + suspend_ctrlupdate = false; + UpdatedItems (); + Refresh (); + } + + public int FindString (string s) + { + return FindString (s, -1); + } + + public int FindString (string s, int startIndex) + { + if (s == null || Items.Count == 0) + return -1; + + if (startIndex < -1 || startIndex >= Items.Count) + throw new ArgumentOutOfRangeException ("startIndex"); + + int i = startIndex; + if (i == (Items.Count - 1)) + i = -1; + do { + i++; + if (string.Compare (s, 0, GetItemText (Items [i]), 0, s.Length, true) == 0) + return i; + if (i == (Items.Count - 1)) + i = -1; + } while (i != startIndex); + + return -1; + } + + public int FindStringExact (string s) + { + return FindStringExact (s, -1); + } + + public int FindStringExact (string s, int startIndex) + { + return FindStringExact (s, startIndex, true); + } + + private int FindStringExact (string s, int startIndex, bool ignoreCase) + { + if (s == null || Items.Count == 0) + return -1; + + if (startIndex < -1 || startIndex >= Items.Count) + throw new ArgumentOutOfRangeException ("startIndex"); + + int i = startIndex; + if (i == (Items.Count - 1)) + i = -1; + do { + i++; + if (string.Compare (s, GetItemText (Items [i]), ignoreCase, CultureInfo.CurrentCulture) == 0) + return i; + if (i == (Items.Count - 1)) + i = -1; + } while (i != startIndex); + + return -1; + } + + public int GetItemHeight (int index) + { + if (DrawMode == DrawMode.OwnerDrawVariable && IsHandleCreated) { + + if (index < 0 || index >= Items.Count ) + throw new ArgumentOutOfRangeException ("The item height value is less than zero"); + + object item = Items [index]; + if (item_heights.Contains (item)) + return (int) item_heights [item]; + + MeasureItemEventArgs args = new MeasureItemEventArgs (DeviceContext, index, ItemHeight); + OnMeasureItem (args); + item_heights [item] = args.ItemHeight; + return args.ItemHeight; + } + + return ItemHeight; + } + + protected override bool IsInputKey (Keys keyData) + { + switch (keyData & ~Keys.Modifiers) { + case Keys.Up: + case Keys.Down: + case Keys.Left: + case Keys.Right: + case Keys.PageUp: + case Keys.PageDown: + case Keys.Home: + case Keys.End: + return true; + + default: + return false; + } + } + + protected override void OnBackColorChanged (EventArgs e) + { + base.OnBackColorChanged (e); + + if (textbox_ctrl != null) + textbox_ctrl.BackColor = BackColor; + } + + protected override void OnDataSourceChanged (EventArgs e) + { + base.OnDataSourceChanged (e); + BindDataItems (); + + /** + ** This 'Debugger.IsAttached' hack is here because of + ** Xamarin Bug #2234, which noted that when changing + ** the DataSource, in Windows exceptions are eaten + ** when SelectedIndexChanged is fired. However, when + ** the debugger is running (i.e. in MonoDevelop), we + ** want to be alerted of exceptions. + **/ + + if (Debugger.IsAttached) { + SetSelectedIndex (); + } else { + try { + SetSelectedIndex (); + } catch { + //ignore exceptions here per + //bug 2234 + } + } + } + + private void SetSelectedIndex () + { + if (DataSource == null || DataManager == null) { + SelectedIndex = -1; + } + else { + SelectedIndex = DataManager.Position; + } + } + + protected override void OnDisplayMemberChanged (EventArgs e) + { + base.OnDisplayMemberChanged (e); + + if (DataManager == null) + return; + + SelectedIndex = DataManager.Position; + + if (selected_index != -1 && DropDownStyle != ComboBoxStyle.DropDownList) + SetWidgetText (GetItemText (Items [selected_index]), true); + + if (!IsHandleCreated) + return; + + Invalidate (); + } + + protected virtual void OnDrawItem (DrawItemEventArgs e) + { + DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]); + if (eh != null) + eh (this, e); + } + + internal void HandleDrawItem (DrawItemEventArgs e) + { + // Only raise OnDrawItem if we are in an OwnerDraw mode + switch (DrawMode) { + case DrawMode.OwnerDrawFixed: + case DrawMode.OwnerDrawVariable: + OnDrawItem (e); + break; + default: + ThemeEngine.Current.DrawComboBoxItem (this, e); + break; + } + } + + protected virtual void OnDropDown (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [DropDownEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnDropDownClosed (EventArgs e) + { + EventHandler eh = (EventHandler) Events [DropDownClosedEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnDropDownStyleChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [DropDownStyleChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnFontChanged (EventArgs e) + { + base.OnFontChanged (e); + + if (textbox_ctrl != null) + textbox_ctrl.Font = Font; + + if (!item_height_specified) + item_height = Font.Height + 2; + + if (IntegralHeight) + UpdateComboBoxBounds (); + + LayoutComboBox (); + } + + protected override void OnForeColorChanged (EventArgs e) + { + base.OnForeColorChanged (e); + if (textbox_ctrl != null) + textbox_ctrl.ForeColor = ForeColor; + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void OnGotFocus (EventArgs e) + { + if (dropdown_style == ComboBoxStyle.DropDownList) { + // We draw DDL styles manually, so they require a + // refresh to have their selection drawn + Invalidate (); + } + + if (textbox_ctrl != null) { + textbox_ctrl.SetSelectable (false); + textbox_ctrl.ShowSelection = Enabled; + textbox_ctrl.ActivateCaret (true); + textbox_ctrl.SelectAll (); + } + + base.OnGotFocus (e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void OnLostFocus (EventArgs e) + { + if (dropdown_style == ComboBoxStyle.DropDownList) { + // We draw DDL styles manually, so they require a + // refresh to have their selection drawn + Invalidate (); + } + + if (listbox_ctrl != null && dropped_down) { + listbox_ctrl.HideWindow (); + } + + if (textbox_ctrl != null) { + textbox_ctrl.SetSelectable (true); + textbox_ctrl.ActivateCaret (false); + textbox_ctrl.ShowSelection = false; + textbox_ctrl.SelectionLength = 0; + textbox_ctrl.HideAutoCompleteList (); + } + + base.OnLostFocus (e); + } + + protected override void OnHandleCreated (EventArgs e) + { + base.OnHandleCreated (e); + + SetBoundsInternal (Left, Top, Width, PreferredHeight, BoundsSpecified.None); + + if (textbox_ctrl != null) + Widgets.AddImplicit (textbox_ctrl); + + LayoutComboBox (); + UpdateComboBoxBounds (); + } + + protected override void OnHandleDestroyed (EventArgs e) + { + base.OnHandleDestroyed (e); + } + + protected override void OnKeyPress (KeyPressEventArgs e) + { + if (dropdown_style == ComboBoxStyle.DropDownList) { + int index = FindStringCaseInsensitive (e.KeyChar.ToString (), SelectedIndex + 1); + if (index != -1) { + SelectedIndex = index; + if (DroppedDown) { //Scroll into view + if (SelectedIndex >= listbox_ctrl.LastVisibleItem ()) + listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.LastVisibleItem () + 1); + // Or, selecting an item earlier in the list. + if (SelectedIndex < listbox_ctrl.FirstVisibleItem ()) + listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.FirstVisibleItem ()); + } + } + } + + base.OnKeyPress (e); + } + + protected virtual void OnMeasureItem (MeasureItemEventArgs e) + { + MeasureItemEventHandler eh = (MeasureItemEventHandler)(Events [MeasureItemEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnParentBackColorChanged (EventArgs e) + { + base.OnParentBackColorChanged (e); + } + + protected override void OnResize (EventArgs e) + { + LayoutComboBox (); + if (listbox_ctrl != null) + listbox_ctrl.CalcListBoxArea (); + } + + protected override void OnSelectedIndexChanged (EventArgs e) + { + base.OnSelectedIndexChanged (e); + + EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnSelectedItemChanged (EventArgs e) + { + } + + protected override void OnSelectedValueChanged (EventArgs e) + { + base.OnSelectedValueChanged (e); + } + + protected virtual void OnSelectionChangeCommitted (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [SelectionChangeCommittedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void RefreshItem (int index) + { + if (index < 0 || index >= Items.Count) + throw new ArgumentOutOfRangeException ("index"); + + if (draw_mode == DrawMode.OwnerDrawVariable) + item_heights.Remove (Items [index]); + } + + protected override void RefreshItems () + { + for (int i = 0; i < Items.Count; i++) { + RefreshItem (i); + } + + LayoutComboBox (); + Refresh (); + + if (selected_index != -1 && DropDownStyle != ComboBoxStyle.DropDownList) + SetWidgetText (GetItemText (Items [selected_index]), false); + } + + public override void ResetText () + { + Text = String.Empty; + } + + protected override bool ProcessKeyEventArgs (ref Message m) + { + return base.ProcessKeyEventArgs (ref m); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void OnKeyDown (KeyEventArgs e) + { + base.OnKeyDown (e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void OnValidating (CancelEventArgs e) + { + base.OnValidating (e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void OnTextChanged (EventArgs e) + { + base.OnTextChanged (e); + } + + protected virtual void OnTextUpdate (EventArgs e) + { + EventHandler eh = (EventHandler) Events [TextUpdateEvent]; + if (eh != null) + eh (this, e); + } + protected override void OnMouseLeave (EventArgs e) + { + if (flat_style == FlatStyle.Popup) + Invalidate (); + base.OnMouseLeave (e); + } + + protected override void OnMouseEnter (EventArgs e) + { + if (flat_style == FlatStyle.Popup) + Invalidate (); + base.OnMouseEnter (e); + } + + protected override void ScaleWidget (SizeF factor, BoundsSpecified specified) + { + base.ScaleWidget (factor, specified); + } + + public void Select (int start, int length) + { + if (start < 0) + throw new ArgumentException ("Start cannot be less than zero"); + + if (length < 0) + throw new ArgumentException ("length cannot be less than zero"); + + if (dropdown_style == ComboBoxStyle.DropDownList) + return; + + textbox_ctrl.Select (start, length); + } + + public void SelectAll () + { + if (dropdown_style == ComboBoxStyle.DropDownList) + return; + + if (textbox_ctrl != null) { + textbox_ctrl.ShowSelection = true; + textbox_ctrl.SelectAll (); + } + } + + protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified) + { + bool vertically_anchored = (Anchor & AnchorStyles.Top) != 0 && (Anchor & AnchorStyles.Bottom) != 0; + bool vertically_docked = Dock == DockStyle.Left || Dock == DockStyle.Right || Dock == DockStyle.Fill; + + if ((specified & BoundsSpecified.Height) != 0 || + (specified == BoundsSpecified.None && (vertically_anchored || vertically_docked))) { + + requested_height = height; + height = SnapHeight (height); + } + + base.SetBoundsCore (x, y, width, height, specified); + } + + protected override void SetItemCore (int index, object value) + { + if (index < 0 || index >= Items.Count) + return; + + Items[index] = value; + } + + protected override void SetItemsCore (IList value) + { + BeginUpdate (); + try { + Items.Clear (); + Items.AddRange (value); + } finally { + EndUpdate (); + } + } + + public override string ToString () + { + return base.ToString () + ", Items.Count:" + Items.Count; + } + + protected override void WndProc (ref Message m) + { + switch ((Msg) m.Msg) { + case Msg.WM_KEYUP: + case Msg.WM_KEYDOWN: + Keys keys = (Keys) m.WParam.ToInt32 (); + // Don't pass the message to base if auto complete is being used and available. + if (textbox_ctrl != null && textbox_ctrl.CanNavigateAutoCompleteList) { + XplatUI.SendMessage (textbox_ctrl.Handle, (Msg) m.Msg, m.WParam, m.LParam); + return; + } + if (keys == Keys.Up || keys == Keys.Down) + break; + goto case Msg.WM_CHAR; + case Msg.WM_CHAR: + // Call our own handler first and send the message to the TextBox if still needed + if (!ProcessKeyMessage (ref m) && textbox_ctrl != null) + XplatUI.SendMessage (textbox_ctrl.Handle, (Msg) m.Msg, m.WParam, m.LParam); + return; + case Msg.WM_MOUSELEAVE: + Point location = PointToClient (Widget.MousePosition); + if (ClientRectangle.Contains (location)) + return; + break; + default: + break; + } + base.WndProc (ref m); + } + + #endregion Public Methods + + #region Private Methods + void OnAutoCompleteCustomSourceChanged(object sender, CollectionChangeEventArgs e) { + if(auto_complete_source == AutoCompleteSource.CustomSource) { + //FIXME: handle add, remove and refresh events in AutoComplete algorithm. + } + } + + internal override bool InternalCapture { + get { return Capture; } + set {} + } + + void LayoutComboBox () + { + int border = ThemeEngine.Current.Border3DSize.Width; + + text_area = ClientRectangle; + text_area.Height = PreferredHeight; + + listbox_area = ClientRectangle; + listbox_area.Y = text_area.Bottom + 3; + listbox_area.Height -= (text_area.Height + 2); + + Rectangle prev_button_area = button_area; + + if (DropDownStyle == ComboBoxStyle.Simple) + button_area = Rectangle.Empty; + else { + button_area = text_area; + button_area.X = text_area.Right - button_width - border; + button_area.Y = text_area.Y + border; + button_area.Width = button_width; + button_area.Height = text_area.Height - 2 * border; + if (flat_style == FlatStyle.Popup || flat_style == FlatStyle.Flat) { + button_area.Inflate (1, 1); + button_area.X += 2; + button_area.Width -= 2; + } + } + + if (button_area != prev_button_area) { + prev_button_area.Y -= border; + prev_button_area.Width += border; + prev_button_area.Height += 2 * border; + Invalidate (prev_button_area); + Invalidate (button_area); + } + + if (textbox_ctrl != null) { + int text_border = border + 1; + textbox_ctrl.Location = new Point (text_area.X + text_border, text_area.Y + text_border); + textbox_ctrl.Width = text_area.Width - button_area.Width - text_border * 2; + textbox_ctrl.Height = text_area.Height - text_border * 2; + } + + if (listbox_ctrl != null && dropdown_style == ComboBoxStyle.Simple) { + listbox_ctrl.Location = listbox_area.Location; + listbox_ctrl.CalcListBoxArea (); + } + } + + private void CreateComboListBox () + { + listbox_ctrl = new ComboListBox (this); + listbox_ctrl.HighlightedIndex = SelectedIndex; + } + + internal void Draw (Rectangle clip, Graphics dc) + { + Theme theme = ThemeEngine.Current; + FlatStyle style = FlatStyle.Standard; + bool is_flat = false; + + style = this.FlatStyle; + is_flat = style == FlatStyle.Flat || style == FlatStyle.Popup; + + theme.ComboBoxDrawBackground (this, dc, clip, style); + + int border = theme.Border3DSize.Width; + + // No edit Widget, we paint the edit ourselves + if (dropdown_style == ComboBoxStyle.DropDownList) { + DrawItemState state = DrawItemState.None; + Color back_color = BackColor; + Color fore_color = ForeColor; + Rectangle item_rect = text_area; + item_rect.X += border; + item_rect.Y += border; + item_rect.Width -= (button_area.Width + 2 * border); + item_rect.Height -= 2 * border; + + if (Focused) { + state = DrawItemState.Selected; + state |= DrawItemState.Focus; + back_color = SystemColors.Highlight; + fore_color = SystemColors.HighlightText; + } + + state |= DrawItemState.ComboBoxEdit; + HandleDrawItem (new DrawItemEventArgs (dc, Font, item_rect, SelectedIndex, state, fore_color, back_color)); + } + + if (show_dropdown_button) { + ButtonState current_state; + if (is_enabled) + current_state = button_state; + else + current_state = ButtonState.Inactive; + + if (is_flat || theme.ComboBoxNormalDropDownButtonHasTransparentBackground (this, current_state)) + dc.FillRectangle (theme.ResPool.GetSolidBrush (theme.ColorControl), button_area); + + if (is_flat) { + theme.DrawFlatStyleComboButton (dc, button_area, current_state); + } else { + theme.ComboBoxDrawNormalDropDownButton (this, dc, clip, button_area, current_state); + } + } + } + + internal bool DropDownButtonEntered { + get { return drop_down_button_entered; } + private set { + if (drop_down_button_entered == value) + return; + drop_down_button_entered = value; + if (ThemeEngine.Current.ComboBoxDropDownButtonHasHotElementStyle (this)) + Invalidate (button_area); + } + } + + internal void DropDownListBox () + { + DropDownButtonEntered = false; + + if (DropDownStyle == ComboBoxStyle.Simple) + return; + + if (listbox_ctrl == null) + CreateComboListBox (); + + listbox_ctrl.Location = PointToScreen (new Point (text_area.X, text_area.Y + text_area.Height)); + + FindMatchOrSetIndex(SelectedIndex); + + if (textbox_ctrl != null) + textbox_ctrl.HideAutoCompleteList (); + + if (listbox_ctrl.ShowWindow ()) + dropped_down = true; + + button_state = ButtonState.Pushed; + if (dropdown_style == ComboBoxStyle.DropDownList) + Invalidate (text_area); + } + + internal void DropDownListBoxFinished () + { + if (DropDownStyle == ComboBoxStyle.Simple) + return; + + FindMatchOrSetIndex (SelectedIndex); + button_state = ButtonState.Normal; + Invalidate (button_area); + dropped_down = false; + OnDropDownClosed (EventArgs.Empty); + /* + * Apples X11 looses override-redirect when doing a Unmap/Map on a previously mapped window + * this causes the popup to appear under the main form. This is horrible but necessary + */ + + // If the user opens a new form in an event, it will close our dropdown, + // so we need a null check here + if (listbox_ctrl != null) { + listbox_ctrl.Dispose (); + listbox_ctrl = null; + } + // The auto complete list could have been shown after the listbox, + // so make sure it's hidden. + if (textbox_ctrl != null) + textbox_ctrl.HideAutoCompleteList (); + } + + private int FindStringCaseInsensitive (string search) + { + if (search.Length == 0) { + return -1; + } + + for (int i = 0; i < Items.Count; i++) + { + if (String.Compare (GetItemText (Items[i]), 0, search, 0, search.Length, true) == 0) + return i; + } + + return -1; + } + + // Search in the list for the substring, starting the search at the list + // position specified, the search wraps thus covering all the list. + internal int FindStringCaseInsensitive (string search, int start_index) + { + if (search.Length == 0) { + return -1; + } + // Accept from first item to after last item. i.e. all cases of (SelectedIndex+1). + if (start_index < 0 || start_index > Items.Count) + throw new ArgumentOutOfRangeException("start_index"); + + for (int i = 0; i < Items.Count; i++) { + int index = (i + start_index) % Items.Count; + if (String.Compare (GetItemText (Items [index]), 0, search, 0, search.Length, true) == 0) + return index; + } + + return -1; + } + + internal override bool IsInputCharInternal (char charCode) + { + return true; + } + + internal void RestoreContextMenu () + { + textbox_ctrl.RestoreContextMenu (); + } + + private void OnKeyDownCB(object sender, KeyEventArgs e) + { + if (Items.Count == 0) + return; + + // for keyboard navigation, we have to do our own scroll, since + // the default behaviour for the SelectedIndex property is a little different, + // setting the selected index in the top always + + int offset; + switch (e.KeyCode) + { + case Keys.Up: + FindMatchOrSetIndex(Math.Max(SelectedIndex - 1, 0)); + + if (DroppedDown) + if (SelectedIndex < listbox_ctrl.FirstVisibleItem ()) + listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.FirstVisibleItem ()); + break; + + case Keys.Down: + if ((e.Modifiers & Keys.Alt) == Keys.Alt) + DropDownListBox (); + else + FindMatchOrSetIndex(Math.Min(SelectedIndex + 1, Items.Count - 1)); + + if (DroppedDown) + if (SelectedIndex >= listbox_ctrl.LastVisibleItem ()) + listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.LastVisibleItem () + 1); + break; + + case Keys.PageUp: + offset = listbox_ctrl == null ? MaxDropDownItems - 1 : listbox_ctrl.page_size - 1; + if (offset < 1) + offset = 1; + + SetSelectedIndex (Math.Max (SelectedIndex - offset, 0), true); + + if (DroppedDown) + if (SelectedIndex < listbox_ctrl.FirstVisibleItem ()) + listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.FirstVisibleItem ()); + break; + + case Keys.PageDown: + if (SelectedIndex == -1) { + SelectedIndex = 0; + if (dropdown_style != ComboBoxStyle.Simple) + return; + } + + offset = listbox_ctrl == null ? MaxDropDownItems - 1 : listbox_ctrl.page_size - 1; + if (offset < 1) + offset = 1; + + SetSelectedIndex (Math.Min (SelectedIndex + offset, Items.Count - 1), true); + + if (DroppedDown) + if (SelectedIndex >= listbox_ctrl.LastVisibleItem ()) + listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.LastVisibleItem () + 1); + break; + + case Keys.Enter: + case Keys.Escape: + if (listbox_ctrl != null && listbox_ctrl.Visible) + DropDownListBoxFinished (); + break; + + case Keys.Home: + if (dropdown_style == ComboBoxStyle.DropDownList) { + SelectedIndex = 0; + + if (DroppedDown) + if (SelectedIndex < listbox_ctrl.FirstVisibleItem ()) + listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.FirstVisibleItem ()); + } + + break; + case Keys.End: + if (dropdown_style == ComboBoxStyle.DropDownList) { + SetSelectedIndex (Items.Count - 1, true); + + if (DroppedDown) + if (SelectedIndex >= listbox_ctrl.LastVisibleItem ()) + listbox_ctrl.Scroll (SelectedIndex - listbox_ctrl.LastVisibleItem () + 1); + } + + break; + default: + break; + } + } + + void SetSelectedIndex (int value, bool supressAutoScroll) + { + if (selected_index == value) + return; + + if (value <= -2 || value >= Items.Count) + throw new ArgumentOutOfRangeException ("SelectedIndex"); + + selected_index = value; + + if (dropdown_style != ComboBoxStyle.DropDownList) { + if (value == -1) + SetWidgetText (string.Empty, false, supressAutoScroll); + else + SetWidgetText (GetItemText (Items [value]), false, supressAutoScroll); + } + + if (DropDownStyle == ComboBoxStyle.DropDownList) + Invalidate (); + + if (listbox_ctrl != null) + listbox_ctrl.HighlightedIndex = value; + + OnSelectedValueChanged (EventArgs.Empty); + OnSelectedIndexChanged (EventArgs.Empty); + OnSelectedItemChanged (EventArgs.Empty); + } + + // If no item is currently selected, and an item is found matching the text + // in the textbox, then selected that item. Otherwise the item at the given + // index is selected. + private void FindMatchOrSetIndex(int index) + { + int match = -1; + if (SelectedIndex == -1 && Text.Length != 0) + match = FindStringCaseInsensitive(Text); + if (match != -1) + SetSelectedIndex (match, true); + else + SetSelectedIndex (index, true); + } + + void OnMouseDownCB (object sender, MouseEventArgs e) + { + Rectangle area; + if (DropDownStyle == ComboBoxStyle.DropDownList) + area = ClientRectangle; + else + area = button_area; + + if (area.Contains (e.X, e.Y)) { + if (Items.Count > 0) + DropDownListBox (); + else { + button_state = ButtonState.Pushed; + OnDropDown (EventArgs.Empty); + } + + Invalidate (button_area); + Update (); + } + Capture = true; + } + + void OnMouseEnter (object sender, EventArgs e) + { + if (ThemeEngine.Current.CombBoxBackgroundHasHotElementStyle (this)) + Invalidate (); + } + + void OnMouseLeave (object sender, EventArgs e) + { + if (ThemeEngine.Current.CombBoxBackgroundHasHotElementStyle (this)) { + drop_down_button_entered = false; + Invalidate (); + } else { + if (show_dropdown_button) + DropDownButtonEntered = false; + } + } + + void OnMouseMoveCB (object sender, MouseEventArgs e) + { + if (show_dropdown_button && !dropped_down) + DropDownButtonEntered = button_area.Contains (e.Location); + + if (DropDownStyle == ComboBoxStyle.Simple) + return; + + if (listbox_ctrl != null && listbox_ctrl.Visible) { + Point location = listbox_ctrl.PointToClient (Widget.MousePosition); + if (listbox_ctrl.ClientRectangle.Contains (location)) + listbox_ctrl.Capture = true; + } + } + + void OnMouseUpCB (object sender, MouseEventArgs e) + { + Capture = false; + + button_state = ButtonState.Normal; + Invalidate (button_area); + + OnClick (EventArgs.Empty); + + if (dropped_down) + listbox_ctrl.Capture = true; + } + + private void OnMouseWheelCB (object sender, MouseEventArgs me) + { + if (Items.Count == 0) + return; + + if (listbox_ctrl != null && listbox_ctrl.Visible) { + int lines = me.Delta / 120 * SystemInformation.MouseWheelScrollLines; + listbox_ctrl.Scroll (-lines); + } else { + int lines = me.Delta / 120; + int index = SelectedIndex - lines; + if (index < 0) + index = 0; + else if (index >= Items.Count) + index = Items.Count - 1; + SelectedIndex = index; + } + } + + MouseEventArgs TranslateMouseEventArgs (MouseEventArgs args) + { + Point loc = PointToClient (Widget.MousePosition); + return new MouseEventArgs (args.Button, args.Clicks, loc.X, loc.Y, args.Delta); + } + + internal override void OnPaintInternal (PaintEventArgs pevent) + { + if (suspend_ctrlupdate) + return; + + Draw (ClientRectangle, pevent.Graphics); + } + + private void OnTextBoxClick (object sender, EventArgs e) + { + OnClick (e); + } + + private void OnTextChangedEdit (object sender, EventArgs e) + { + if (process_textchanged_event == false) + return; + + int item = FindStringCaseInsensitive (textbox_ctrl.Text); + + if (item == -1) { + // Setting base.Text below will raise this event + // if we found something + OnTextChanged (EventArgs.Empty); + return; + } + + if (listbox_ctrl != null) { + // Set as top item + if (process_texchanged_autoscroll) + listbox_ctrl.EnsureTop (item); + } + + base.Text = textbox_ctrl.Text; + } + + private void OnTextKeyPress (object sender, KeyPressEventArgs e) + { + selected_index = -1; + if (listbox_ctrl != null) + listbox_ctrl.HighlightedIndex = -1; + } + + internal void SetWidgetText (string s, bool suppressTextChanged) + { + SetWidgetText (s, suppressTextChanged, false); + } + + internal void SetWidgetText (string s, bool suppressTextChanged, bool supressAutoScroll) + { + if (suppressTextChanged) + process_textchanged_event = false; + if (supressAutoScroll) + process_texchanged_autoscroll = false; + + textbox_ctrl.Text = s; + textbox_ctrl.SelectAll (); + process_textchanged_event = true; + process_texchanged_autoscroll = true; + } + + void UpdateComboBoxBounds () + { + if (requested_height == -1) + return; + + // Save the requested height since set bounds can destroy it + int save_height = requested_height; + SetBounds (bounds.X, bounds.Y, bounds.Width, SnapHeight (requested_height), + BoundsSpecified.Height); + requested_height = save_height; + } + + int SnapHeight (int height) + { + if (DropDownStyle == ComboBoxStyle.Simple && height > PreferredHeight) { + if (IntegralHeight) { + int border = ThemeEngine.Current.Border3DSize.Height; + int lb_height = (height - PreferredHeight - 2) - border * 2; + if (lb_height > ItemHeight) { + int partial = (lb_height) % ItemHeight; + height -= partial; + } else if (lb_height < ItemHeight) + height = PreferredHeight; + } + } else + height = PreferredHeight; + + return height; + } + + private void UpdatedItems () + { + if (listbox_ctrl != null) { + listbox_ctrl.UpdateLastVisibleItem (); + listbox_ctrl.CalcListBoxArea (); + listbox_ctrl.Refresh (); + } + } + + #endregion Private Methods + + [ListBindableAttribute (false)] + public class ObjectCollection : IList, ICollection, IEnumerable + { + + private ComboBox owner; + internal ArrayList object_items = new ArrayList (); + + public ComboBox Owner + { + get { return owner; } + } + + #region UIA Framework Events + + //NOTE: + // We are using Reflection to add/remove internal events. + // Class ListProvider uses the events. + // + //Event used to generate UIA StructureChangedEvent + static object UIACollectionChangedEvent = new object (); + + internal event CollectionChangeEventHandler UIACollectionChanged { + add { owner.Events.AddHandler (UIACollectionChangedEvent, value); } + remove { owner.Events.RemoveHandler (UIACollectionChangedEvent, value); } + } + + internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args) + { + CollectionChangeEventHandler eh + = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent]; + if (eh != null) + eh (owner, args); + } + + #endregion UIA Framework Events + + public ObjectCollection (ComboBox owner) + { + this.owner = owner; + } + + #region Public Properties + public int Count { + get { return object_items.Count; } + } + + public bool IsReadOnly { + get { return false; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public virtual object this [int index] { + get { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("index"); + + return object_items[index]; + } + set { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("index"); + if (value == null) + throw new ArgumentNullException ("value"); + + //UIA Framework event: Item Removed + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, object_items [index])); + + object_items[index] = value; + + //UIA Framework event: Item Added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value)); + + if (owner.listbox_ctrl != null) + owner.listbox_ctrl.InvalidateItem (index); + if (index == owner.SelectedIndex) { + if (owner.textbox_ctrl == null) + owner.Refresh (); + else { + owner.textbox_ctrl.Text = value.ToString (); + owner.textbox_ctrl.SelectAll (); + } + } + } + } + + bool ICollection.IsSynchronized { + get { return false; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + bool IList.IsFixedSize { + get { return false; } + } + + #endregion Public Properties + + #region Public Methods + public int Add (object item) + { + int idx; + + idx = AddItem (item, false); + owner.UpdatedItems (); + return idx; + } + + public void AddRange (object[] items) + { + if (items == null) + throw new ArgumentNullException ("items"); + + foreach (object mi in items) + AddItem (mi, true); + + if (owner.sorted) + Sort (); + + owner.UpdatedItems (); + } + + public void Clear () + { + owner.selected_index = -1; + object_items.Clear (); + owner.UpdatedItems (); + owner.Refresh (); + + //UIA Framework event: Items list cleared + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null)); + } + + public bool Contains (object value) + { + if (value == null) + throw new ArgumentNullException ("value"); + + return object_items.Contains (value); + } + + public void CopyTo (object [] destination, int arrayIndex) + { + object_items.CopyTo (destination, arrayIndex); + } + + void ICollection.CopyTo (Array destination, int index) + { + object_items.CopyTo (destination, index); + } + + public IEnumerator GetEnumerator () + { + return object_items.GetEnumerator (); + } + + int IList.Add (object item) + { + return Add (item); + } + + public int IndexOf (object value) + { + if (value == null) + throw new ArgumentNullException ("value"); + + return object_items.IndexOf (value); + } + + public void Insert (int index, object item) + { + if (index < 0 || index > Count) + throw new ArgumentOutOfRangeException ("index"); + if (item == null) + throw new ArgumentNullException ("item"); + + owner.BeginUpdate (); + + if (owner.Sorted) + AddItem (item, false); + else { + object_items.Insert (index, item); + //UIA Framework event: Item added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item)); + } + + owner.EndUpdate (); // Calls UpdatedItems + } + + public void Remove (object value) + { + if (value == null) + return; + int index = IndexOf (value); + if (index >= 0) + RemoveAt (index); + } + + public void RemoveAt (int index) + { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("index"); + + if (index < owner.SelectedIndex) + --owner.SelectedIndex; + else if (index == owner.SelectedIndex) + owner.SelectedIndex = -1; + + object removed = object_items [index]; + + object_items.RemoveAt (index); + owner.UpdatedItems (); + + //UIA Framework event: Item removed + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, removed)); + } + #endregion Public Methods + + #region Private Methods + private int AddItem (object item, bool suspend) + { + // suspend means do not sort as we put new items in, we will do a + // big sort at the end + if (item == null) + throw new ArgumentNullException ("item"); + + if (owner.Sorted && !suspend) { + int index = 0; + foreach (object o in object_items) { + if (String.Compare (item.ToString (), o.ToString ()) < 0) { + object_items.Insert (index, item); + + // If we added the new item before the selectedindex + // bump the selectedindex by one, behavior differs if + // Handle has not been created. + if (index <= owner.selected_index && owner.IsHandleCreated) + owner.selected_index++; + + //UIA Framework event: Item added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item)); + + return index; + } + index++; + } + } + object_items.Add (item); + + //UIA Framework event: Item added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item)); + + return object_items.Count - 1; + } + + internal void AddRange (IList items) + { + foreach (object mi in items) + AddItem (mi, false); + + if (owner.sorted) + Sort (); + + owner.UpdatedItems (); + } + + internal void Sort () + { + // If the objects the user put here don't have their own comparer, + // use one that compares based on the object's ToString + if (object_items.Count > 0 && object_items[0] is IComparer) + object_items.Sort (); + else + object_items.Sort (new ObjectComparer (owner)); + } + + private class ObjectComparer : IComparer + { + private ListWidget owner; + + public ObjectComparer (ListWidget owner) + { + this.owner = owner; + } + + #region IComparer Members + public int Compare (object x, object y) + { + return string.Compare (owner.GetItemText (x), owner.GetItemText (y)); + } + #endregion + } + #endregion Private Methods + } + + internal class ComboTextBox : TextBox { + + private ComboBox owner; + + public ComboTextBox (ComboBox owner) + { + this.owner = owner; + ShowSelection = false; + owner.EnabledChanged += OwnerEnabledChangedHandler; + owner.LostFocus += OwnerLostFocusHandler; + } + + void OwnerEnabledChangedHandler (object o, EventArgs args) + { + ShowSelection = owner.Focused && owner.Enabled; + } + + void OwnerLostFocusHandler (object o, EventArgs args) + { + if (IsAutoCompleteAvailable) + owner.Text = Text; + } + + protected override void OnKeyDown (KeyEventArgs args) + { + if (args.KeyCode == Keys.Enter && IsAutoCompleteAvailable) + owner.Text = Text; + + base.OnKeyDown (args); + } + + internal override void OnAutoCompleteValueSelected (EventArgs args) + { + base.OnAutoCompleteValueSelected (args); + owner.Text = Text; + } + + internal void SetSelectable (bool selectable) + { + SetStyle (Widgetstyles.Selectable, selectable); + } + + internal void ActivateCaret (bool active) + { + if (active) + document.CaretHasFocus (); + else + document.CaretLostFocus (); + } + + internal override void OnTextUpdate () + { + base.OnTextUpdate (); + owner.OnTextUpdate (EventArgs.Empty); + } + + protected override void OnGotFocus (EventArgs e) + { + owner.Select (false, true); + } + + protected override void OnLostFocus (EventArgs e) + { + owner.Select (false, true); + } + + // We have to pass these events to our owner - MouseMove is not, however. + + protected override void OnMouseDown (MouseEventArgs e) + { + base.OnMouseDown (e); + owner.OnMouseDown (owner.TranslateMouseEventArgs (e)); + } + + protected override void OnMouseUp (MouseEventArgs e) + { + base.OnMouseUp (e); + owner.OnMouseUp (owner.TranslateMouseEventArgs (e)); + } + + protected override void OnMouseClick (MouseEventArgs e) + { + base.OnMouseClick (e); + owner.OnMouseClick (owner.TranslateMouseEventArgs (e)); + } + + protected override void OnMouseDoubleClick (MouseEventArgs e) + { + base.OnMouseDoubleClick (e); + owner.OnMouseDoubleClick (owner.TranslateMouseEventArgs (e)); + } + + public override bool Focused { + get { + return owner.Focused; + } + } + protected override void Dispose(bool disposing) + { + if (disposing ) { + // Prevents corruption of combobox text by disposed object + owner.EnabledChanged -= OwnerEnabledChangedHandler; + owner.LostFocus -= OwnerLostFocusHandler; + } + base.Dispose(disposing); + } + + internal override bool ActivateOnShow { get { return false; } } + } + + internal class ComboListBox : Widget + { + private ComboBox owner; + private VScrollBarLB vscrollbar_ctrl; + private int top_item; /* First item that we show the in the current page */ + private int last_item; /* Last visible item */ + internal int page_size; /* Number of listbox items per page */ + private Rectangle textarea_drawable; /* Rectangle of the drawable text area */ + + internal enum ItemNavigation + { + First, + Last, + Next, + Previous, + NextPage, + PreviousPage, + } + + #region UIA Framework: Properties + + internal int UIATopItem { + get { return top_item; } + } + + internal int UIALastItem { + get { return last_item; } + } + + internal ScrollBar UIAVScrollBar { + get { return vscrollbar_ctrl; } + } + + #endregion + + class VScrollBarLB : VScrollBar + { + public VScrollBarLB () + { + } + + internal override bool InternalCapture { + get { return Capture; } + set { } + } + + public void FireMouseDown (MouseEventArgs e) + { + if (!Visible) + return; + + e = TranslateEvent (e); + OnMouseDown (e); + } + + public void FireMouseUp (MouseEventArgs e) + { + if (!Visible) + return; + + e = TranslateEvent (e); + OnMouseUp (e); + } + + public void FireMouseMove (MouseEventArgs e) + { + if (!Visible) + return; + + e = TranslateEvent (e); + OnMouseMove (e); + } + + MouseEventArgs TranslateEvent (MouseEventArgs e) + { + Point loc = PointToClient (Widget.MousePosition); + return new MouseEventArgs (e.Button, e.Clicks, loc.X, loc.Y, e.Delta); + } + } + + public ComboListBox (ComboBox owner) + { + this.owner = owner; + top_item = 0; + last_item = 0; + page_size = 0; + + MouseWheel += new MouseEventHandler (OnMouseWheelCLB); + + SetStyle (Widgetstyles.UserPaint | Widgetstyles.AllPaintingInWmPaint, true); + SetStyle (Widgetstyles.ResizeRedraw | Widgetstyles.Opaque, true); + + this.is_visible = false; + + if (owner.DropDownStyle == ComboBoxStyle.Simple) + InternalBorderStyle = BorderStyle.Fixed3D; + else + InternalBorderStyle = BorderStyle.FixedSingle; + } + + protected override CreateParams CreateParams + { + get { + CreateParams cp = base.CreateParams; + if (owner == null || owner.DropDownStyle == ComboBoxStyle.Simple) + return cp; + + cp.Style ^= (int)WindowStyles.WS_CHILD; + cp.Style ^= (int)WindowStyles.WS_VISIBLE; + cp.Style |= (int)WindowStyles.WS_POPUP; + cp.ExStyle |= (int) WindowExStyles.WS_EX_TOOLWINDOW | (int) WindowExStyles.WS_EX_TOPMOST; + return cp; + } + } + + internal override bool InternalCapture { + get { + return Capture; + } + + set { + } + } + + internal override bool ActivateOnShow { get { return false; } } + #region Private Methods + + // Calcs the listbox area + internal void CalcListBoxArea () + { + int width, height; + bool show_scrollbar; + + if (owner.DropDownStyle == ComboBoxStyle.Simple) { + Rectangle area = owner.listbox_area; + width = area.Width; + height = area.Height; + show_scrollbar = owner.Items.Count * owner.ItemHeight > height; + + // No calculation needed + if (height <= 0 || width <= 0) + return; + + } + else { // DropDown or DropDownList + + width = owner.DropDownWidth; + int visible_items_count = (owner.Items.Count <= owner.MaxDropDownItems) ? owner.Items.Count : owner.MaxDropDownItems; + + if (owner.DrawMode == DrawMode.OwnerDrawVariable) { + height = 0; + for (int i = 0; i < visible_items_count; i++) { + height += owner.GetItemHeight (i); + } + + show_scrollbar = owner.Items.Count > owner.MaxDropDownItems; + + } else { + if (owner.DropDownHeight == default_drop_down_height) { // ignore DropDownHeight + height = owner.ItemHeight * visible_items_count; + show_scrollbar = owner.Items.Count > owner.MaxDropDownItems; + } else { + // ignore visible items count, and use manual height instead + height = owner.DropDownHeight; + show_scrollbar = (owner.Items.Count * owner.ItemHeight) > height; + } + } + } + + page_size = Math.Max (height / owner.ItemHeight, 1); + + ComboBoxStyle dropdown_style = owner.DropDownStyle; + if (!show_scrollbar) { + + if (vscrollbar_ctrl != null) + vscrollbar_ctrl.Visible = false; + if (dropdown_style != ComboBoxStyle.Simple) + height = owner.ItemHeight * owner.items.Count; + } else { + /* Need vertical scrollbar */ + if (vscrollbar_ctrl == null) { + vscrollbar_ctrl = new VScrollBarLB (); + vscrollbar_ctrl.Minimum = 0; + vscrollbar_ctrl.SmallChange = 1; + vscrollbar_ctrl.LargeChange = 1; + vscrollbar_ctrl.Maximum = 0; + vscrollbar_ctrl.ValueChanged += new EventHandler (VerticalScrollEvent); + Widgets.AddImplicit (vscrollbar_ctrl); + } + + vscrollbar_ctrl.Dock = DockStyle.Right; + + vscrollbar_ctrl.Maximum = owner.Items.Count - 1; + int large = page_size; + if (large < 1) + large = 1; + vscrollbar_ctrl.LargeChange = large; + vscrollbar_ctrl.Visible = true; + + int hli = HighlightedIndex; + if (hli > 0) { + hli = Math.Min (hli, vscrollbar_ctrl.Maximum); + vscrollbar_ctrl.Value = hli; + } + } + + var borderWidth = Hwnd.GetBorderWidth (CreateParams); + var borderAdjustment = dropdown_style == ComboBoxStyle.Simple ? new Size (0, 0) : + new Size (borderWidth.top + borderWidth.bottom, borderWidth.left + borderWidth.right); + Size = new Size (width, height + borderAdjustment.Height); + textarea_drawable = new Rectangle (ClientRectangle.Location, + new Size (width - borderAdjustment.Width, height)); + + if (vscrollbar_ctrl != null && show_scrollbar) + textarea_drawable.Width -= vscrollbar_ctrl.Width; + + last_item = LastVisibleItem (); + } + + private void Draw (Rectangle clip, Graphics dc) + { + dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (owner.BackColor), clip); + + if (owner.Items.Count > 0) { + + for (int i = top_item; i <= last_item; i++) { + Rectangle item_rect = GetItemDisplayRectangle (i, top_item); + + if (!clip.IntersectsWith (item_rect)) + continue; + + DrawItemState state = DrawItemState.None; + Color back_color = owner.BackColor; + Color fore_color = owner.ForeColor; + + if (i == HighlightedIndex) { + state |= DrawItemState.Selected; + back_color = SystemColors.Highlight; + fore_color = SystemColors.HighlightText; + + if (owner.DropDownStyle == ComboBoxStyle.DropDownList) { + state |= DrawItemState.Focus; + } + } + + owner.HandleDrawItem (new DrawItemEventArgs (dc, owner.Font, item_rect, + i, state, fore_color, back_color)); + } + } + } + + int highlighted_index = -1; + + public int HighlightedIndex { + get { return highlighted_index; } + set { + if (highlighted_index == value) + return; + + if (highlighted_index != -1 && highlighted_index < this.owner.Items.Count) + Invalidate (GetItemDisplayRectangle (highlighted_index, top_item)); + highlighted_index = value; + if (highlighted_index != -1) + Invalidate (GetItemDisplayRectangle (highlighted_index, top_item)); + } + } + + private Rectangle GetItemDisplayRectangle (int index, int top_index) + { + if (index < 0 || index >= owner.Items.Count) + throw new ArgumentOutOfRangeException ("GetItemRectangle index out of range."); + + Rectangle item_rect = new Rectangle (); + int height = owner.GetItemHeight (index); + + item_rect.X = 0; + item_rect.Width = textarea_drawable.Width; + if (owner.DrawMode == DrawMode.OwnerDrawVariable) { + item_rect.Y = 0; + for (int i = top_index; i < index; i++) + item_rect.Y += owner.GetItemHeight (i); + } else + item_rect.Y = height * (index - top_index); + + item_rect.Height = height; + return item_rect; + } + + public void HideWindow () + { + if (owner.DropDownStyle == ComboBoxStyle.Simple) + return; + + Capture = false; + Hide (); + owner.DropDownListBoxFinished (); + } + + private int IndexFromPointDisplayRectangle (int x, int y) + { + for (int i = top_item; i <= last_item; i++) { + if (GetItemDisplayRectangle (i, top_item).Contains (x, y) == true) + return i; + } + + return -1; + } + + public void InvalidateItem (int index) + { + if (Visible) + Invalidate (GetItemDisplayRectangle (index, top_item)); + } + + public int LastVisibleItem () + { + Rectangle item_rect; + int top_y = textarea_drawable.Y + textarea_drawable.Height; + int i = 0; + + for (i = top_item; i < owner.Items.Count; i++) { + item_rect = GetItemDisplayRectangle (i, top_item); + if (item_rect.Y + item_rect.Height > top_y) { + return i; + } + } + return i - 1; + } + + public void SetTopItem (int item) + { + if (top_item == item) + return; + top_item = item; + UpdateLastVisibleItem (); + Invalidate (); + } + + public int FirstVisibleItem () + { + return top_item; + } + + public void EnsureTop (int item) + { + if (owner.Items.Count == 0) + return; + if (vscrollbar_ctrl == null || !vscrollbar_ctrl.Visible) + return; + + int max = vscrollbar_ctrl.Maximum - page_size + 1; + if (item > max) + item = max; + else if (item < vscrollbar_ctrl.Minimum) + item = vscrollbar_ctrl.Minimum; + + vscrollbar_ctrl.Value = item; + } + + bool scrollbar_grabbed = false; + + bool InScrollBar { + get { + if (vscrollbar_ctrl == null || !vscrollbar_ctrl.is_visible) + return false; + + return vscrollbar_ctrl.Bounds.Contains (PointToClient (Widget.MousePosition)); + } + } + + protected override void OnMouseDown (MouseEventArgs e) + { + if (InScrollBar) { + vscrollbar_ctrl.FireMouseDown (e); + scrollbar_grabbed = true; + } + } + + protected override void OnMouseMove (MouseEventArgs e) + { + if (owner.DropDownStyle == ComboBoxStyle.Simple) + return; + + if (scrollbar_grabbed || (!Capture && InScrollBar)) { + vscrollbar_ctrl.FireMouseMove (e); + return; + } + + Point pt = PointToClient (Widget.MousePosition); + int index = IndexFromPointDisplayRectangle (pt.X, pt.Y); + + if (index != -1) + HighlightedIndex = index; + } + + protected override void OnMouseUp (MouseEventArgs e) + { + int index = IndexFromPointDisplayRectangle (e.X, e.Y); + + if (scrollbar_grabbed) { + vscrollbar_ctrl.FireMouseUp (e); + scrollbar_grabbed = false; + if (index != -1) + HighlightedIndex = index; + return; + } + + if (index == -1) { + HideWindow (); + return; + } + + bool is_change = owner.SelectedIndex != index; + + owner.SetSelectedIndex (index, true); + owner.OnSelectionChangeCommitted (new EventArgs ()); + + // If the user selected the already selected item, SelectedIndex + // won't fire these events, but .Net does, so we do it here + if (!is_change) { + owner.OnSelectedValueChanged (EventArgs.Empty); + owner.OnSelectedIndexChanged (EventArgs.Empty); + } + + HideWindow (); + } + + internal override void OnPaintInternal (PaintEventArgs pevent) + { + Draw (pevent.ClipRectangle,pevent.Graphics); + } + + public bool ShowWindow () + { + if (owner.DropDownStyle == ComboBoxStyle.Simple && owner.Items.Count == 0) + return false; + + HighlightedIndex = owner.SelectedIndex; + + CalcListBoxArea (); + // If the listbox would extend below the screen, move it above the textbox. + Rectangle scrn_rect = Screen.FromControl (owner).Bounds; + if (this.Location.Y + this.Height >= scrn_rect.Bottom) + this.Location = new Point (this.Location.X, this.Location.Y - (this.Height + owner.TextArea.Height)); + Show (); + + Refresh (); + owner.OnDropDown (EventArgs.Empty); + return true; + } + + public void UpdateLastVisibleItem () + { + last_item = LastVisibleItem (); + } + + public void Scroll (int delta) + { + if (delta == 0 || vscrollbar_ctrl == null || !vscrollbar_ctrl.Visible) + return; + + int max = vscrollbar_ctrl.Maximum - page_size + 1; + + int val = vscrollbar_ctrl.Value + delta; + if (val > max) + val = max; + else if (val < vscrollbar_ctrl.Minimum) + val = vscrollbar_ctrl.Minimum; + vscrollbar_ctrl.Value = val; + } + + private void OnMouseWheelCLB (object sender, MouseEventArgs me) + { + if (owner.Items.Count == 0) + return; + + int lines = me.Delta / 120 * SystemInformation.MouseWheelScrollLines; + Scroll (-lines); + } + + // Value Changed + private void VerticalScrollEvent (object sender, EventArgs e) + { + if (top_item == vscrollbar_ctrl.Value) + return; + + top_item = vscrollbar_ctrl.Value; + UpdateLastVisibleItem (); + Invalidate (); + } + + protected override void WndProc(ref Message m) { + if (m.Msg == (int)Msg.WM_SETFOCUS) { + owner.Select (false, true); + } + base.WndProc (ref m); + } + + #endregion Private Methods + } + } +} diff --git a/source/ShiftUI/Widgets/ContainerControl.cs b/source/ShiftUI/Widgets/ContainerControl.cs new file mode 100644 index 0000000..5d02f46 --- /dev/null +++ b/source/ShiftUI/Widgets/ContainerControl.cs @@ -0,0 +1,850 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + public class ContainerWidget : ScrollableWidget, IContainerWidget { + private Widget active_Widget; + private Widget unvalidated_Widget; + private ArrayList pending_validation_chain; + + // This is an internal hack that allows some container Widgets + // to not auto select their child when they are activated + internal bool auto_select_child = true; + private SizeF auto_scale_dimensions; + private AutoScaleMode auto_scale_mode; + private bool auto_scale_mode_set; + private bool auto_scale_pending; + private bool is_auto_scaling; + + internal bool validation_failed; //track whether validation was cancelled by a validating Widget + + #region Public Constructors + public ContainerWidget() { + active_Widget = null; + unvalidated_Widget = null; + WidgetRemoved += new WidgetEventHandler(OnWidgetRemoved); + auto_scale_dimensions = SizeF.Empty; + auto_scale_mode = AutoScaleMode.Inherit; + } + #endregion // Public Constructors + + #region Public Instance Properties + [Browsable (false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Widget ActiveWidget { + get { + return active_Widget; + } + + set { + if (value==null || (active_Widget == value && active_Widget.Focused)) { + return; + } + + if (!Contains(value)) { + throw new ArgumentException("Cannot activate invisible or disabled Widget."); + } + + // Fire the enter and leave events if possible + Form form = FindForm (); + Widget active = GetMostDeeplyNestedActiveWidget (form == null ? this : form); + Widget common_ancestor = GetCommonContainer (active, value); + ArrayList chain = new ArrayList (); + ArrayList validation_chain = new ArrayList (); + Widget walk = active; + + // we split this up into three steps: + // 1. walk up the tree (if we need to) to our root, firing leave events. + // 2. validate. + // 3. walk down the tree (if we need to), firing enter events. + + // "our root" is either the common ancestor of the current active + // Widget and the new active Widget, or the current active Widget, + // or the new active Widget. That is, it's either one of these three + // configurations: + + // (1) root (2) new (3) current + // / \ / \ / \ + // ... ... ... ... ... ... + // / \ / \ + // current new current new + + + // note (3) doesn't require any upward walking, and no leave events are generated. + // (2) doesn't require any downward walking, and no enter events are generated. + + // as we walk up the tree, we generate a list of all Widgets which cause + // validation. After firing the leave events, we invoke (in order starting from + // the most deeply nested) their Validating event. If one sets CancelEventArgs.Cancel + // to true, we ignore the Widget the user wanted to set ActiveWidget to, and use + // the Validating Widget instead. + + bool fire_enter = true; + Widget root = common_ancestor; + + active_Widget = value; + + // Generate the leave messages + while (walk != common_ancestor && walk != null) { + if (walk == value) { + root = value; + fire_enter = false; + break; + } + walk.FireLeave (); + /* clear our idea of the active Widget as we go back up */ + if (walk is ContainerWidget) + ((ContainerWidget)walk).active_Widget = null; + + if (walk.CausesValidation) + validation_chain.Add (walk); + + walk = walk.Parent; + } + + // Validation can be postponed due to all the Widgets + // in the enter chain not causing validation. If we don't have any + // enter chain, it means that the selected Widget is a child and then + // we need to validate the Widgets anyway + bool postpone_validation; + Widget topmost_under_root = null; // topmost under root, in the *enter* chain + if (value == root) + postpone_validation = false; + else { + postpone_validation = true; + walk = value; + while (walk != root && walk != null) { + if (walk.CausesValidation) + postpone_validation = false; + + topmost_under_root = walk; + walk = walk.Parent; + } + } + + Widget failed_validation_Widget = PerformValidation (form == null ? this : form, postpone_validation, + validation_chain, topmost_under_root); + if (failed_validation_Widget != null) { + active_Widget = value = failed_validation_Widget; + fire_enter = true; + } + + if (fire_enter) { + walk = value; + while (walk != root && walk != null) { + chain.Add (walk); + walk = walk.Parent; + } + + if (root != null && walk == root && !(root is ContainerWidget)) + chain.Add (walk); + + for (int i = chain.Count - 1; i >= 0; i--) { + walk = (Widget) chain [i]; + walk.FireEnter (); + } + } + + walk = this; + Widget ctl = this; + while (walk != null) { + if (walk.Parent is ContainerWidget) { + ((ContainerWidget) walk.Parent).active_Widget = ctl; + ctl = walk.Parent; + } + walk = walk.Parent; + } + + if (this is Form) + CheckAcceptButton(); + + // Scroll Widget into view + ScrollWidgetIntoView(active_Widget); + + + walk = this; + ctl = this; + while (walk != null) { + if (walk.Parent is ContainerWidget) { + ctl = walk.Parent; + } + walk = walk.Parent; + } + + // Let the Widget know it's selected + if (ctl.InternalContainsFocus) + SendWidgetFocus (active_Widget); + } + } + + // Return the Widget where validation failed, and null otherwise + // @topmost_under_root is the Widget under the root in the enter chain, if any + // + // The process of validation happens as described: + // + // 1. Iterate over the nodes in the enter chain (walk down), looking for any node + // causing validation. If we can't find any, don't validate the current validation chain, but postpone it, + // saving it in the top_container.pending_validation_chain field, since we need to keep track of it later. + // If we have a previous pending_validation_chain, add the new nodes, making sure they are not repeated + // (this is computed in ActiveWidget and we receive if as the postpone_validation parameter). + // + // 2. If we found at least one node causing validation in the enter chain, try to validate the elements + // in pending_validation_chain, if any. Then continue with the ones receives as parameters. + // + // 3. Return null if all the validation performed successfully, and return the Widget where the validation + // failed otherwise. + // + private Widget PerformValidation (ContainerWidget top_container, bool postpone_validation, ArrayList validation_chain, + Widget topmost_under_root) + { + validation_failed = false; + + if (postpone_validation) { + AddValidationChain (top_container, validation_chain); + return null; + } + + // if not null, pending chain has always one element or more + if (top_container.pending_validation_chain != null) { + // if the topmost node in the enter chain is exactly the topmost + // int the validation chain, remove it, as .net does + int last_idx = top_container.pending_validation_chain.Count - 1; + if (topmost_under_root == top_container.pending_validation_chain [last_idx]) + top_container.pending_validation_chain.RemoveAt (last_idx); + + AddValidationChain (top_container, validation_chain); + validation_chain = top_container.pending_validation_chain; + top_container.pending_validation_chain = null; + } + + for (int i = 0; i < validation_chain.Count; i ++) { + if (!ValidateWidget ((Widget)validation_chain[i])) { + validation_failed = true; + return (Widget)validation_chain[i]; + } + } + + return null; + } + + // Add the elements in validation_chain to the pending validation chain stored in top_container + private void AddValidationChain (ContainerWidget top_container, ArrayList validation_chain) + { + if (validation_chain.Count == 0) + return; + + if (top_container.pending_validation_chain == null || top_container.pending_validation_chain.Count == 0) { + top_container.pending_validation_chain = validation_chain; + return; + } + + foreach (Widget c in validation_chain) + if (!top_container.pending_validation_chain.Contains (c)) + top_container.pending_validation_chain.Add (c); + } + + private bool ValidateWidget (Widget c) + { + CancelEventArgs e = new CancelEventArgs (); + + c.FireValidating (e); + + if (e.Cancel) + return false; + + c.FireValidated (); + return true; + } + + private Widget GetMostDeeplyNestedActiveWidget (ContainerWidget container) + { + Widget active = container.ActiveWidget; + while (active is ContainerWidget) { + if (((ContainerWidget)active).ActiveWidget == null) + break; + active = ((ContainerWidget)active).ActiveWidget; + } + return active; + } + + // Just in a separate method to make debugging a little easier, + // should eventually be rolled into ActiveWidget setter + private Widget GetCommonContainer (Widget active_Widget, Widget value) + { + Widget new_container = null; + Widget prev_container = active_Widget; + + while (prev_container != null) { + new_container = value.Parent; + while (new_container != null) { + if (new_container == prev_container) + return new_container; + new_container = new_container.Parent; + } + + prev_container = prev_container.Parent; + } + + return null; + } + + internal void SendWidgetFocus (Widget c) + { + if (c != null && c.IsHandleCreated) { + XplatUI.SetFocus (c.window.Handle); + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + [Localizable (true)] + public SizeF AutoScaleDimensions { + get { + return auto_scale_dimensions; + } + + set { + if (auto_scale_dimensions != value) { + auto_scale_dimensions = value; + + PerformAutoScale (); + } + } + } + + protected SizeF AutoScaleFactor { + get { + if (auto_scale_dimensions.IsEmpty) + return new SizeF (1f, 1f); + + return new SizeF(CurrentAutoScaleDimensions.Width / auto_scale_dimensions.Width, + CurrentAutoScaleDimensions.Height / auto_scale_dimensions.Height); + } + } + + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public AutoScaleMode AutoScaleMode { + get { + return auto_scale_mode; + } + set { + if (this is Form) + (this as Form).AutoScale = false; + + if (auto_scale_mode != value) { + auto_scale_mode = value; + + if (auto_scale_mode_set) + auto_scale_dimensions = SizeF.Empty; + + auto_scale_mode_set = true; + + PerformAutoScale (); + } + } + } + + [Browsable (false)] + public override BindingContext BindingContext { + get { + if (base.BindingContext == null) { + base.BindingContext = new BindingContext(); + } + return base.BindingContext; + } + + set { + base.BindingContext = value; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public SizeF CurrentAutoScaleDimensions { + get { + switch(auto_scale_mode) { + case AutoScaleMode.Dpi: + return TextRenderer.GetDpi (); + + case AutoScaleMode.Font: + Size s = TextRenderer.MeasureText ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890", Font); + int width = (int)Math.Round ((float)s.Width / 62f); + + return new SizeF (width, s.Height); + } + + return auto_scale_dimensions; + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Form ParentForm { + get { + Widget parent; + + parent = this.Parent; + + while (parent != null) { + if (parent is Form) { + return (Form)parent; + } + parent = parent.Parent; + } + + return null; + } + } + #endregion // Public Instance Properties + + #region Protected Instance Methods + protected override bool CanEnableIme { + get { return false; } + } + protected override CreateParams CreateParams { + get { + return base.CreateParams; + } + } + #endregion // Public Instance Methods + + #region Public Instance Methods + internal void PerformAutoScale (bool called_by_scale) + { + if ((AutoScaleMode == AutoScaleMode.Inherit) && !called_by_scale) + return; + + if ((layout_suspended > 0) && !called_by_scale) { + auto_scale_pending = true; + return; + } + // Set this first so we don't get called again from + // PerformDelayedAutoScale after ResumeLayout + auto_scale_pending = false; + + SizeF factor = AutoScaleFactor; + if (AutoScaleMode == AutoScaleMode.Inherit) { + ContainerWidget cc = FindContainer (this.Parent); + if (cc != null) + factor = cc.AutoScaleFactor; + } + if (factor != new SizeF (1F, 1F)) { + is_auto_scaling = true; + SuspendLayout (); + Scale (factor); + ResumeLayout (false); + is_auto_scaling = false; + } + + auto_scale_dimensions = CurrentAutoScaleDimensions; + } + + public void PerformAutoScale () + { + PerformAutoScale (false); + } + + internal void PerformDelayedAutoScale () + { + if (auto_scale_pending) + PerformAutoScale (); + } + + internal bool IsAutoScaling { + get { return is_auto_scaling; } + } + + [MonoTODO ("Stub, not implemented")] + static bool ValidateWarned; + public bool Validate() { + //throw new NotImplementedException(); + if (!ValidateWarned) { + Console.WriteLine("ContainerWidget.Validate is not yet implemented"); + ValidateWarned = true; + } + return true; + } + + public bool Validate (bool checkAutoValidate) + { + if ((checkAutoValidate && (AutoValidate != AutoValidate.Disable)) || !checkAutoValidate) + return Validate (); + + return true; + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public virtual bool ValidateChildren () + { + return ValidateChildren (ValidationConstraints.Selectable); + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public virtual bool ValidateChildren (ValidationConstraints validationConstraints) + { + bool recurse = !((validationConstraints & ValidationConstraints.ImmediateChildren) == ValidationConstraints.ImmediateChildren); + + foreach (Widget Widget in Widgets) + if (!ValidateNestedWidgets (Widget, validationConstraints, recurse)) + return false; + + return true; + } + + bool IContainerWidget.ActivateWidget(Widget Widget) { + return Select(Widget); + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void AdjustFormScrollbars(bool displayScrollbars) { + base.AdjustFormScrollbars(displayScrollbars); + } + + protected override void Dispose(bool disposing) { + base.Dispose(disposing); + } + + // LAMESPEC This used to be documented, but it's not in code + // and no longer listed in MSDN2 + // //[EditorBrowsable (EditorBrowsableState.Advanced)] + // protected override void OnWidgetRemoved(WidgetEventArgs e) { + private void OnWidgetRemoved(object sender, WidgetEventArgs e) { + if (e.Widget == this.unvalidated_Widget) { + this.unvalidated_Widget = null; + } + + if (e.Widget == this.active_Widget) { + this.unvalidated_Widget = null; + } + + // base.OnWidgetRemoved(e); + } + + protected override void OnCreateWidget() { + base.OnCreateWidget(); + // MS seems to call this here, it gets the whole databinding process started + OnBindingContextChanged (EventArgs.Empty); + } + + protected override bool ProcessCmdKey (ref Message msg, Keys keyData) + { + if (ToolStripManager.ProcessCmdKey (ref msg, keyData) == true) + return true; + + return base.ProcessCmdKey (ref msg, keyData); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override bool ProcessDialogChar(char charCode) { + if (GetTopLevel()) { + if (ProcessMnemonic(charCode)) { + return true; + } + } + return base.ProcessDialogChar(charCode); + } + + protected override bool ProcessDialogKey(Keys keyData) { + Keys key; + bool forward; + + key = keyData & Keys.KeyCode; + forward = true; + + switch (key) { + case Keys.Tab: { + if ((keyData & (Keys.Alt | Keys.Widget)) == Keys.None) { + if (ProcessTabKey ((Widget.ModifierKeys & Keys.Shift) == 0)) { + return true; + } + } + break; + } + + case Keys.Left: { + forward = false; + goto case Keys.Down; + } + + case Keys.Up: { + forward = false; + goto case Keys.Down; + } + + case Keys.Right: { + goto case Keys.Down; + } + case Keys.Down: { + if (SelectNextWidget(active_Widget, forward, false, false, true)) { + return true; + } + break; + } + + + } + return base.ProcessDialogKey(keyData); + } + + protected override bool ProcessMnemonic(char charCode) { + bool wrapped; + Widget c; + + wrapped = false; + c = active_Widget; + + do { + c = GetNextWidget(c, true); + if (c != null) { + // This is stupid. I want to be able to call c.ProcessMnemonic directly + if (c.ProcessWidgetMnemonic(charCode)) { + return(true); + } + continue; + } else { + if (wrapped) { + break; + } + wrapped = true; + } + } while (c != active_Widget); + + return false; + } + + protected virtual bool ProcessTabKey(bool forward) { + return SelectNextWidget(active_Widget, forward, true, true, false); + } + + protected override void Select(bool directed, bool forward) + { + if (Parent != null) { + IContainerWidget parent = Parent.GetContainerWidget (); + if (parent != null) { + parent.ActiveWidget = this; + } + } + + if (directed && auto_select_child) { + SelectNextWidget (null, forward, true, true, false); + } + } + + protected virtual void UpdateDefaultButton() { + // MS Internal + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void WndProc(ref Message m) { + switch ((Msg) m.Msg) { + + case Msg.WM_SETFOCUS: + if (active_Widget != null) + Select (active_Widget); + else + base.WndProc (ref m); + break; + + default: + base.WndProc(ref m); + break; + } + } + #endregion // Protected Instance Methods + + #region Internal Methods + internal void ChildWidgetRemoved (Widget Widget) + { + ContainerWidget top_container = FindForm (); + if (top_container == null) + top_container = this; + + // Remove Widgets -as well as any sub Widget- that was in the pending validation chain + ArrayList pending_validation_chain = top_container.pending_validation_chain; + if (pending_validation_chain != null) { + RemoveChildrenFromValidation (pending_validation_chain, Widget); + + if (pending_validation_chain.Count == 0) + top_container.pending_validation_chain = null; + } + + if (Widget == active_Widget || Widget.Contains (active_Widget)) { + SelectNextWidget (this, true, true, true, true); + if (Widget == active_Widget || Widget.Contains (active_Widget)) { + active_Widget = null; + } + } + } + + // Check that this Widget (or any child) is included in the pending validation chain + bool RemoveChildrenFromValidation (ArrayList validation_chain, Widget c) + { + if (RemoveFromValidationChain (validation_chain, c)) + return true; + + foreach (Widget child in c.Widgets) + if (RemoveChildrenFromValidation (validation_chain, child)) + return true; + + return false; + } + + // Remove the top most Widget in the pending validation chain, as well as any children there, + // taking advantage of the fact that the chain is in reverse order of the Widget's hierarchy + bool RemoveFromValidationChain (ArrayList validation_chain, Widget c) + { + int idx = validation_chain.IndexOf (c); + if (idx > -1) { + pending_validation_chain.RemoveAt (idx--); + return true; + } + + return false; + } + + internal virtual void CheckAcceptButton() + { + // do nothing here, only called if it is a Form + } + + private bool ValidateNestedWidgets (Widget c, ValidationConstraints constraints, bool recurse) + { + bool validate_result = true; + + if (!c.CausesValidation) + validate_result = true; + else if (!ValidateThisWidget (c, constraints)) + validate_result = true; + else if (!ValidateWidget (c)) + validate_result = false; + + if (recurse) + foreach (Widget Widget in c.Widgets) + if (!ValidateNestedWidgets (Widget, constraints, recurse)) + return false; + + return validate_result; + } + + private bool ValidateThisWidget (Widget c, ValidationConstraints constraints) + { + if (constraints == ValidationConstraints.None) + return true; + + if ((constraints & ValidationConstraints.Enabled) == ValidationConstraints.Enabled && !c.Enabled) + return false; + + if ((constraints & ValidationConstraints.Selectable) == ValidationConstraints.Selectable && !c.GetStyle (Widgetstyles.Selectable)) + return false; + + if ((constraints & ValidationConstraints.TabStop) == ValidationConstraints.TabStop && !c.TabStop) + return false; + + if ((constraints & ValidationConstraints.Visible) == ValidationConstraints.Visible && !c.Visible) + return false; + + return true; + } + #endregion // Internal Methods + + protected override void OnParentChanged (EventArgs e) + { + base.OnParentChanged (e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void OnFontChanged (EventArgs e) + { + base.OnFontChanged (e); + + if (AutoScaleMode == AutoScaleMode.Font) + PerformAutoScale (); + } + + protected override void OnLayout (LayoutEventArgs e) + { + base.OnLayout (e); + } + + AutoValidate auto_validate = AutoValidate.Inherit; + + [Browsable (false)] + [AmbientValue (AutoValidate.Inherit)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public virtual AutoValidate AutoValidate { + get { + return auto_validate; + } + + [MonoTODO("Currently does nothing with the setting")] + set { + if (auto_validate != value){ + auto_validate = value; + OnAutoValidateChanged (new EventArgs ()); + } + } + } + + internal bool ShouldSerializeAutoValidate () + { + return this.AutoValidate != AutoValidate.Inherit; + } + + static object OnValidateChanged = new object (); + + protected virtual void OnAutoValidateChanged (EventArgs e) + { + EventHandler eh = (EventHandler) (Events [OnValidateChanged]); + if (eh != null) + eh (this, e); + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public event EventHandler AutoValidateChanged { + add { Events.AddHandler (OnValidateChanged, value); } + remove { Events.RemoveHandler (OnValidateChanged, value); } + } + } +} diff --git a/source/ShiftUI/Widgets/DateTimePicker.cs b/source/ShiftUI/Widgets/DateTimePicker.cs new file mode 100644 index 0000000..183fd77 --- /dev/null +++ b/source/ShiftUI/Widgets/DateTimePicker.cs @@ -0,0 +1,2018 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// John BouAntoun jba-mono@optusnet.com.au +// Rolf Bjarne Kvinge rolfkvinge@ya.com +// +// TODO: +// - wire in all events from monthcalendar + + +using System; +using System.Drawing; +using System.Collections; +using System.ComponentModel; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Threading; + +namespace ShiftUI { + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [DefaultBindingProperty ("Value")] + [ComVisible (true)] + [DefaultEvent("ValueChanged")] + [DefaultProperty("Value")] + //[Designer("ShiftUI.Design.DateTimePickerDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [ToolboxWidget] + public class DateTimePicker : Widget { + + #region Public variables + + // this class has to have the specified hour, minute and second, as it says in msdn + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public static readonly DateTime MaxDateTime = new DateTime (9998, 12, 31, 0, 0, 0); + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public static readonly DateTime MinDateTime = new DateTime (1753, 1, 1); + + internal const int check_box_size = 13; + internal const int check_box_space = 4; + + #endregion // Public variables + + #region Local variables + + protected static readonly Color DefaultMonthBackColor = ThemeEngine.Current.ColorWindow; + protected static readonly Color DefaultTitleBackColor = ThemeEngine.Current.ColorActiveCaption; + protected static readonly Color DefaultTitleForeColor = ThemeEngine.Current.ColorActiveCaptionText; + protected static readonly Color DefaultTrailingForeColor = SystemColors.GrayText; + + internal MonthCalendar month_calendar; + bool is_checked; + string custom_format; + LeftRightAlignment drop_down_align; + DateTimePickerFormat format; + DateTime max_date; + DateTime min_date; + bool show_check_box; + bool show_up_down; + DateTime date_value; + bool right_to_left_layout; + + // variables used for drawing and such + internal const int up_down_width = check_box_size; + internal bool is_drop_down_visible; + internal bool is_up_pressed; + internal bool is_down_pressed; + internal Timer updown_timer; + internal const int initial_timer_delay = 500; + internal const int subsequent_timer_delay = 100; + internal bool is_checkbox_selected; + + // variables for determining how to format the string + internal PartData[] part_data; + internal int editing_part_index = -1; + internal int editing_number = -1; + internal string editing_text; + + bool drop_down_button_entered; + #endregion // Local variables + + #region DateTimePickerAccessibleObject Subclass + [ComVisible(true)] + public class DateTimePickerAccessibleObject : WidgetAccessibleObject { + #region DateTimePickerAccessibleObject Local Variables + private new DateTimePicker owner; + #endregion // DateTimePickerAccessibleObject Local Variables + + #region DateTimePickerAccessibleObject Constructors + public DateTimePickerAccessibleObject(DateTimePicker owner) : base(owner) { + this.owner = owner; + } + #endregion // DateTimePickerAccessibleObject Constructors + + #region DateTimePickerAccessibleObject Properties + public override string KeyboardShortcut { + get { + return base.KeyboardShortcut; + } + } + + public override AccessibleRole Role { + get { + return base.Role; + } + } + + public override AccessibleStates State { + get { + AccessibleStates retval; + + retval = AccessibleStates.Default; + + if (owner.Checked) { + retval |= AccessibleStates.Checked; + } + + return retval; + } + } + + public override string Value { + get { + return owner.Text; + } + } + #endregion // DateTimePickerAccessibleObject Properties + } + #endregion // DateTimePickerAccessibleObject Sub-class + + #region public constructors + + // only public constructor + public DateTimePicker () { + + // initialise the month calendar + month_calendar = new MonthCalendar (this); + month_calendar.CalendarDimensions = new Size (1, 1); + month_calendar.MaxSelectionCount = 1; + month_calendar.ForeColor = Widget.DefaultForeColor; + month_calendar.BackColor = DefaultMonthBackColor; + month_calendar.TitleBackColor = DefaultTitleBackColor; + month_calendar.TitleForeColor = DefaultTitleForeColor; + month_calendar.TrailingForeColor = DefaultTrailingForeColor; + month_calendar.Visible = false; + // initialize the timer + updown_timer = new Timer(); + updown_timer.Interval = initial_timer_delay; + + + // initialise other variables + is_checked = true; + custom_format = null; + drop_down_align = LeftRightAlignment.Left; + format = DateTimePickerFormat.Long; + max_date = MaxDateTime; + min_date = MinDateTime; + show_check_box = false; + show_up_down = false; + date_value = DateTime.Now; + + is_drop_down_visible = false; + BackColor = SystemColors.Window; + ForeColor = SystemColors.WindowText; + + month_calendar.DateChanged += new DateRangeEventHandler (MonthCalendarDateChangedHandler); + month_calendar.DateSelected += new DateRangeEventHandler (MonthCalendarDateSelectedHandler); + month_calendar.LostFocus += new EventHandler (MonthCalendarLostFocusHandler); + updown_timer.Tick += new EventHandler (UpDownTimerTick); + KeyPress += new KeyPressEventHandler (KeyPressHandler); + KeyDown += new KeyEventHandler (KeyDownHandler); + GotFocus += new EventHandler (GotFocusHandler); + LostFocus += new EventHandler (LostFocusHandler); + MouseDown += new MouseEventHandler (MouseDownHandler); + MouseUp += new MouseEventHandler (MouseUpHandler); + MouseEnter += new EventHandler (OnMouseEnter); + MouseLeave += new EventHandler (OnMouseLeave); + MouseMove += new MouseEventHandler (OnMouseMove); + Paint += new PaintEventHandler (PaintHandler); + Resize += new EventHandler (ResizeHandler); + SetStyle (Widgetstyles.UserPaint | Widgetstyles.StandardClick, false); + SetStyle (Widgetstyles.FixedHeight, true); + SetStyle (Widgetstyles.Selectable, true); + + CalculateFormats (); + } + + #endregion + + #region public properties + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override Color BackColor { + set { + base.BackColor = value; + } + get { + return base.BackColor; + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override Image BackgroundImage { + set { + base.BackgroundImage = value; + } + get { + return base.BackgroundImage; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override ImageLayout BackgroundImageLayout { + get{ + return base.BackgroundImageLayout; + } + set { + base.BackgroundImageLayout = value; + } + } + + [AmbientValue(null)] + [Localizable(true)] + public Font CalendarFont { + set { + month_calendar.Font = value; + } + get { + return month_calendar.Font; + } + } + + public Color CalendarForeColor { + set { + month_calendar.ForeColor = value; + } + get { + return month_calendar.ForeColor; + } + } + + public Color CalendarMonthBackground { + set { + month_calendar.BackColor = value; + } + get { + return month_calendar.BackColor; + } + } + + public Color CalendarTitleBackColor { + set { + month_calendar.TitleBackColor = value; + } + get { + return month_calendar.TitleBackColor; + } + } + + public Color CalendarTitleForeColor { + set { + month_calendar.TitleForeColor = value; + } + get { + return month_calendar.TitleForeColor; + } + } + + public Color CalendarTrailingForeColor { + set { + month_calendar.TrailingForeColor = value; + } + get { + return month_calendar.TrailingForeColor; + } + } + + // when checked the value is grayed out + [Bindable(true)] + [DefaultValue(true)] + public bool Checked { + set { + if (is_checked != value) { + is_checked = value; + // invalidate the value inside this control + if (ShowCheckBox) { + for (int i = 0; i < part_data.Length; i++) + part_data [i].Selected = false; + Invalidate (date_area_rect); + OnUIAChecked (); + OnUIASelectionChanged (); + } + } + } + get { + return is_checked; + } + } + + // the custom format string to format this control with + [Localizable (true)] + [DefaultValue(null)] + [RefreshProperties(RefreshProperties.Repaint)] + public string CustomFormat { + set { + if (custom_format != value) { + custom_format = value; + if (this.Format == DateTimePickerFormat.Custom) { + CalculateFormats (); + } + } + } + get { + return custom_format; + } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + protected override bool DoubleBuffered { + get { + return base.DoubleBuffered; + } + set { + base.DoubleBuffered = value; + } + } + + // which side the drop down is to be aligned on + [DefaultValue(LeftRightAlignment.Left)] + [Localizable(true)] + public LeftRightAlignment DropDownAlign { + set { + if (drop_down_align != value) { + drop_down_align = value; + } + } + get { + return drop_down_align; + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override Color ForeColor { + set { + base.ForeColor = value; + } + get { + return base.ForeColor; + } + } + + // the format of the date time picker text, default is long + [RefreshProperties(RefreshProperties.Repaint)] + public DateTimePickerFormat Format { + set { + if (format != value) { + format = value; + RecreateHandle (); // MS recreates the handle on every format change. + CalculateFormats (); + this.OnFormatChanged (EventArgs.Empty); + // invalidate the value inside this control + this.Invalidate (date_area_rect); + } + } + get { + return format; + } + } + + public DateTime MaxDate { + set { + if (value < min_date) { + string msg = string.Format (CultureInfo.CurrentCulture, + "'{0}' is not a valid value for 'MaxDate'. 'MaxDate' " + + "must be greater than or equal to MinDate.", + value.ToString ("G")); + throw new ArgumentOutOfRangeException ("MaxDate", msg); + } + if (value > MaxDateTime) { + string msg = string.Format (CultureInfo.CurrentCulture, + "DateTimePicker does not support dates after {0}.", + MaxDateTime.ToString ("G", CultureInfo.CurrentCulture)); + throw new ArgumentOutOfRangeException ("MaxDate", msg); + } + if (max_date != value) { + max_date = value; + if (Value > max_date) { + Value = max_date; + // invalidate the value inside this control + this.Invalidate (date_area_rect); + } + OnUIAMaximumChanged (); + } + } + get { + return max_date; + } + } + + public static DateTime MaximumDateTime { + get { + return MaxDateTime; + } + } + + public DateTime MinDate { + set { + // If the user tries to set DateTime.MinValue, fix it to + // DateTimePicker's minimum. + if (value == DateTime.MinValue) + value = MinDateTime; + + if (value > MaxDate) { + string msg = string.Format (CultureInfo.CurrentCulture, + "'{0}' is not a valid value for 'MinDate'. 'MinDate' " + + "must be less than MaxDate.", + value.ToString ("G")); + throw new ArgumentOutOfRangeException ("MinDate", msg); + } + if (value < MinDateTime) { + string msg = string.Format (CultureInfo.CurrentCulture, + "DateTimePicker does not support dates before {0}.", + MinDateTime.ToString ("G", CultureInfo.CurrentCulture)); + throw new ArgumentOutOfRangeException ("MinDate", msg); + } + if (min_date != value) { + min_date = value; + if (Value < min_date) { + Value = min_date; + // invalidate the value inside this control + this.Invalidate (date_area_rect); + } + OnUIAMinimumChanged (); + } + } + get { + return min_date; + } + } + + public static DateTime MinimumDateTime { + get { + return MinDateTime; + } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + [Browsable (false)] + public new Padding Padding { + get { return base.Padding; } + set { base.Padding = value; } + } + + // the prefered height to draw this control using current font + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int PreferredHeight { + get { + // Make it proportional + return (int) Math.Ceiling (Font.Height * 1.5); + } + } + + [DefaultValue (false)] + [Localizable (true)] + public virtual bool RightToLeftLayout { + get { + return right_to_left_layout; + } + set { + if (right_to_left_layout != value) { + right_to_left_layout = value; + OnRightToLeftLayoutChanged (EventArgs.Empty); + } + } + } + + // whether or not the check box is shown + [DefaultValue(false)] + public bool ShowCheckBox { + set { + if (show_check_box != value) { + show_check_box = value; + // invalidate the value inside this control + this.Invalidate (date_area_rect); + OnUIAShowCheckBoxChanged (); + } + } + get { + return show_check_box; + } + } + + // if true show the updown control, else popup the monthcalendar + [DefaultValue(false)] + public bool ShowUpDown { + set { + if (show_up_down != value) { + show_up_down = value; + // need to invalidate the whole control + this.Invalidate (); + OnUIAShowUpDownChanged (); + } + } + get { + return show_up_down; + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public override string Text { + set { + DateTime parsed_value; + + if (value == null || value == string.Empty) { + date_value = DateTime.Now; + OnValueChanged (EventArgs.Empty); + OnTextChanged (EventArgs.Empty); + return; + } + + if (format == DateTimePickerFormat.Custom) { + // TODO: if the format is a custom format we need to do a custom parse here + // This implementation will fail if the custom format is set to something that can + // be a standard datetime format string + // http://msdn2.microsoft.com/en-us/library/az4se3k1.aspx + parsed_value = DateTime.ParseExact (value, GetExactFormat (), null); + } else { + parsed_value = DateTime.ParseExact (value, GetExactFormat (), null); + } + + if (date_value != parsed_value) { + Value = parsed_value; + } + } + get { + if (!IsHandleCreated) + return ""; + + if (format == DateTimePickerFormat.Custom) { + System.Text.StringBuilder result = new System.Text.StringBuilder (); + for (int i = 0; i < part_data.Length; i++) { + result.Append(part_data[i].GetText(date_value)); + } + return result.ToString (); + } else { + return Value.ToString (GetExactFormat ()); + } + } + } + + [Bindable(true)] + [RefreshProperties(RefreshProperties.All)] + public DateTime Value { + set { + if (date_value != value) { + if (value < MinDate || value > MaxDate) + throw new ArgumentOutOfRangeException ("value", "value must be between MinDate and MaxDate"); + + date_value = value; + this.OnValueChanged (EventArgs.Empty); + this.Invalidate (date_area_rect); + } + } + get { + return date_value; + } + } + + #endregion // public properties + + #region public methods + + // just return the text value + public override string ToString () { + return this.Text; + } + + #endregion // public methods + + #region public events + static object CloseUpEvent = new object (); + static object DropDownEvent = new object (); + static object FormatChangedEvent = new object (); + static object ValueChangedEvent = new object (); + static object RightToLeftLayoutChangedEvent = new object (); + + // raised when the monthcalendar is closed + public event EventHandler CloseUp { + add { Events.AddHandler (CloseUpEvent, value); } + remove { Events.RemoveHandler (CloseUpEvent, value); } + } + + // raised when the monthcalendar is opened + public event EventHandler DropDown { + add { Events.AddHandler (DropDownEvent, value); } + remove { Events.RemoveHandler (DropDownEvent, value); } + } + + // raised when the format of the value is changed + public event EventHandler FormatChanged { + add { Events.AddHandler (FormatChangedEvent, value); } + remove { Events.RemoveHandler (FormatChangedEvent, value); } + } + + // raised when the date Value is changed + public event EventHandler ValueChanged { + add { Events.AddHandler (ValueChangedEvent, value); } + remove { Events.RemoveHandler (ValueChangedEvent, value); } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler BackColorChanged { + add { + base.BackColorChanged += value; + } + + remove { + base.BackColorChanged -= value; + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageChanged { + add { + base.BackgroundImageChanged += value; + } + + remove { + base.BackgroundImageChanged -= value; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageLayoutChanged { + add + { + base.BackgroundImageLayoutChanged += value; + } + + remove + { + base.BackgroundImageLayoutChanged -= value; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler Click { + add { + base.Click += value; + } + remove { + base.Click -= value; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler DoubleClick { + add { + base.DoubleClick += value; + } + remove { + base.DoubleClick -= value; + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler ForeColorChanged { + add { + base.ForeColorChanged += value; + } + + remove { + base.ForeColorChanged -= value; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event MouseEventHandler MouseClick { + add { + base.MouseClick += value; + } + remove { + base.MouseClick -= value; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event MouseEventHandler MouseDoubleClick { + add { + base.MouseDoubleClick += value; + } + remove { + base.MouseDoubleClick -= value; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler PaddingChanged { + add + { + base.PaddingChanged += value; + } + remove + { + base.PaddingChanged -= value; + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event PaintEventHandler Paint { + add { + base.Paint += value; + } + + remove { + base.Paint -= value; + } + } + + public event EventHandler RightToLeftLayoutChanged { + add { + Events.AddHandler (RightToLeftLayoutChangedEvent, value); + } + remove { + Events.RemoveHandler (RightToLeftLayoutChangedEvent, value); + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public new event EventHandler TextChanged { + add { + base.TextChanged += value; + } + + remove { + base.TextChanged -= value; + } + } + #endregion // public events + + #region protected properties + + // not sure why we're overriding this one + protected override CreateParams CreateParams { + get { + return base.CreateParams; + } + } + + // specify the default size for this control + protected override Size DefaultSize { + get { + // todo actually measure this properly + return new Size (200, PreferredHeight); + } + } + + #endregion // protected properties + + #region protected methods + + // not sure why we're overriding this one + protected override AccessibleObject CreateAccessibilityInstance () { + return base.CreateAccessibilityInstance (); + } + + // not sure why we're overriding this one + protected override void CreateHandle () { + base.CreateHandle (); + } + + // not sure why we're overriding this one + protected override void DestroyHandle () { + base.DestroyHandle (); + } + + // find out if this key is an input key for us, depends on which date part is focused + protected override bool IsInputKey (Keys keyData) { + switch (keyData) + { + case Keys.Up: + case Keys.Down: + case Keys.Left: + case Keys.Right: + return true; + } + return false; + } + + // raises the CloseUp event + protected virtual void OnCloseUp (EventArgs eventargs) { + EventHandler eh = (EventHandler)(Events [CloseUpEvent]); + if (eh != null) + eh (this, eventargs); + } + + // raise the drop down event + protected virtual void OnDropDown (EventArgs eventargs) { + EventHandler eh = (EventHandler)(Events [DropDownEvent]); + if (eh != null) + eh (this, eventargs); + } + + protected override void OnFontChanged(EventArgs e) { + // FIXME - do we need to update/invalidate/recalc our stuff? + month_calendar.Font = Font; + Size = new Size (Size.Width, PreferredHeight); + + base.OnFontChanged (e); + } + + // raises the format changed event + protected virtual void OnFormatChanged (EventArgs e) { + EventHandler eh = (EventHandler)(Events [FormatChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnHandleCreated (EventArgs e) { + base.OnHandleCreated(e); + } + protected override void OnHandleDestroyed (EventArgs e) { + base.OnHandleDestroyed(e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnRightToLeftLayoutChanged (EventArgs e) { + EventHandler eh = (EventHandler) Events [RightToLeftLayoutChangedEvent]; + if (eh != null) + eh (this, e); + } + + // not sure why we're overriding this one + protected override void OnSystemColorsChanged (EventArgs e) { + base.OnSystemColorsChanged (e); + } + + // raise the ValueChanged event + protected virtual void OnValueChanged (EventArgs eventargs) { + EventHandler eh = (EventHandler)(Events [ValueChangedEvent]); + if (eh != null) + eh (this, eventargs); + } + + // SetBoundsCore was removed from the 2.0 public API, so + // I had to do this hack instead. :/ + internal override int OverrideHeight (int height) + { + return DefaultSize.Height; + } + + // not sure why we're overriding this + protected override void WndProc (ref Message m) { + base.WndProc (ref m); + } + + #endregion // protected methods + + #region internal / private properties + + // this is the region that the date and the check box is drawn on + internal Rectangle date_area_rect { + get { + return ThemeEngine.Current.DateTimePickerGetDateArea (this); + } + } + + internal Rectangle CheckBoxRect { + get { + Rectangle retval = new Rectangle (check_box_space, ClientSize.Height / 2 - check_box_size / 2, + check_box_size, check_box_size); + return retval; + } + } + + // the rectangle for the drop down arrow + internal Rectangle drop_down_arrow_rect { + get { + return ThemeEngine.Current.DateTimePickerGetDropDownButtonArea (this); + } + } + + // the part of the date that is currently hilighted + internal Rectangle hilight_date_area { + get { + // TODO: put hilighted part calculation in here + return Rectangle.Empty; + } + } + + internal bool DropDownButtonEntered { + get { return drop_down_button_entered; } + } + + #endregion + + #region internal / private methods + + private void ResizeHandler (object sender, EventArgs e) + { + Invalidate (); + } + + private void UpDownTimerTick (object sender, EventArgs e) + { + if (updown_timer.Interval == initial_timer_delay) + updown_timer.Interval = subsequent_timer_delay; + + if (is_down_pressed) + IncrementSelectedPart (-1); + else if (is_up_pressed) + IncrementSelectedPart (1); + else + updown_timer.Enabled = false; + } + + // calculates the maximum width + internal Single CalculateMaxWidth(string format, Graphics gr, StringFormat string_format) + { + SizeF size; + float result = 0; + string text; + Font font = this.Font; + + switch (format) + { + case "M": + case "MM": + case "MMM": + case "MMMM": + for (int i = 1; i <= 12; i++) { + text = PartData.GetText (Value.AddMonths (i), format); + size = gr.MeasureString (text, font, int.MaxValue, string_format); + result = Math.Max (result, size.Width); + } + return result; + case "d": + case "dd": + case "ddd": + case "dddd": + for (int i = 1; i <= 12; i++) { + text = PartData.GetText (Value.AddDays (i), format); + size = gr.MeasureString (text, font, int.MaxValue, string_format); + result = Math.Max (result, size.Width); + } + return result; + case "h": + case "hh": + for (int i = 1; i <= 12; i++) { + text = PartData.GetText (Value.AddHours (i), format); + size = gr.MeasureString (text, font, int.MaxValue, string_format); + result = Math.Max (result, size.Width); + } + return result; + case "H": + case "HH": + for (int i = 1; i <= 24; i++) { + text = PartData.GetText (Value.AddDays (i), format); + size = gr.MeasureString (text, font, int.MaxValue, string_format); + result = Math.Max (result, size.Width); + } + return result; + case "m": + case "mm": + for (int i = 1; i <= 60; i++) { + text = PartData.GetText (Value.AddMinutes (i), format); + size = gr.MeasureString (text, font, int.MaxValue, string_format); + result = Math.Max (result, size.Width); + } + return result; + case "s": + case "ss": + for (int i = 1; i <= 60; i++) { + text = PartData.GetText (Value.AddSeconds (i), format); + size = gr.MeasureString (text, font, int.MaxValue, string_format); + result = Math.Max (result, size.Width); + } + return result; + case "t": + case "tt": + for (int i = 1; i <= 2; i++) { + text = PartData.GetText (Value.AddHours (i * 12), format); + size = gr.MeasureString (text, font, int.MaxValue, string_format); + result = Math.Max (result, size.Width); + } + return result; + case "y": + case "yy": + case "yyyy": + // Actually all the allowed year values are between MinDateTime and MaxDateTime, + // which are 4 digits always + text = PartData.GetText (Value, format); + size = gr.MeasureString (text, font, int.MaxValue, string_format); + result = Math.Max (result, size.Width); + return result; + default: + return gr.MeasureString (format, font, int.MaxValue, string_format).Width; + } + } + + // returns the format of the date as a string + // (i.e. resolves the Format enum values to it's corresponding string format) + // Why CurrentCulture and not CurrentUICulture is explained here: + // http://blogs.msdn.com/michkap/archive/2007/01/11/1449754.aspx + private string GetExactFormat() + { + switch (this.format) { + case DateTimePickerFormat.Long: + return Thread.CurrentThread.CurrentCulture.DateTimeFormat.LongDatePattern; + case DateTimePickerFormat.Short: + return Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern; + case DateTimePickerFormat.Time: + return Thread.CurrentThread.CurrentCulture.DateTimeFormat.LongTimePattern; + case DateTimePickerFormat.Custom: + return this.custom_format == null ? String.Empty : this.custom_format; + default: + return Thread.CurrentThread.CurrentCulture.DateTimeFormat.LongDatePattern; + } + } + + private void CalculateFormats() + { + string real_format; + System.Text.StringBuilder literal = new System.Text.StringBuilder (); + System.Collections.ArrayList formats = new ArrayList (); + bool is_literal = false; + char lastch = (char) 0; + char ch; + + real_format = GetExactFormat (); + + // parse the format string + for (int i = 0; i < real_format.Length; i++) + { + ch = real_format [i]; + + if (is_literal && ch != '\'') + { + literal.Append (ch); + continue; + } + + switch (ch) + { + case 't': + case 'd': + case 'h': + case 'H': + case 'm': + case 'M': + case 's': + case 'y': + case 'g': // Spec says nothing about g, but it seems to be treated like spaces. + if (!(lastch == ch || lastch == 0) && literal.Length != 0) + { + formats.Add (new PartData(literal.ToString (), false, this)); + literal.Length = 0; + } + literal.Append (ch); + break; + case '\'': + if (is_literal && i < real_format.Length - 1 && real_format [i + 1] == '\'') { + literal.Append (ch); + i++; + break; + } + if (literal.Length == 0) { + is_literal = !is_literal; + break; + } + formats.Add (new PartData (literal.ToString (), is_literal, this)); + literal.Length = 0; + is_literal = !is_literal; + break; + default: + if (literal.Length != 0) + { + formats.Add (new PartData(literal.ToString (), false, this)); + literal.Length = 0; + } + formats.Add (new PartData (ch.ToString(), true, this)); + break; + + } + lastch = ch; + } + if (literal.Length >= 0) + formats.Add (new PartData (literal.ToString (), is_literal, this)); + + part_data = new PartData [formats.Count]; + formats.CopyTo (part_data); + } + + private Point CalculateDropDownLocation (Rectangle parent_control_rect, Size child_size, bool align_left) + { + // default bottom left + Point location = new Point(parent_control_rect.Left + 5, parent_control_rect.Bottom); + // now adjust the alignment + if (!align_left) { + location.X = parent_control_rect.Right - child_size.Width; + } + + Point screen_location = PointToScreen (location); + Rectangle working_area = Screen.FromControl(this).WorkingArea; + // now adjust if off the right side of the screen + if (screen_location.X < working_area.X) { + screen_location.X = working_area.X; + } + // now adjust if it should be displayed above control + if (screen_location.Y + child_size.Height > working_area.Bottom) { + screen_location.Y -= (parent_control_rect.Height + child_size.Height); + } + + // since the parent of the month calendar is the form, adjust accordingly. + if (month_calendar.Parent != null) { + screen_location = month_calendar.Parent.PointToClient(screen_location); + } + + return screen_location; + } + + // actually draw this control + internal void Draw (Rectangle clip_rect, Graphics dc) + { + ThemeEngine.Current.DrawDateTimePicker (dc, clip_rect, this); + } + + // drop the calendar down + internal void DropDownMonthCalendar () + { + EndDateEdit (true); + // ensure the right date is set for the month_calendar + month_calendar.SetDate (this.date_value); + // get a rectangle that has the dimensions of the text area, + // but the height of the dtp control. + Rectangle align_area = this.date_area_rect; + align_area.Y = this.ClientRectangle.Y; + align_area.Height = this.ClientRectangle.Height; + + // establish the month calendar's location + month_calendar.Location = CalculateDropDownLocation ( + align_area, + month_calendar.Size, + (this.DropDownAlign == LeftRightAlignment.Left)); + month_calendar.Show (); + month_calendar.Focus (); + month_calendar.Capture = true; + + // fire any registered events + // XXX should this just call OnDropDown? + EventHandler eh = (EventHandler)(Events [DropDownEvent]); + if (eh != null) + eh (this, EventArgs.Empty); + } + + // hide the month calendar + internal void HideMonthCalendar () + { + this.is_drop_down_visible = false; + Invalidate (drop_down_arrow_rect); + month_calendar.Capture = false; + if (month_calendar.Visible) { + month_calendar.Hide (); + } + Focus (); + } + + private int GetSelectedPartIndex() + { + for (int i = 0; i < part_data.Length; i++) + { + if (part_data[i].Selected && !part_data[i].is_literal) + return i; + } + return -1; + } + + internal void IncrementSelectedPart(int delta) + { + int selected_index = GetSelectedPartIndex(); + + if (selected_index == -1) { + return; + } + + EndDateEdit (false); + + DateTimePart dt_part = part_data [selected_index].date_time_part; + switch (dt_part) + { + case DateTimePart.Day: + if (delta < 0) { + if (Value.Day == 1) + SetPart(DateTime.DaysInMonth(Value.Year, Value.Month), dt_part); + else + SetPart(Value.Day + delta, dt_part); + } else { + if (Value.Day == DateTime.DaysInMonth(Value.Year, Value.Month)) + SetPart(1, dt_part); + else + SetPart(Value.Day + delta, dt_part) ; + } + break; + case DateTimePart.DayName: + Value = Value.AddDays(delta); + break; + case DateTimePart.AMPMHour: + case DateTimePart.Hour: + SetPart(Value.Hour + delta, dt_part); + break; + case DateTimePart.Minutes: + SetPart(Value.Minute + delta, dt_part); + break; + case DateTimePart.Month: + SetPart (Value.Month + delta, dt_part, true); + break; + case DateTimePart.Seconds: + SetPart(Value.Second + delta, dt_part); + break; + case DateTimePart.AMPMSpecifier: + int hour = Value.Hour; + hour = hour >= 0 && hour <= 11 ? hour + 12 : hour - 12; + SetPart (hour, DateTimePart.Hour); + break; + case DateTimePart.Year: + SetPart(Value.Year + delta, dt_part); + break; + } + } + + internal void SelectPart (int index) + { + is_checkbox_selected = false; + for (int i = 0; i < part_data.Length; i++) + { + part_data[i].Selected = (i == index); + } + + Invalidate (); + OnUIASelectionChanged (); + } + + internal void SelectNextPart() + { + int selected_index; + if (is_checkbox_selected) { + for (int i = 0; i < part_data.Length; i++) + { + if (!part_data[i].is_literal) + { + is_checkbox_selected = false; + part_data[i].Selected = true; + Invalidate(); + break; + } + } + } else { + selected_index = GetSelectedPartIndex(); + if (selected_index >= 0) + part_data [selected_index].Selected = false; + + for (int i = selected_index + 1; i < part_data.Length; i++) + { + if (!part_data[i].is_literal) + { + part_data [i].Selected = true; + Invalidate(); + break; + } + } + if (GetSelectedPartIndex() == -1) + { // if no part was found before the end, look from the beginning + if (ShowCheckBox) + { + is_checkbox_selected = true; + Invalidate(); + } + else + { + for (int i = 0; i <= selected_index; i++) + { + if (!part_data[i].is_literal) + { + part_data[i].Selected = true; + Invalidate(); + break; + } + } + } + } + } + + OnUIASelectionChanged (); + } + + internal void SelectPreviousPart() + { + if (is_checkbox_selected) + { + for (int i = part_data.Length - 1; i >= 0; i--) + { + if (!part_data[i].is_literal) + { + is_checkbox_selected = false; + part_data[i].Selected = true; + Invalidate(); + break; + } + } + } + else + { + int selected_index = GetSelectedPartIndex(); + + if (selected_index >= 0) + part_data[selected_index].Selected = false; + + for (int i = selected_index - 1; i >= 0; i--) + { + if (!part_data[i].is_literal) + { + part_data[i].Selected = true; + Invalidate(); + break; + } + } + if (GetSelectedPartIndex() == -1) + { // if no part was found before the beginning, look from the end + if (ShowCheckBox) + { + is_checkbox_selected = true; + Invalidate(); + } + else + { + for (int i = part_data.Length - 1; i >= selected_index; i--) + { + if (!part_data[i].is_literal) + { + part_data[i].Selected = true; + Invalidate(); + break; + } + } + } + } + } + + OnUIASelectionChanged (); + } + + // raised by key down events. + private void KeyDownHandler(object sender, KeyEventArgs e) + { + switch (e.KeyCode) + { + case Keys.Add: + case Keys.Up: + { + if (ShowCheckBox && Checked == false) + break; + IncrementSelectedPart(1); + e.Handled = true; + break; + } + case Keys.Subtract: + case Keys.Down: + { + if (ShowCheckBox && Checked == false) + break; + IncrementSelectedPart(-1); + e.Handled = true; + break; + } + case Keys.Left: + {// select the next part to the left + if (ShowCheckBox && Checked == false) + break; + SelectPreviousPart(); + e.Handled = true; + break; + } + case Keys.Right: + {// select the next part to the right + if (ShowCheckBox && Checked == false) + break; + SelectNextPart(); + e.Handled = true; + break; + } + case Keys.F4: + if (!e.Alt && !is_drop_down_visible) { + DropDownMonthCalendar (); + e.Handled = true; + } + + break; + } + } + + // raised by any key down events + private void KeyPressHandler (object sender, KeyPressEventArgs e) + { + switch (e.KeyChar) { + case ' ': + if (show_check_box && is_checkbox_selected) + Checked = !Checked; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + int number = e.KeyChar - (int) '0'; + int selected_index = GetSelectedPartIndex(); + if (selected_index == -1) + break; + if (!part_data[selected_index].is_numeric_format) + break; + + DateTimePart dt_part = part_data [selected_index].date_time_part; + if (editing_part_index < 0) { + editing_part_index = selected_index; + editing_number = 0; + editing_text = String.Empty; + } + + editing_text += number.ToString (); + int date_part_max_length = 0; + + switch (dt_part) { + case DateTimePart.Day: + case DateTimePart.Month: + case DateTimePart.Seconds: + case DateTimePart.Minutes: + case DateTimePart.AMPMHour: + case DateTimePart.Hour: + date_part_max_length = 2; + break; + case DateTimePart.Year: + date_part_max_length = 4; + break; + } + + editing_number = editing_number * 10 + number; + if (editing_text.Length >= date_part_max_length) + EndDateEdit (false); + + Invalidate (date_area_rect); + break; + default: + break; + } + e.Handled = true; + } + + private void EndDateEdit (bool invalidate) + { + if (editing_part_index == -1) + return; + + PartData part = part_data [editing_part_index]; + if (part.date_time_part == DateTimePart.Year) { // Special case + // Infer, like .Net does + if (editing_number > 0 && editing_number < 30) + editing_number += 2000; + else if (editing_number >= 30 && editing_number < 100) + editing_number += 1900; + } + + SetPart (editing_number, part.date_time_part); + editing_part_index = editing_number = -1; + editing_text = null; + + if (invalidate) + Invalidate (date_area_rect); + } + + internal void SetPart (int value, DateTimePart dt_part) + { + SetPart (value, dt_part, false); + } + + // set the specified part of the date to the specified value + internal void SetPart (int value, DateTimePart dt_part, bool adjust) + { + switch (dt_part) + { + case DateTimePart.Seconds: + if (value == -1) + value = 59; + if (value >= 0 && value <= 59) + Value = new DateTime(Value.Year, Value.Month, Value.Day, Value.Hour, Value.Minute, value, Value.Millisecond); + break; + case DateTimePart.Minutes: + if (value == -1) + value = 59; + if (value >= 0 && value <= 59) + Value = new DateTime(Value.Year, Value.Month, Value.Day, Value.Hour, value, Value.Second, Value.Millisecond); + break; + case DateTimePart.AMPMHour: + if (value == -1) + value = 23; + if (value >= 0 && value <= 23) { + int prev_hour = Value.Hour; + if ((prev_hour >= 12 && prev_hour <= 23) && value < 12) // Adjust to p.m. + value += 12; + Value = new DateTime (Value.Year, Value.Month, Value.Day, value, Value.Minute, Value.Second, Value.Millisecond); + } + break; + case DateTimePart.Hour: + if (value == -1) + value = 23; + if (value >= 0 && value <= 23) + Value = new DateTime(Value.Year, Value.Month, Value.Day, value, Value.Minute, Value.Second, Value.Millisecond); + break; + case DateTimePart.Day: + int max_days = DateTime.DaysInMonth(Value.Year, Value.Month); + if (value >= 1 && value <= 31 && value <= max_days) + Value = new DateTime(Value.Year, Value.Month, value, Value.Hour, Value.Minute, Value.Second, Value.Millisecond); + break; + case DateTimePart.Month: + DateTime date = Value; + + if (adjust) { + if (value == 0) { + date = date.AddYears (-1); + value = 12; + } else if (value == 13) { + date = date.AddYears (1); + value = 1; + } + } + + if (value >= 1 && value <= 12) { + // if we move from say december to november with days on 31, we must + // remap to the maximum number of days + int days_in_new_month = DateTime.DaysInMonth (date.Year, value); + + if (date.Day > days_in_new_month) + Value = new DateTime (date.Year, value, days_in_new_month, date.Hour, date.Minute, date.Second, date.Millisecond); + else + Value = new DateTime (date.Year, value, date.Day, date.Hour, date.Minute, date.Second, date.Millisecond); + } + break; + case DateTimePart.Year: + if (value >= min_date.Year && value <= max_date.Year) { + // if we move to a leap year, the days in month could throw an exception + int days_in_new_month = DateTime.DaysInMonth (value, Value.Month); + + if (Value.Day > days_in_new_month) + Value = new DateTime (value, Value.Month, days_in_new_month, Value.Hour, Value.Minute, Value.Second, Value.Millisecond); + else + Value = new DateTime (value, Value.Month, Value.Day, Value.Hour, Value.Minute, Value.Second, Value.Millisecond); + } + break; + } + } + + private void GotFocusHandler (object sender, EventArgs e) + { + if (ShowCheckBox) { + is_checkbox_selected = true; + Invalidate (CheckBoxRect); + OnUIASelectionChanged (); + } + } + + // if we loose focus deselect any selected parts. + private void LostFocusHandler (object sender, EventArgs e) + { + int selected_index = GetSelectedPartIndex (); + if (selected_index != -1) + { + part_data [selected_index].Selected = false; + Rectangle invalidate_rect = Rectangle.Ceiling (part_data [selected_index].drawing_rectangle); + invalidate_rect.Inflate (2, 2); + Invalidate (invalidate_rect); + OnUIASelectionChanged (); + } + else if (is_checkbox_selected) + { + is_checkbox_selected = false; + Invalidate (CheckBoxRect); + OnUIASelectionChanged (); + } + } + + // if month calendar looses focus and the drop down is up, then close it + private void MonthCalendarLostFocusHandler(object sender, EventArgs e) + { + if (is_drop_down_visible && !month_calendar.Focused) + { + //this.HideMonthCalendar(); + //This is handled from the monthcalender itself, + //it may loose focus, but still has to be visible, + //for instance when the context menu is displayed. + } + + } + + private void MonthCalendarDateChangedHandler (object sender, DateRangeEventArgs e) + { + if (month_calendar.Visible) + this.Value = e.Start.Date.Add (this.Value.TimeOfDay); + } + + // fired when a user clicks on the month calendar to select a date + private void MonthCalendarDateSelectedHandler (object sender, DateRangeEventArgs e) + { + this.HideMonthCalendar (); + } + + private void MouseUpHandler(object sender, MouseEventArgs e) + { + if (ShowUpDown) + { + if (is_up_pressed || is_down_pressed) + { + updown_timer.Enabled = false; + is_up_pressed = false; + is_down_pressed = false; + Invalidate (drop_down_arrow_rect); + } + } + } + + // to check if the mouse has come down on this control + private void MouseDownHandler (object sender, MouseEventArgs e) + { + // Only left clicks are handled. + if (e.Button != MouseButtons.Left) + return; + + if (ShowCheckBox && CheckBoxRect.Contains(e.X, e.Y)) + { + is_checkbox_selected = true; + Checked = !Checked; + OnUIASelectionChanged (); + return; + } + + // Deselect the checkbox only if the pointer is not on it + // *and* the other parts are enabled (Checked as true) + if (Checked) { + is_checkbox_selected = false; + OnUIASelectionChanged (); + } + + if (ShowUpDown && drop_down_arrow_rect.Contains (e.X, e.Y)) + { + if (!(ShowCheckBox && Checked == false)) + { + if (e.Y < this.Height / 2) { + is_up_pressed = true; + is_down_pressed = false; + IncrementSelectedPart (1); + } else { + is_up_pressed = false; + is_down_pressed = true; + IncrementSelectedPart (-1); + } + Invalidate (drop_down_arrow_rect); + updown_timer.Interval = initial_timer_delay; + updown_timer.Enabled = true; + } + } else if (is_drop_down_visible == false && drop_down_arrow_rect.Contains (e.X, e.Y)) { + DropDownButtonClicked (); + } else { + // mouse down on this control anywhere else collapses it + if (is_drop_down_visible) { + HideMonthCalendar (); + } + if (!(ShowCheckBox && Checked == false)) + { + // go through the parts to see if the click is in any of them + bool invalidate_afterwards = false; + for (int i = 0; i < part_data.Length; i++) { + bool old = part_data [i].Selected; + + if (part_data [i].is_literal) + continue; + + if (part_data [i].drawing_rectangle.Contains (e.X, e.Y)) { + part_data [i].Selected = true; + } else + part_data [i].Selected = false; + + if (old != part_data [i].Selected) + invalidate_afterwards = true; + } + if (invalidate_afterwards) { + Invalidate (); + OnUIASelectionChanged (); + } + } + + } + } + + internal void DropDownButtonClicked () + { + if (!is_drop_down_visible) { + is_drop_down_visible = true; + if (!Checked) + Checked = true; + Invalidate (drop_down_arrow_rect); + DropDownMonthCalendar (); + } else { + HideMonthCalendar (); + } + } + + // paint this control now + private void PaintHandler (object sender, PaintEventArgs pe) { + if (Width <= 0 || Height <= 0 || Visible == false) + return; + + Draw (pe.ClipRectangle, pe.Graphics); + } + + void OnMouseEnter (object sender, EventArgs e) + { + if (ThemeEngine.Current.DateTimePickerBorderHasHotElementStyle) + Invalidate (); + } + + void OnMouseLeave (object sender, EventArgs e) + { + drop_down_button_entered = false; + if (ThemeEngine.Current.DateTimePickerBorderHasHotElementStyle) + Invalidate (); + } + + void OnMouseMove (object sender, MouseEventArgs e) + { + if (!is_drop_down_visible && + ThemeEngine.Current.DateTimePickerDropDownButtonHasHotElementStyle && + drop_down_button_entered != drop_down_arrow_rect.Contains (e.Location)) { + drop_down_button_entered = !drop_down_button_entered; + Invalidate (drop_down_arrow_rect); + } + } + #endregion + + #region internal classes + internal enum DateTimePart { + Seconds, + Minutes, + AMPMHour, + Hour, + Day, + DayName, + Month, + Year, + AMPMSpecifier, + Literal + } + + internal class PartData + { + internal string value; + internal bool is_literal; + bool is_selected; + internal RectangleF drawing_rectangle; + internal DateTimePart date_time_part; + DateTimePicker owner; + + internal bool is_numeric_format + { + get + { + if (is_literal) + return false; + switch (value) { + case "m": + case "mm": + case "d": + case "dd": + case "h": + case "hh": + case "H": + case "HH": + case "M": + case "MM": + case "s": + case "ss": + case "y": + case "yy": + case "yyyy": + return true; + case "ddd": + case "dddd": + return false; + default: + return false; + } + } + } + + internal PartData(string value, bool is_literal, DateTimePicker owner) + { + this.value = value; + this.is_literal = is_literal; + this.owner = owner; + date_time_part = GetDateTimePart (value); + } + + internal bool Selected { + get { + return is_selected; + } + set { + if (value == is_selected) + return; + + owner.EndDateEdit (false); + is_selected = value; + } + } + + // calculate the string to show for this data + internal string GetText(DateTime date) + { + if (is_literal) { + return value; + } else { + return GetText (date, value); + } + } + + static DateTimePart GetDateTimePart (string value) + { + switch (value) { + case "s": + case "ss": + return DateTimePart.Seconds; + case "m": + case "mm": + return DateTimePart.Minutes; + case "h": + case "hh": + return DateTimePart.AMPMHour; + case "H": + case "HH": + return DateTimePart.Hour; + case "d": + case "dd": + return DateTimePart.Day; + case "ddd": + case "dddd": + return DateTimePart.DayName; + case "M": + case "MM": + case "MMMM": + return DateTimePart.Month; + case "y": + case "yy": + case "yyy": + case "yyyy": + return DateTimePart.Year; + case "t": + case "tt": + return DateTimePart.AMPMSpecifier; + } + + return DateTimePart.Literal; + } + + static internal string GetText(DateTime date, string format) + { + if (format.StartsWith ("g")) + return " "; + else if (format.Length == 1) + return date.ToString ("%" + format); + else if (format == "yyyyy" || format == "yyyyyy" || format == "yyyyyyy" || format == "yyyyyyyy") + return date.ToString ("yyyy"); + else if (format.Length > 1) + return date.ToString (format); + else + return string.Empty; + } + } + + #endregion + + #region UIA Framework: Methods, Properties and Events + + internal bool UIAIsCheckBoxSelected { + get { return is_checkbox_selected; } + } + + static object UIAMinimumChangedEvent = new object (); + static object UIAMaximumChangedEvent = new object (); + static object UIASelectionChangedEvent = new object (); + static object UIACheckedEvent = new object (); + static object UIAShowCheckBoxChangedEvent = new object (); + static object UIAShowUpDownChangedEvent = new object (); + + internal event EventHandler UIAMinimumChanged { + add { Events.AddHandler (UIAMinimumChangedEvent, value); } + remove { Events.RemoveHandler (UIAMinimumChangedEvent, value); } + } + + internal event EventHandler UIAMaximumChanged { + add { Events.AddHandler (UIAMinimumChangedEvent, value); } + remove { Events.RemoveHandler (UIAMinimumChangedEvent, value); } + } + + internal event EventHandler UIASelectionChanged { + add { Events.AddHandler (UIASelectionChangedEvent, value); } + remove { Events.RemoveHandler (UIASelectionChangedEvent, value); } + } + + internal event EventHandler UIAChecked { + add { Events.AddHandler (UIACheckedEvent, value); } + remove { Events.RemoveHandler (UIACheckedEvent, value); } + } + + internal event EventHandler UIAShowCheckBoxChanged { + add { Events.AddHandler (UIAShowCheckBoxChangedEvent, value); } + remove { Events.RemoveHandler (UIAShowCheckBoxChangedEvent, value); } + } + + internal event EventHandler UIAShowUpDownChanged { + add { Events.AddHandler (UIAShowUpDownChangedEvent, value); } + remove { Events.RemoveHandler (UIAShowUpDownChangedEvent, value); } + } + + internal void OnUIAMinimumChanged () + { + EventHandler eh = (EventHandler)(Events [UIAMinimumChangedEvent]); + if (eh != null) + eh (this, EventArgs.Empty); + } + + internal void OnUIAMaximumChanged () + { + EventHandler eh = (EventHandler)(Events [UIAMaximumChangedEvent]); + if (eh != null) + eh (this, EventArgs.Empty); + } + + internal void OnUIASelectionChanged () + { + EventHandler eh = (EventHandler)(Events [UIASelectionChangedEvent]); + if (eh != null) + eh (this, EventArgs.Empty); + } + + internal void OnUIAChecked () + { + EventHandler eh = (EventHandler)(Events [UIACheckedEvent]); + if (eh != null) + eh (this, EventArgs.Empty); + } + + internal void OnUIAShowCheckBoxChanged () + { + EventHandler eh = (EventHandler)(Events [UIAShowCheckBoxChangedEvent]); + if (eh != null) + eh (this, EventArgs.Empty); + } + + internal void OnUIAShowUpDownChanged () + { + EventHandler eh = (EventHandler)(Events [UIAShowUpDownChangedEvent]); + if (eh != null) + eh (this, EventArgs.Empty); + } + + #endregion + } +} diff --git a/source/ShiftUI/Widgets/FlowLayoutPanel.cs b/source/ShiftUI/Widgets/FlowLayoutPanel.cs new file mode 100644 index 0000000..680cc57 --- /dev/null +++ b/source/ShiftUI/Widgets/FlowLayoutPanel.cs @@ -0,0 +1,197 @@ +// +// FlowLayoutPanel.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using ShiftUI.Layout; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Drawing; +using System; + +namespace ShiftUI +{ + [ComVisibleAttribute (true)] + [ClassInterfaceAttribute (ClassInterfaceType.AutoDispatch)] + [ProvideProperty ("FlowBreak", typeof (Widget))] + [DefaultProperty ("FlowDirection")] + [Docking (DockingBehavior.Ask)] + //[Designer ("ShiftUI.Design.FlowLayoutPanelDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [ToolboxWidget] + public class FlowLayoutPanel : Panel, IExtenderProvider + { + private FlowLayoutSettings settings; + + public FlowLayoutPanel () : base () + { + CreateDockPadding (); + } + + #region Properties + [Localizable (true)] + [DefaultValue (FlowDirection.LeftToRight)] + public FlowDirection FlowDirection { + get { return LayoutSettings.FlowDirection; } + set { LayoutSettings.FlowDirection = value; } + } + + [LocalizableAttribute (true)] + [DefaultValue (true)] + public bool WrapContents { + get { return LayoutSettings.WrapContents; } + set { LayoutSettings.WrapContents = value; } + } + + public override LayoutEngine LayoutEngine { + get { return this.LayoutSettings.LayoutEngine; } + } + + internal FlowLayoutSettings LayoutSettings { + get { + if (this.settings == null) + this.settings = new FlowLayoutSettings (this); + + return this.settings; + } + } + #endregion + + #region Public Methods + [DefaultValue (false)] + [DisplayName ("FlowBreak")] + public bool GetFlowBreak (Widget control) + { + return LayoutSettings.GetFlowBreak (control); + } + + [DisplayName ("FlowBreak")] + public void SetFlowBreak (Widget control, bool value) + { + LayoutSettings.SetFlowBreak (control, value); + } + #endregion + + #region IExtenderProvider Members + bool IExtenderProvider.CanExtend (object obj) + { + if (obj is Widget) + if ((obj as Widget).Parent == this) + return true; + + return false; + } + #endregion + + #region Internal Methods + internal override void CalculateCanvasSize (bool canOverride) + { + if (canOverride) + canvas_size = ClientSize; + else + base.CalculateCanvasSize (canOverride); + } + + protected override void OnLayout (LayoutEventArgs levent) + { + base.OnLayout (levent); + + // base.OnLayout() calls CalculateCanvasSize(true) in which we just set the canvas to + // clientsize so we could re-layout everything according to the flow. + // This time we want to actually calculate the canvas. + CalculateCanvasSize (false); + if (AutoSize && (canvas_size.Width > ClientSize.Width || canvas_size.Height > ClientSize.Height)) { + ClientSize = canvas_size; + } + AdjustFormScrollbars (AutoScroll); + } + + internal override Size GetPreferredSizeCore (Size proposedSize) + { + int width = 0; + int height = 0; + bool horizontal = FlowDirection == FlowDirection.LeftToRight || FlowDirection == FlowDirection.RightToLeft; + if (!WrapContents || (horizontal && proposedSize.Width == 0) || (!horizontal && proposedSize.Height == 0)) { + foreach (Widget control in Widgets) { + Size control_preferred_size; + if (control.AutoSize) + control_preferred_size = control.PreferredSize; + else + control_preferred_size = control.Size; + Padding control_margin = control.Margin; + if (horizontal) { + width += control_preferred_size.Width + control_margin.Horizontal; + height = Math.Max (height, control_preferred_size.Height + control_margin.Vertical); + } else { + height += control_preferred_size.Height + control_margin.Vertical; + width = Math.Max (width, control_preferred_size.Width + control_margin.Horizontal); + } + } + } else { + int size_in_flow_direction = 0; + int size_in_other_direction = 0; + int increase; + foreach (Widget control in Widgets) { + Size control_preferred_size; + if (control.AutoSize) + control_preferred_size = control.PreferredSize; + else + control_preferred_size = control.ExplicitBounds.Size; + Padding control_margin = control.Margin; + if (horizontal) { + increase = control_preferred_size.Width + control_margin.Horizontal; + if (size_in_flow_direction != 0 && size_in_flow_direction + increase >= proposedSize.Width) { + width = Math.Max (width, size_in_flow_direction); + size_in_flow_direction = 0; + height += size_in_other_direction; + size_in_other_direction = 0; + } + size_in_flow_direction += increase; + size_in_other_direction = Math.Max (size_in_other_direction, control_preferred_size.Height + control_margin.Vertical); + } else { + increase = control_preferred_size.Height + control_margin.Vertical; + if (size_in_flow_direction != 0 && size_in_flow_direction + increase >= proposedSize.Height) { + height = Math.Max (height, size_in_flow_direction); + size_in_flow_direction = 0; + width += size_in_other_direction; + size_in_other_direction = 0; + } + size_in_flow_direction += increase; + size_in_other_direction = Math.Max (size_in_other_direction, control_preferred_size.Width + control_margin.Horizontal); + } + } + if (horizontal) { + width = Math.Max (width, size_in_flow_direction); + height += size_in_other_direction; + } else { + height = Math.Max (height, size_in_flow_direction); + width += size_in_other_direction; + } + } + return new Size (width, height); + } + #endregion + } +} diff --git a/source/ShiftUI/Widgets/GridEntry.cs b/source/ShiftUI/Widgets/GridEntry.cs new file mode 100644 index 0000000..619bb4c --- /dev/null +++ b/source/ShiftUI/Widgets/GridEntry.cs @@ -0,0 +1,860 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2008 Novell, Inc. +// +// Authors: +// Jonathan Chambers (jonathan.chambers@ansys.com) +// Ivan N. Zlatev (contact@i-nz.net) +// + +// NOT COMPLETE + +using System; +using System.Collections; +using System.Drawing; +using System.Drawing.Design; +using ShiftUI; +using ShiftUI.Design; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Globalization; + +namespace ShiftUI.PropertyGridInternal +{ + internal class GridEntry : GridItem, ITypeDescriptorContext + { + #region Local Variables + private PropertyGrid property_grid; + private bool expanded; + private GridItemCollection grid_items; + private GridItem parent; + private PropertyDescriptor[] property_descriptors; + private int top; + private Rectangle plus_minus_bounds; + private GridItemCollection child_griditems_cache; + #endregion // Local Variables + + #region Contructors + protected GridEntry (PropertyGrid propertyGrid, GridEntry parent) + { + if (propertyGrid == null) + throw new ArgumentNullException ("propertyGrid"); + property_grid = propertyGrid; + plus_minus_bounds = new Rectangle (0,0,0,0); + top = -1; + grid_items = new GridItemCollection (); + expanded = false; + this.parent = parent; + child_griditems_cache = null; + } + + // Cannot use one PropertyDescriptor for all owners, because the + // propertydescriptors might have different Invokees. Check + // ReflectionPropertyDescriptor.GetInvokee and how it's used. + // + public GridEntry (PropertyGrid propertyGrid, PropertyDescriptor[] properties, + GridEntry parent) : this (propertyGrid, parent) + { + if (properties == null || properties.Length == 0) + throw new ArgumentNullException ("prop_desc"); + property_descriptors = properties; + } + #endregion // Constructors + + + public override bool Expandable { + get { + TypeConverter converter = GetConverter (); + if (converter == null || !converter.GetPropertiesSupported ((ITypeDescriptorContext)this)) + return false; + + if (GetChildGridItemsCached ().Count > 0) + return true; + + return false; + } + } + + public override bool Expanded { + get { return expanded; } + set { + if (expanded != value) { + expanded = value; + PopulateChildGridItems (); + if (value) + property_grid.OnExpandItem (this); + else + property_grid.OnCollapseItem (this); + } + } + } + + public override GridItemCollection GridItems { + get { + PopulateChildGridItems (); + return grid_items; + } + } + + public override GridItemType GridItemType { + get { return GridItemType.Property; } + } + + public override string Label { + get { + PropertyDescriptor property = this.PropertyDescriptor; + if (property != null) { + string label = property.DisplayName; + ParenthesizePropertyNameAttribute parensAttr = + property.Attributes[typeof (ParenthesizePropertyNameAttribute)] as ParenthesizePropertyNameAttribute; + if (parensAttr != null && parensAttr.NeedParenthesis) + label = "(" + label + ")"; + return label; + } + return String.Empty; + } + } + + public override GridItem Parent { + get { return parent; } + } + + public GridEntry ParentEntry { + get { + if (parent != null && parent.GridItemType == GridItemType.Category) + return parent.Parent as GridEntry; + return parent as GridEntry; + } + } + + public override PropertyDescriptor PropertyDescriptor { + get { return property_descriptors != null ? property_descriptors[0] : null; } + } + + public PropertyDescriptor[] PropertyDescriptors { + get { return property_descriptors; } + } + + public object PropertyOwner { + get { + object[] owners = PropertyOwners; + if (owners != null) + return owners[0]; + return null; + } + } + + public object[] PropertyOwners { + get { + if (ParentEntry == null) + return null; + + object[] owners = ParentEntry.Values; + PropertyDescriptor[] properties = PropertyDescriptors; + object newOwner = null; + for (int i=0; i < owners.Length; i++) { + if (owners[i] is ICustomTypeDescriptor) { + newOwner = ((ICustomTypeDescriptor)owners[i]).GetPropertyOwner (properties[i]); + if (newOwner != null) + owners[i] = newOwner; + } + } + return owners; + } + } + + // true if the value is the same among all properties + public bool HasMergedValue { + get { + if (!IsMerged) + return false; + + object[] values = this.Values; + for (int i=0; i+1 < values.Length; i++) { + if (!Object.Equals (values[i], values[i+1])) + return false; + } + return true; + } + } + + public virtual bool IsMerged { + get { return (PropertyDescriptors != null && PropertyDescriptors.Length > 1); } + } + + // If IsMerged this will return all values for all properties in all owners + public virtual object[] Values { + get { + if (PropertyDescriptor == null || this.PropertyOwners == null) + return null; + if (IsMerged) { + object[] owners = this.PropertyOwners; + PropertyDescriptor[] properties = PropertyDescriptors; + object[] values = new object[owners.Length]; + for (int i=0; i < owners.Length; i++) + values[i] = properties[i].GetValue (owners[i]); + return values; + } else { + return new object[] { this.Value }; + } + } + } + + // Returns the first value for the first propertyowner and propertydescriptor + // + public override object Value { + get { + if (PropertyDescriptor == null || PropertyOwner == null) + return null; + + return PropertyDescriptor.GetValue (PropertyOwner); + } + set + { + PropertyDescriptor.SetValue(PropertyOwner, value); + } + } + + public string ValueText { + get { + string text = null; + try { + text = ConvertToString (this.Value); + if (text == null) + text = String.Empty; + } catch { + text = String.Empty; + } + return text; + } + } + + public override bool Select () + { + property_grid.SelectedGridItem = this; + return true; + } + + #region ITypeDescriptorContext + void ITypeDescriptorContext.OnComponentChanged () + { + } + + bool ITypeDescriptorContext.OnComponentChanging () + { + return false; + } + + IContainer ITypeDescriptorContext.Container { + get { + if (PropertyOwner == null) + return null; + + IComponent component = property_grid.SelectedObject as IComponent; + if (component != null && component.Site != null) + return component.Site.Container; + return null; + } + } + + object ITypeDescriptorContext.Instance { + get { + if (ParentEntry != null && ParentEntry.PropertyOwner != null) + return ParentEntry.PropertyOwner; + return PropertyOwner; + } + } + + PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor { + get { + if (ParentEntry != null && ParentEntry.PropertyDescriptor != null) + return ParentEntry.PropertyDescriptor; + return PropertyDescriptor; + } + } + #endregion + + #region IServiceProvider Members + + object IServiceProvider.GetService (Type serviceType) { + IComponent selectedComponent = property_grid.SelectedObject as IComponent; + if (selectedComponent != null && selectedComponent.Site != null) + return selectedComponent.Site.GetService (serviceType); + return null; + } + + #endregion + + internal int Top { + get { return top; } + set { + if (top != value) + top = value; + } + } + + internal Rectangle PlusMinusBounds { + get { return plus_minus_bounds; } + set { plus_minus_bounds = value; } + } + + public void SetParent (GridItem parent) + { + this.parent = parent; + } + + public ICollection AcceptedValues { + get { + TypeConverter converter = GetConverter (); + if (PropertyDescriptor != null && converter != null && + converter.GetStandardValuesSupported ((ITypeDescriptorContext)this)) { + ArrayList values = new ArrayList (); + string stringVal = null; + ICollection standardValues = converter.GetStandardValues ((ITypeDescriptorContext)this); + if (standardValues != null) { + foreach (object value in standardValues) { + stringVal = ConvertToString (value); + if (stringVal != null) + values.Add (stringVal); + } + } + return values.Count > 0 ? values : null; + } + return null; + } + } + + private string ConvertToString (object value) + { + if (value is string) + return (string)value; + + if (PropertyDescriptor != null && PropertyDescriptor.Converter != null && + PropertyDescriptor.Converter.CanConvertTo ((ITypeDescriptorContext)this, typeof (string))) { + try { + return PropertyDescriptor.Converter.ConvertToString ((ITypeDescriptorContext)this, value); + } catch { + // XXX: Happens too often... + // property_grid.ShowError ("Property value of '" + property_descriptor.Name + "' is not convertible to string."); + return null; + } + } + + return null; + } + + public bool HasCustomEditor { + get { return EditorStyle != UITypeEditorEditStyle.None; } + } + + public UITypeEditorEditStyle EditorStyle { + get { + UITypeEditor editor = GetEditor (); + if (editor != null) { + try { + return editor.GetEditStyle ((ITypeDescriptorContext)this); + } catch { + // Some of our Editors throw NotImplementedException + } + } + return UITypeEditorEditStyle.None; + } + } + + public bool EditorResizeable { + get { + if (this.EditorStyle == UITypeEditorEditStyle.DropDown) { + UITypeEditor editor = GetEditor (); + if (editor != null && editor.IsDropDownResizable) + return true; + } + return false; + } + } + + public bool EditValue (IWindowsFormsEditorService service) + { + if (service == null) + throw new ArgumentNullException ("service"); + + IServiceContainer parent = ((ITypeDescriptorContext)this).GetService (typeof (IServiceContainer)) as IServiceContainer; + ServiceContainer container = null; + + if (parent != null) + container = new ServiceContainer (parent); + else + container = new ServiceContainer (); + + container.AddService (typeof (IWindowsFormsEditorService), service); + + UITypeEditor editor = GetEditor (); + if (editor != null) { + try { + object value = editor.EditValue ((ITypeDescriptorContext)this, + container, + this.Value); + string error = null; + return SetValue (value, out error); + } catch { //(Exception e) { + // property_grid.ShowError (e.Message + Environment.NewLine + e.StackTrace); + } + } + return false; + } + + private UITypeEditor GetEditor () + { + if (PropertyDescriptor != null) { + try { // can happen, because we are missing some editors + if (PropertyDescriptor != null) + return (UITypeEditor) PropertyDescriptor.GetEditor (typeof (UITypeEditor)); + } catch { + // property_grid.ShowError ("Unable to load UITypeEditor for property '" + PropertyDescriptor.Name + "'."); + } + } + return null; + } + + private TypeConverter GetConverter () + { + if (PropertyDescriptor != null) + return PropertyDescriptor.Converter; + return null; + } + + public bool ToggleValue () + { + if (IsReadOnly || (IsMerged && !HasMergedValue)) + return false; + + bool success = false; + string error = null; + object value = this.Value; + if (PropertyDescriptor.PropertyType == typeof(bool)) + success = SetValue (!(bool)value, out error); + else { + TypeConverter converter = GetConverter (); + if (converter != null && + converter.GetStandardValuesSupported ((ITypeDescriptorContext)this)) { + TypeConverter.StandardValuesCollection values = + (TypeConverter.StandardValuesCollection) converter.GetStandardValues ((ITypeDescriptorContext)this); + if (values != null) { + for (int i = 0; i < values.Count; i++) { + if (value != null && value.Equals (values[i])){ + if (i < values.Count-1) + success = SetValue (values[i+1], out error); + else + success = SetValue (values[0], out error); + break; + } + } + } + } + } + if (!success && error != null) + property_grid.ShowError (error); + return success; + } + + public bool SetValue (object value, out string error) + { + error = null; + if (this.IsReadOnly) + return false; + + if (SetValueCore (value, out error)) { + InvalidateChildGridItemsCache (); + property_grid.OnPropertyValueChangedInternal (this, this.Value); + return true; + } + return false; + } + + protected virtual bool SetValueCore (object value, out string error) + { + error = null; + + TypeConverter converter = GetConverter (); + Type valueType = value != null ? value.GetType () : null; + // if the new value is not of the same type try to convert it + if (valueType != null && this.PropertyDescriptor.PropertyType != null && + !this.PropertyDescriptor.PropertyType.IsAssignableFrom (valueType)) { + bool conversionError = false; + try { + if (converter != null && + converter.CanConvertFrom ((ITypeDescriptorContext)this, valueType)) + value = converter.ConvertFrom ((ITypeDescriptorContext)this, + CultureInfo.CurrentCulture, value); + else + conversionError = true; + } catch (Exception e) { + error = e.Message; + conversionError = true; + } + if (conversionError) { + string valueText = ConvertToString (value); + string errorShortDescription = null; + if (valueText != null) { + errorShortDescription = "Property value '" + valueText + "' of '" + + PropertyDescriptor.Name + "' is not convertible to type '" + + this.PropertyDescriptor.PropertyType.Name + "'"; + + } else { + errorShortDescription = "Property value of '" + + PropertyDescriptor.Name + "' is not convertible to type '" + + this.PropertyDescriptor.PropertyType.Name + "'"; + } + error = errorShortDescription + Environment.NewLine + Environment.NewLine + error; + return false; + } + } + + bool changed = false; + bool current_changed = false; + object[] propertyOwners = this.PropertyOwners; + PropertyDescriptor[] properties = PropertyDescriptors; + for (int i=0; i < propertyOwners.Length; i++) { + object currentVal = properties[i].GetValue (propertyOwners[i]); + current_changed = false; + if (!Object.Equals (currentVal, value)) { + if (this.ShouldCreateParentInstance) { + Hashtable updatedParentProperties = new Hashtable (); + PropertyDescriptorCollection parentProperties = TypeDescriptor.GetProperties (propertyOwners[i]); + foreach (PropertyDescriptor property in parentProperties) { + if (property.Name == properties[i].Name) + updatedParentProperties[property.Name] = value; + else + updatedParentProperties[property.Name] = property.GetValue (propertyOwners[i]); + } + object updatedParentValue = this.ParentEntry.PropertyDescriptor.Converter.CreateInstance ( + (ITypeDescriptorContext)this, updatedParentProperties); + if (updatedParentValue != null) + current_changed = this.ParentEntry.SetValueCore (updatedParentValue, out error); + } else { + try { + properties[i].SetValue (propertyOwners[i], value); + } catch { + // MS seems to swallow this + // + // string valueText = ConvertToString (value); + // if (valueText != null) + // error = "Property value '" + valueText + "' of '" + properties[i].Name + "' is invalid."; + // else + // error = "Property value of '" + properties[i].Name + "' is invalid."; + return false; + } + + if (IsValueType (this.ParentEntry)) + current_changed = ParentEntry.SetValueCore (propertyOwners[i], out error); + else + current_changed = Object.Equals (properties[i].GetValue (propertyOwners[i]), value); + } + } + if (current_changed) + changed = true; + } + return changed; + } + + private bool IsValueType (GridEntry item) + { + if (item != null && item.PropertyDescriptor != null && + (item.PropertyDescriptor.PropertyType.IsValueType || + item.PropertyDescriptor.PropertyType.IsPrimitive)) + return true; + return false; + } + + public bool ResetValue () + { + if (IsResetable) { + object[] owners = this.PropertyOwners; + PropertyDescriptor[] properties = PropertyDescriptors; + for (int i=0; i < owners.Length; i++) { + properties[i].ResetValue (owners[i]); + if (IsValueType (this.ParentEntry)) { + string error = null; + if (!ParentEntry.SetValueCore (owners[i], out error) && error != null) + property_grid.ShowError (error); + } + } + property_grid.OnPropertyValueChangedInternal (this, this.Value); + return true; + } + return false; + } + + public bool HasDefaultValue { + get { + if (PropertyDescriptor != null) + return !PropertyDescriptor.ShouldSerializeValue (PropertyOwner); + return false; + } + } + + // Determines if the current value can be reset + // + public virtual bool IsResetable { + get { return (!IsReadOnly && PropertyDescriptor.CanResetValue (PropertyOwner)); } + + } + + // If false the entry can be modified only by the means of a predefined values + // and not such inputed by the user. + // + public virtual bool IsEditable { + get { + TypeConverter converter = GetConverter (); + if (PropertyDescriptor == null) + return false; + else if (PropertyDescriptor.PropertyType.IsArray) + return false; + else if (PropertyDescriptor.IsReadOnly && !this.ShouldCreateParentInstance) + return false; + else if (converter == null || + !converter.CanConvertFrom ((ITypeDescriptorContext)this, typeof (string))) + return false; + else if (converter.GetStandardValuesSupported ((ITypeDescriptorContext)this) && + converter.GetStandardValuesExclusive ((ITypeDescriptorContext)this)) + return false; + else + return true; + } + } + + // If true the the entry cannot be modified at all + // + public virtual bool IsReadOnly { + get { + TypeConverter converter = GetConverter (); + if (PropertyDescriptor == null || PropertyOwner == null) + return true; + else if (PropertyDescriptor.IsReadOnly && + (EditorStyle != UITypeEditorEditStyle.Modal || PropertyDescriptor.PropertyType.IsValueType) && + !this.ShouldCreateParentInstance) + return true; + else if (PropertyDescriptor.IsReadOnly && + TypeDescriptor.GetAttributes (PropertyDescriptor.PropertyType) + [typeof(ImmutableObjectAttribute)].Equals (ImmutableObjectAttribute.Yes)) + return true; + else if (ShouldCreateParentInstance && ParentEntry.IsReadOnly) + return true; + else if (!HasCustomEditor && converter == null) + return true; + else if (converter != null && + !converter.GetStandardValuesSupported ((ITypeDescriptorContext)this) && + !converter.CanConvertFrom ((ITypeDescriptorContext)this, + typeof (string)) && + !HasCustomEditor) { + return true; + } else if (PropertyDescriptor.PropertyType.IsArray && !HasCustomEditor) + return true; + else + return false; + } + } + + public bool IsPassword { + get { + if (PropertyDescriptor != null) + return PropertyDescriptor.Attributes.Contains (PasswordPropertyTextAttribute.Yes); + return false; + } + } + // This is a way to set readonly properties (e.g properties without a setter). + // The way it works is that if CreateInstance is supported by the parent's converter + // it gets passed a list of properties and their values which it uses to create an + // instance (e.g by passing them to the ctor of that object type). + // + // This is used for e.g Font + // + public virtual bool ShouldCreateParentInstance { + get { + if (this.ParentEntry != null && ParentEntry.PropertyDescriptor != null) { + TypeConverter parentConverter = ParentEntry.GetConverter (); + if (parentConverter != null && parentConverter.GetCreateInstanceSupported ((ITypeDescriptorContext)this)) + return true; + } + return false; + } + } + + public virtual bool PaintValueSupported { + get { + UITypeEditor editor = GetEditor (); + if (editor != null) { + try { + return editor.GetPaintValueSupported (); + } catch { + // Some of our Editors throw NotImplementedException + } + } + return false; + } + } + + public virtual void PaintValue (Graphics gfx, Rectangle rect) + { + UITypeEditor editor = GetEditor (); + if (editor != null) { + try { + editor.PaintValue (this.Value, gfx, rect); + } catch { + // Some of our Editors throw NotImplementedException + } + } + } + +#region Population + protected void PopulateChildGridItems () + { + grid_items = GetChildGridItemsCached (); + } + + private void InvalidateChildGridItemsCache () + { + if (child_griditems_cache != null) { + child_griditems_cache = null; + PopulateChildGridItems (); + } + } + + private GridItemCollection GetChildGridItemsCached () + { + if (child_griditems_cache == null) { + child_griditems_cache = GetChildGridItems (); + // foreach (GridEntry item in child_griditems_cache) + // PrintDebugInfo (item); + } + + return child_griditems_cache; + } + + // private static void PrintDebugInfo (GridEntry item) + // { + // if (item.PropertyDescriptor != null) { + // Console.WriteLine ("=== [" + item.PropertyDescriptor.Name + "] ==="); + // try { + // TypeConverter converter = item.GetConverter (); + // Console.WriteLine ("IsReadOnly: " + item.IsReadOnly); + // Console.WriteLine ("IsEditable: " + item.IsEditable); + // Console.WriteLine ("PropertyDescriptor.IsReadOnly: " + item.PropertyDescriptor.IsReadOnly); + // if (item.ParentEntry != null) + // Console.WriteLine ("ParentEntry.IsReadOnly: " + item.ParentEntry.IsReadOnly); + // Console.WriteLine ("ImmutableObjectAttribute.Yes: " + TypeDescriptor.GetAttributes (item.PropertyDescriptor.PropertyType) + // [typeof(ImmutableObjectAttribute)].Equals (ImmutableObjectAttribute.Yes)); + // UITypeEditor editor = item.GetEditor (); + // Console.WriteLine ("Editor: " + (editor == null ? "none" : editor.GetType ().Name)); + // if (editor != null) + // Console.WriteLine ("Editor.EditorStyle: " + editor.GetEditStyle ((ITypeDescriptorContext)item)); + // Console.WriteLine ("Converter: " + (converter == null ? "none" : converter.GetType ().Name)); + // if (converter != null) { + // Console.WriteLine ("Converter.GetStandardValuesSupported: " + converter.GetStandardValuesSupported ((ITypeDescriptorContext)item).ToString ()); + // Console.WriteLine ("Converter.GetStandardValuesExclusive: " + converter.GetStandardValuesExclusive ((ITypeDescriptorContext)item).ToString ()); + // Console.WriteLine ("ShouldCreateParentInstance: " + item.ShouldCreateParentInstance); + // Console.WriteLine ("CanConvertFrom (string): " + converter.CanConvertFrom ((ITypeDescriptorContext)item, typeof (string))); + // } + // Console.WriteLine ("IsArray: " + item.PropertyDescriptor.PropertyType.IsArray.ToString ()); + // } catch { /* Some converters and editor throw NotImplementedExceptions */ } + // } + // } + + private GridItemCollection GetChildGridItems () + { + object[] propertyOwners = this.Values; + string[] propertyNames = GetMergedPropertyNames (propertyOwners); + GridItemCollection items = new GridItemCollection (); + + foreach (string propertyName in propertyNames) { + PropertyDescriptor[] properties = new PropertyDescriptor[propertyOwners.Length]; + for (int i=0; i < propertyOwners.Length; i++) + properties[i] = GetPropertyDescriptor (propertyOwners[i], propertyName); + items.Add (new GridEntry (property_grid, properties, this)); + } + + return items; + } + + private bool IsPropertyMergeable (PropertyDescriptor property) + { + if (property == null) + return false; + + MergablePropertyAttribute attrib = property.Attributes [typeof (MergablePropertyAttribute)] as MergablePropertyAttribute; + if (attrib != null && !attrib.AllowMerge) + return false; + + return true; + } + + private string[] GetMergedPropertyNames (object [] objects) + { + if (objects == null || objects.Length == 0) + return new string[0]; + + ArrayList intersection = new ArrayList (); + for (int i = 0; i < objects.Length; i ++) { + if (objects [i] == null) + continue; + + PropertyDescriptorCollection properties = GetProperties (objects[i], property_grid.BrowsableAttributes); + ArrayList new_intersection = new ArrayList (); + + foreach (PropertyDescriptor currentProperty in (i == 0 ? (ICollection)properties : (ICollection)intersection)) { + PropertyDescriptor matchingProperty = (i == 0 ? currentProperty : properties [currentProperty.Name]); + if (objects.Length > 1 && !IsPropertyMergeable (matchingProperty)) + continue; + if (matchingProperty.PropertyType == currentProperty.PropertyType) + new_intersection.Add (matchingProperty); + } + + intersection = new_intersection; + } + + string[] propertyNames = new string [intersection.Count]; + for (int i=0; i < intersection.Count; i++) + propertyNames[i] = ((PropertyDescriptor)intersection[i]).Name; + + return propertyNames; + } + + private PropertyDescriptor GetPropertyDescriptor (object propertyOwner, string propertyName) + { + if (propertyOwner == null || propertyName == null) + return null; + + PropertyDescriptorCollection properties = GetProperties (propertyOwner, property_grid.BrowsableAttributes); + if (properties != null) + return properties[propertyName]; + return null; + } + + private PropertyDescriptorCollection GetProperties (object propertyOwner, AttributeCollection attributes) + { + if (propertyOwner == null || property_grid.SelectedTab == null) + return new PropertyDescriptorCollection (null); + + Attribute[] atts = new Attribute[attributes.Count]; + attributes.CopyTo (atts, 0); + return property_grid.SelectedTab.GetProperties ((ITypeDescriptorContext)this, propertyOwner, atts); + } +#endregion + } +} diff --git a/source/ShiftUI/Widgets/GridItemCollection.cs b/source/ShiftUI/Widgets/GridItemCollection.cs new file mode 100644 index 0000000..22eedc8 --- /dev/null +++ b/source/ShiftUI/Widgets/GridItemCollection.cs @@ -0,0 +1,158 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jonathan Chambers (jonathan.chambers@ansys.com) +// + +// COMPLETE + +using System; +using System.Collections; +using ShiftUI.PropertyGridInternal; + +namespace ShiftUI +{ + public class GridItemCollection : IEnumerable, ICollection + { + #region Local Variables + private System.Collections.SortedList list; + #endregion // Local Variables + + #region Public Static Fields + public static GridItemCollection Empty = new GridItemCollection(); + #endregion // Public Static Fields + + #region Constructors + internal GridItemCollection() + { + list = new SortedList(); + } + #endregion // Constructors + + #region Internal Properties and Methods + internal void Add (GridItem grid_item) + { + string key = grid_item.Label; + while (list.ContainsKey (key)) + key += "_"; + list.Add (key, grid_item); + } + + internal void AddRange (GridItemCollection items) + { + foreach (GridItem item in items) + Add (item); + } + + internal int IndexOf (GridItem grid_item) + { + return list.IndexOfValue (grid_item); + } + #endregion // Internal Properties and Methods + + #region Public Instance Properties + public int Count { + get { + return list.Count; + } + } + + public GridItem this [int index] { + get { + if (index>=list.Count) { + throw new ArgumentOutOfRangeException("index"); + } + return (GridItem)list.GetByIndex(index); + } + } + + public GridItem this [string label] { + get { + return (GridItem)list[label]; + } + } + #endregion // Public Instance Properties + + #region IEnumerable Members + public IEnumerator GetEnumerator() + { + return new GridItemEnumerator (this); + } + #endregion + + #region Enumerator Class + internal class GridItemEnumerator : IEnumerator{ + int nIndex; + GridItemCollection collection; + + public GridItemEnumerator(GridItemCollection coll) + { + collection = coll; + nIndex = -1; + } + + public bool MoveNext () + { + nIndex++; + return (nIndex < collection.Count); + } + + public void Reset () + { + nIndex = -1; + } + + object System.Collections.IEnumerator.Current { + get { + return collection [nIndex]; + } + } + } + #endregion + + #region ICollection Members + + bool ICollection.IsSynchronized { + get { + return list.IsSynchronized; + } + } + + void ICollection.CopyTo(Array dest, int index) + { + list.CopyTo (dest, index); + } + + object ICollection.SyncRoot { + get { + return list.SyncRoot; + } + } + + #endregion + + internal void Clear () + { + list.Clear (); + } + } +} diff --git a/source/ShiftUI/Widgets/GroupBox.cs b/source/ShiftUI/Widgets/GroupBox.cs new file mode 100644 index 0000000..27b8384 --- /dev/null +++ b/source/ShiftUI/Widgets/GroupBox.cs @@ -0,0 +1,344 @@ +// +// ShiftUI.GroupBox.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// +// TODO: +// +// Copyright (C) Novell Inc., 2004-2005 +// +// + +using System.Drawing; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI +{ + [DefaultProperty("Text")] + [DefaultEvent("Enter")] + //[Designer ("ShiftUI.Design.GroupBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + [ToolboxWidget] + public class GroupBox : Widget + { + private FlatStyle flat_style; + private Rectangle display_rectangle = new Rectangle (); + + #region Events + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler AutoSizeChanged { + add { base.AutoSizeChanged += value; } + remove { base.AutoSizeChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public new event EventHandler Click { + add { base.Click += value; } + remove { base.Click -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public new event EventHandler DoubleClick { + add { base.DoubleClick += value; } + remove { base.DoubleClick -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public new event KeyEventHandler KeyDown { + add { base.KeyDown += value; } + remove { base.KeyDown -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public new event KeyPressEventHandler KeyPress { + add { base.KeyPress += value; } + remove { base.KeyPress -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public new event KeyEventHandler KeyUp { + add { base.KeyUp += value; } + remove { base.KeyUp -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public new event MouseEventHandler MouseClick { + add { base.MouseClick += value; } + remove { base.MouseClick -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public new event MouseEventHandler MouseDoubleClick { + add { base.MouseDoubleClick += value; } + remove { base.MouseDoubleClick -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public new event MouseEventHandler MouseDown { + add { base.MouseDown += value; } + remove { base.MouseDown -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public new event EventHandler MouseEnter { + add { base.MouseEnter += value; } + remove { base.MouseEnter -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public new event EventHandler MouseLeave { + add { base.MouseLeave += value; } + remove { base.MouseLeave -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public new event MouseEventHandler MouseMove { + add { base.MouseMove += value; } + remove { base.MouseMove -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public new event MouseEventHandler MouseUp { + add { base.MouseUp += value; } + remove { base.MouseUp -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public new event EventHandler TabStopChanged { + add { base.TabStopChanged += value; } + remove { base.TabStopChanged -= value; } + } + #endregion Events + + public GroupBox () + { + TabStop = false; + flat_style = FlatStyle.Standard; + + SetStyle(Widgetstyles.ContainerWidget | Widgetstyles.ResizeRedraw | Widgetstyles.SupportsTransparentBackColor, true); + SetStyle(Widgetstyles.Selectable, false); + } + + #region Public Properties + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public override bool AllowDrop { + get { return base.AllowDrop; } + set { base.AllowDrop = value; } + } + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)] + public override bool AutoSize { + get { return base.AutoSize; } + set { base.AutoSize = value; } + } + + [Browsable (true)] + [DefaultValue (AutoSizeMode.GrowOnly)] + [Localizable (true)] + public AutoSizeMode AutoSizeMode { + get { return base.GetAutoSizeMode (); } + set { base.SetAutoSizeMode (value); } + } + + protected override CreateParams CreateParams { + get { return base.CreateParams; } + } + + protected override Size DefaultSize { + get { return ThemeEngine.Current.GroupBoxDefaultSize;} + } + + public override Rectangle DisplayRectangle { + get { + display_rectangle.X = Padding.Left; + display_rectangle.Y = Font.Height + Padding.Top; + display_rectangle.Width = Width - Padding.Horizontal; + display_rectangle.Height = Height - Font.Height - Padding.Vertical; + return display_rectangle; + } + } + + [DefaultValue(FlatStyle.Standard)] + public FlatStyle FlatStyle { + get { return flat_style; } + set { + if (!Enum.IsDefined (typeof (FlatStyle), value)) + throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for FlatStyle", value)); + + if (flat_style == value) + return; + + flat_style = value; + Refresh (); + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public new bool TabStop { + get { return base.TabStop; } + set { base.TabStop = value; } + } + + [Localizable(true)] + public override string Text { + get { return base.Text; } + set { + if (base.Text == value) + return; + + base.Text = value; + Refresh (); + } + } + + #endregion //Public Properties + + #region Public Methods + protected override AccessibleObject CreateAccessibilityInstance () + { + return new GroupBoxAccessibleObject (this); + } + + protected override void OnFontChanged (EventArgs e) + { + base.OnFontChanged (e); + Refresh (); + } + + protected override void OnPaint (PaintEventArgs e) + { + ThemeEngine.Current.DrawGroupBox (e.Graphics, ClientRectangle, this); + base.OnPaint(e); + } + + protected override bool ProcessMnemonic (char charCode) + { + if (IsMnemonic(charCode, Text) == true) { + // Select item next in line in tab order + if (this.Parent != null) { + Parent.SelectNextWidget(this, true, false, true, false); + } + return true; + } + + return base.ProcessMnemonic (charCode); + } + + protected override void ScaleWidget (SizeF factor, BoundsSpecified specified) + { + base.ScaleWidget (factor, specified); + } + + public override string ToString() + { + return GetType ().FullName + ", Text: " + Text; + } + + protected override void WndProc(ref Message m) { + base.WndProc (ref m); + } + + #endregion Public Methods + + [DefaultValue (false)] + public bool UseCompatibleTextRendering { + get { + return use_compatible_text_rendering; + } + + set { + if (use_compatible_text_rendering != value) { + use_compatible_text_rendering = value; + if (Parent != null) + Parent.PerformLayout (this, "UseCompatibleTextRendering"); + Invalidate (); + } + } + } + + #region Protected Properties + protected override Padding DefaultPadding { + get { return new Padding (3); } + } + #endregion + + #region Internal Methods + internal override Size GetPreferredSizeCore (Size proposedSize) + { + Size retsize = new Size (Padding.Left, Padding.Top); + + foreach (Widget child in Widgets) { + if (child.Dock == DockStyle.Fill) { + if (child.Bounds.Right > retsize.Width) + retsize.Width = child.Bounds.Right; + } else if (child.Dock != DockStyle.Top && child.Dock != DockStyle.Bottom && (child.Bounds.Right + child.Margin.Right) > retsize.Width) + retsize.Width = child.Bounds.Right + child.Margin.Right; + + if (child.Dock == DockStyle.Fill) { + if (child.Bounds.Bottom > retsize.Height) + retsize.Height = child.Bounds.Bottom; + } else if (child.Dock != DockStyle.Left && child.Dock != DockStyle.Right && (child.Bounds.Bottom + child.Margin.Bottom) > retsize.Height) + retsize.Height = child.Bounds.Bottom + child.Margin.Bottom; + } + + retsize.Width += Padding.Right; + retsize.Height += Padding.Bottom; + + retsize.Height += this.Font.Height; + + return retsize; + } + #endregion + + #region Private Classes + private class GroupBoxAccessibleObject : Widget.WidgetAccessibleObject + { + public GroupBoxAccessibleObject (Widget owner) : base (owner) + { + } + } + #endregion + } +} diff --git a/source/ShiftUI/Widgets/HScrollBar.cs b/source/ShiftUI/Widgets/HScrollBar.cs new file mode 100644 index 0000000..a6d1fe2 --- /dev/null +++ b/source/ShiftUI/Widgets/HScrollBar.cs @@ -0,0 +1,52 @@ +// +// ShiftUI.HScrollBar.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (C) 2004, Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez jordi@ximian.com +// + + +using System.Drawing; +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + public class HScrollBar : ScrollBar + { + public HScrollBar() + { + vert = false; + } + + protected override Size DefaultSize { + get { return ThemeEngine.Current.HScrollBarDefaultSize;} + } + + protected override CreateParams CreateParams { + get { return base.CreateParams; } + } + } +} diff --git a/source/ShiftUI/Widgets/IRootGridEntry.cs b/source/ShiftUI/Widgets/IRootGridEntry.cs new file mode 100644 index 0000000..25142bb --- /dev/null +++ b/source/ShiftUI/Widgets/IRootGridEntry.cs @@ -0,0 +1,40 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. +// +// Authors: +// Jonathan Chambers jonathan.chambers@ansys.com +// + + +// COMPLETE + +using System; +namespace ShiftUI.PropertyGridInternal +{ + public interface IRootGridEntry + { + System.ComponentModel.AttributeCollection BrowsableAttributes { get; set; } + + void ShowCategories ( bool showCategories ); + + void ResetBrowsableAttributes (); + } +} diff --git a/source/ShiftUI/Widgets/ImplicitHScrollBar.cs b/source/ShiftUI/Widgets/ImplicitHScrollBar.cs new file mode 100644 index 0000000..3e2acfa --- /dev/null +++ b/source/ShiftUI/Widgets/ImplicitHScrollBar.cs @@ -0,0 +1,48 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// Partially based on work by: +// Aleksey Ryabchuk ryabchuk@yahoo.com +// Alexandre Pigolkine pigolkine@gmx.de +// Dennis Hayes dennish@raytek.com +// Jaak Simm jaaksimm@firm.ee +// John Sohn jsohn@columbus.rr.com +// + +// COMPLETE + +using System; + +namespace ShiftUI { + + internal class ImplicitHScrollBar : HScrollBar { + + public ImplicitHScrollBar () + { + implicit_Widget = true; + SetStyle (Widgetstyles.Selectable, false); + } + } +} + diff --git a/source/ShiftUI/Widgets/ImplicitVScrollBar.cs b/source/ShiftUI/Widgets/ImplicitVScrollBar.cs new file mode 100644 index 0000000..618cc53 --- /dev/null +++ b/source/ShiftUI/Widgets/ImplicitVScrollBar.cs @@ -0,0 +1,48 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// Partially based on work by: +// Aleksey Ryabchuk ryabchuk@yahoo.com +// Alexandre Pigolkine pigolkine@gmx.de +// Dennis Hayes dennish@raytek.com +// Jaak Simm jaaksimm@firm.ee +// John Sohn jsohn@columbus.rr.com +// + +// COMPLETE + +using System; + +namespace ShiftUI { + + internal class ImplicitVScrollBar : VScrollBar { + + public ImplicitVScrollBar () + { + implicit_Widget = true; + SetStyle (Widgetstyles.Selectable, false); + } + } +} + diff --git a/source/ShiftUI/Widgets/Label.cs b/source/ShiftUI/Widgets/Label.cs new file mode 100644 index 0000000..4bd4515 --- /dev/null +++ b/source/ShiftUI/Widgets/Label.cs @@ -0,0 +1,729 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// Peter Bartok, pbartok@novell.com +// +// + +// COMPLETE + +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Drawing.Text; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; +using ShiftUI.Theming; +using System; + +namespace ShiftUI +{ + [DefaultProperty ("Text")] + //[Designer ("ShiftUI.Design.LabelDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + [ToolboxItem ("ShiftUI.Design.AutoSizeToolboxItem," + Consts.AssemblySystem_Design)] + [DefaultBindingProperty ("Text")] + [ToolboxWidget] + public class Label : Widget + { + private bool autosize; + private bool auto_ellipsis; + private Image image; + private bool render_transparent; + private FlatStyle flat_style; + private bool use_mnemonic; + private int image_index = -1; + private string image_key = string.Empty; + private ImageList image_list; + internal ContentAlignment image_align; + internal StringFormat string_format; + internal ContentAlignment text_align; + static SizeF req_witdthsize = new SizeF (0,0); + + #region Events + static object AutoSizeChangedEvent = new object (); + static object TextAlignChangedEvent = new object (); + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler AutoSizeChanged { + add { Events.AddHandler (AutoSizeChangedEvent, value); } + remove { Events.RemoveHandler (AutoSizeChangedEvent, value); } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageChanged { + add { base.BackgroundImageChanged += value; } + remove { base.BackgroundImageChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageLayoutChanged { + add { base.BackgroundImageLayoutChanged += value; } + remove { base.BackgroundImageLayoutChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler ImeModeChanged { + add { base.ImeModeChanged += value; } + remove { base.ImeModeChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event KeyEventHandler KeyDown { + add { base.KeyDown += value; } + remove { base.KeyDown -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event KeyPressEventHandler KeyPress { + add { base.KeyPress += value; } + remove { base.KeyPress -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event KeyEventHandler KeyUp { + add { base.KeyUp += value; } + remove { base.KeyUp -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler TabStopChanged { + add { base.TabStopChanged += value; } + remove { base.TabStopChanged -= value; } + } + + public event EventHandler TextAlignChanged { + add { Events.AddHandler (TextAlignChangedEvent, value); } + remove { Events.RemoveHandler (TextAlignChangedEvent, value); } + } + #endregion + + public Label () + { + // Defaults in the Spec + autosize = false; + TabStop = false; + string_format = new StringFormat(); + string_format.FormatFlags = StringFormatFlags.LineLimit; + TextAlign = ContentAlignment.TopLeft; + image = null; + UseMnemonic = true; + image_list = null; + image_align = ContentAlignment.MiddleCenter; + SetUseMnemonic (UseMnemonic); + flat_style = FlatStyle.Standard; + + SetStyle (Widgetstyles.Selectable, false); + SetStyle (Widgetstyles.ResizeRedraw | + Widgetstyles.UserPaint | + Widgetstyles.AllPaintingInWmPaint | + Widgetstyles.SupportsTransparentBackColor | + Widgetstyles.OptimizedDoubleBuffer + , true); + + HandleCreated += new EventHandler (OnHandleCreatedLB); + } + + #region Public Properties + + [DefaultValue (false)] + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public bool AutoEllipsis { + get { return this.auto_ellipsis; } + set + { + if (this.auto_ellipsis != value) { + this.auto_ellipsis = value; + + if (this.auto_ellipsis) + string_format.Trimming = StringTrimming.EllipsisCharacter; + else + string_format.Trimming = StringTrimming.Character; + + if (Parent != null) + Parent.PerformLayout (this, "AutoEllipsis"); + this.Invalidate (); + } + } + } + + [Browsable (true)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)] + //[EditorBrowsable (EditorBrowsableState.Always)] + [DefaultValue(false)] + [Localizable(true)] + [RefreshProperties(RefreshProperties.All)] + public override bool AutoSize { + get { return autosize; } + set { + if (autosize == value) + return; + + base.SetAutoSizeMode (AutoSizeMode.GrowAndShrink); + base.AutoSize = value; + autosize = value; + CalcAutoSize (); + Invalidate (); + + OnAutoSizeChanged (EventArgs.Empty); + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override Image BackgroundImage { + get { return base.BackgroundImage; } + set { + base.BackgroundImage = value; + Invalidate (); + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + [DefaultValue(BorderStyle.None)] + [DispId(-504)] + public virtual BorderStyle BorderStyle { + get { return InternalBorderStyle; } + set { InternalBorderStyle = value; } + } + + protected override CreateParams CreateParams { + get { + CreateParams create_params = base.CreateParams; + + if (BorderStyle != BorderStyle.Fixed3D) + return create_params; + + create_params.ExStyle &= ~(int) WindowExStyles.WS_EX_CLIENTEDGE; + create_params.ExStyle |= (int)WindowExStyles.WS_EX_STATICEDGE; + + return create_params; + } + } + + protected override ImeMode DefaultImeMode { + get { return ImeMode.Disable;} + } + + protected override Padding DefaultMargin { + get { return new Padding (3, 0, 3, 0); } + } + + protected override Size DefaultSize { + get { return ThemeElements.LabelPainter.DefaultSize; } + } + + [DefaultValue(FlatStyle.Standard)] + public FlatStyle FlatStyle { + get { return flat_style; } + set { + if (!Enum.IsDefined (typeof (FlatStyle), value)) + throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for FlatStyle", value)); + + if (flat_style == value) + return; + + flat_style = value; + if (Parent != null) + Parent.PerformLayout (this, "FlatStyle"); + Invalidate (); + } + } + + [Localizable(true)] + public Image Image { + get { + if (this.image != null) + return this.image; + + if (this.image_index >= 0) + if (this.image_list != null) + return this.image_list.Images[this.image_index]; + + if (!string.IsNullOrEmpty (this.image_key)) + if (this.image_list != null) + return this.image_list.Images[this.image_key]; + + return null; + } + set { + if (this.image != value) { + this.image = value; + this.image_index = -1; + this.image_key = string.Empty; + this.image_list = null; + + if (this.AutoSize && this.Parent != null) + this.Parent.PerformLayout (this, "Image"); + + Invalidate (); + } + } + } + + [DefaultValue(ContentAlignment.MiddleCenter)] + [Localizable(true)] + public ContentAlignment ImageAlign { + get { return image_align; } + set { + if (!Enum.IsDefined (typeof (ContentAlignment), value)) + throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for ContentAlignment", value)); + + if (image_align == value) + return; + + image_align = value; + Invalidate (); + } + } + + [DefaultValue (-1)] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + [Localizable (true)] + [TypeConverter (typeof (ImageIndexConverter))] + [RefreshProperties (RefreshProperties.Repaint)] + public int ImageIndex { + get { + if (ImageList == null) { + return -1; + } + + if (image_index >= image_list.Images.Count) { + return image_list.Images.Count - 1; + } + + return image_index; + } + set { + + if (value < -1) + throw new ArgumentException (); + + if (this.image_index != value) { + this.image_index = value; + this.image = null; + this.image_key = string.Empty; + Invalidate (); + } + } + } + + [Localizable (true)] + [DefaultValue ("")] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + [RefreshProperties (RefreshProperties.Repaint)] + [TypeConverter (typeof (ImageKeyConverter))] + public string ImageKey { + get { return this.image_key; } + set { + if (this.image_key != value) { + this.image = null; + this.image_index = -1; + this.image_key = value; + this.Invalidate (); + } + } + } + + [DefaultValue(null)] + [RefreshProperties (RefreshProperties.Repaint)] + public ImageList ImageList { + get { return image_list;} + set { + if (image_list == value) + return; + + image_list = value; + + if (image_list != null && image_index !=-1) + Image = null; + + Invalidate (); + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new ImeMode ImeMode { + get { return base.ImeMode; } + set { base.ImeMode = value; } + } + + internal virtual Size InternalGetPreferredSize (Size proposed) + { + Size size; + + if (Text == string.Empty) { + size = new Size (0, Font.Height); + } else { + size = Size.Ceiling (TextRenderer.MeasureString (Text, Font, req_witdthsize, string_format)); + size.Width += 3; + } + + size.Width += Padding.Horizontal; + size.Height += Padding.Vertical; + + if (!use_compatible_text_rendering) + return size; + + if (border_style == BorderStyle.None) + size.Height += 3; + else + size.Height += 6; + + return size; + } + + public override Size GetPreferredSize (Size proposedSize) + { + return InternalGetPreferredSize (proposedSize); + } + + [Browsable(false)] + //[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public virtual int PreferredHeight { + get { return InternalGetPreferredSize (Size.Empty).Height; } + } + + [Browsable(false)] + //[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + public virtual int PreferredWidth { + get { return InternalGetPreferredSize (Size.Empty).Width; } + } + + [Obsolete ("This property has been deprecated. Use BackColor instead.")] + protected virtual bool RenderTransparent { + get { return render_transparent; } + set { render_transparent = value;} + } + + [Browsable(false)] + [DefaultValue(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new bool TabStop { + get { return base.TabStop; } + set { base.TabStop = value; } + } + + [DefaultValue(ContentAlignment.TopLeft)] + [Localizable(true)] + public virtual ContentAlignment TextAlign { + get { return text_align; } + + set { + if (!Enum.IsDefined (typeof (ContentAlignment), value)) + throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for ContentAlignment", value)); + + if (text_align != value) { + text_align = value; + switch (value) { + case ContentAlignment.BottomLeft: + string_format.LineAlignment = StringAlignment.Far; + string_format.Alignment = StringAlignment.Near; + break; + case ContentAlignment.BottomCenter: + string_format.LineAlignment = StringAlignment.Far; + string_format.Alignment = StringAlignment.Center; + break; + case ContentAlignment.BottomRight: + string_format.LineAlignment = StringAlignment.Far; + string_format.Alignment = StringAlignment.Far; + break; + case ContentAlignment.TopLeft: + string_format.LineAlignment = StringAlignment.Near; + string_format.Alignment = StringAlignment.Near; + break; + case ContentAlignment.TopCenter: + string_format.LineAlignment = StringAlignment.Near; + string_format.Alignment = StringAlignment.Center; + break; + case ContentAlignment.TopRight: + string_format.LineAlignment = StringAlignment.Near; + string_format.Alignment = StringAlignment.Far; + break; + case ContentAlignment.MiddleLeft: + string_format.LineAlignment = StringAlignment.Center; + string_format.Alignment = StringAlignment.Near; + break; + case ContentAlignment.MiddleRight: + string_format.LineAlignment = StringAlignment.Center; + string_format.Alignment = StringAlignment.Far; + break; + case ContentAlignment.MiddleCenter: + string_format.LineAlignment = StringAlignment.Center; + string_format.Alignment = StringAlignment.Center; + break; + default: + break; + } + + OnTextAlignChanged (EventArgs.Empty); + Invalidate (); + } + } + } + + [DefaultValue(true)] + public bool UseMnemonic { + get { return use_mnemonic; } + set { + if (use_mnemonic != value) { + use_mnemonic = value; + SetUseMnemonic (use_mnemonic); + Invalidate (); + } + } + } + + #endregion + + #region Public Methods + + protected Rectangle CalcImageRenderBounds (Image image, Rectangle r, ContentAlignment align) + { + Rectangle rcImageClip = r; + rcImageClip.Inflate (-2,-2); + + int X = r.X; + int Y = r.Y; + + if (align == ContentAlignment.TopCenter || + align == ContentAlignment.MiddleCenter || + align == ContentAlignment.BottomCenter) { + X += (r.Width - image.Width) / 2; + } else if (align == ContentAlignment.TopRight || + align == ContentAlignment.MiddleRight|| + align == ContentAlignment.BottomRight) { + X += (r.Width - image.Width); + } + + if( align == ContentAlignment.BottomCenter || + align == ContentAlignment.BottomLeft || + align == ContentAlignment.BottomRight) { + Y += r.Height - image.Height; + } else if(align == ContentAlignment.MiddleCenter || + align == ContentAlignment.MiddleLeft || + align == ContentAlignment.MiddleRight) { + Y += (r.Height - image.Height) / 2; + } + + rcImageClip.X = X; + rcImageClip.Y = Y; + rcImageClip.Width = image.Width; + rcImageClip.Height = image.Height; + + return rcImageClip; + } + + protected override AccessibleObject CreateAccessibilityInstance () + { + return base.CreateAccessibilityInstance (); + } + + protected override void Dispose(bool disposing) + { + base.Dispose (disposing); + + if (disposing) + string_format.Dispose (); + } + + protected internal void DrawImage (Graphics g, Image image, Rectangle r, ContentAlignment align) + { + if (image == null || g == null) + return; + + Rectangle rcImageClip = CalcImageRenderBounds (image, r, align); + + if (Enabled) + g.DrawImage (image, rcImageClip.X, rcImageClip.Y, rcImageClip.Width, rcImageClip.Height); + else + WidgetPaint.DrawImageDisabled (g, image, rcImageClip.X, rcImageClip.Y, BackColor); + } + + protected override void OnEnabledChanged (EventArgs e) + { + base.OnEnabledChanged (e); + } + + protected override void OnFontChanged (EventArgs e) + { + base.OnFontChanged (e); + if (autosize) + CalcAutoSize(); + Invalidate (); + } + + protected override void OnPaddingChanged (EventArgs e) + { + base.OnPaddingChanged (e); + } + + protected override void OnPaint (PaintEventArgs e) + { + ThemeElements.LabelPainter.Draw (e.Graphics, ClientRectangle, this); + base.OnPaint(e); + } + + protected override void OnParentChanged (EventArgs e) + { + base.OnParentChanged (e); + } + + protected override void OnRightToLeftChanged (EventArgs e) + { + base.OnRightToLeftChanged (e); + } + + protected virtual void OnTextAlignChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [TextAlignChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnTextChanged (EventArgs e) + { + base.OnTextChanged (e); + if (autosize) + CalcAutoSize (); + Invalidate (); + } + + protected override void OnVisibleChanged (EventArgs e) + { + base.OnVisibleChanged (e); + } + + protected override bool ProcessMnemonic (char charCode) + { + if (IsMnemonic (charCode, Text)) { + // Select item next in line in tab order + if (this.Parent != null) + Parent.SelectNextWidget(this, true, false, false, false); + return true; + } + + return base.ProcessMnemonic (charCode); + } + + protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified) + { + base.SetBoundsCore (x, y, width, height, specified); + } + + public override string ToString() + { + return base.ToString () + ", Text: " + Text; + } + + protected override void WndProc (ref Message m) + { + switch ((Msg) m.Msg) { + case Msg.WM_DRAWITEM: + m.Result = (IntPtr)1; + break; + default: + base.WndProc (ref m); + break; + } + } + + #endregion Public Methods + + #region Private Methods + + private void CalcAutoSize () + { + if (!AutoSize) + return; + + Size s = InternalGetPreferredSize (Size.Empty); + + SetBounds (Left, Top, s.Width, s.Height, BoundsSpecified.Size); + } + + private void OnHandleCreatedLB (Object o, EventArgs e) + { + if (autosize) + CalcAutoSize (); + } + + private void SetUseMnemonic (bool use) + { + if (use) + string_format.HotkeyPrefix = HotkeyPrefix.Show; + else + string_format.HotkeyPrefix = HotkeyPrefix.None; + } + + #endregion Private Methods + [DefaultValue (false)] + public bool UseCompatibleTextRendering { + get { return use_compatible_text_rendering; } + set { use_compatible_text_rendering = value; } + } + + [SettingsBindable (true)] + //[Editor ("System.ComponentModel.Design.MultilineStringEditor, " + Consts.AssemblySystem_Design, + // typeof (System.Drawing.Design.UITypeEditor))] + public override string Text { + get { return base.Text; } + set { base.Text = value; } + } + + protected override void OnMouseEnter (EventArgs e) + { + base.OnMouseEnter (e); + } + + protected override void OnMouseLeave (EventArgs e) + { + base.OnMouseLeave (e); + } + + protected override void OnHandleDestroyed (EventArgs e) + { + base.OnHandleDestroyed (e); + } + } +} diff --git a/source/ShiftUI/Widgets/LabelEditTextBox.cs b/source/ShiftUI/Widgets/LabelEditTextBox.cs new file mode 100644 index 0000000..8e03bd0 --- /dev/null +++ b/source/ShiftUI/Widgets/LabelEditTextBox.cs @@ -0,0 +1,108 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// +// + +// This is an internal class that allows us to use a textbox for label editing +// in the tree and in listview. The textbox will make itself invisible when +// the user pressed the enter key +using System; + +namespace ShiftUI { + + internal class LabelEditTextBox : FixedSizeTextBox { + + public LabelEditTextBox () : base (true, true) + { + } + + protected override bool IsInputKey (Keys key_data) + { + if ((key_data & Keys.Alt) == 0) { + switch (key_data & Keys.KeyCode) { + case Keys.Enter: + return true; + case Keys.Escape: + return true; + } + } + return base.IsInputKey (key_data); + } + + protected override void OnKeyDown (KeyEventArgs e) + { + if (!Visible) + return; + + switch (e.KeyCode) { + case Keys.Return: + Visible = false; + Parent.Focus (); + e.Handled = true; + OnEditingFinished (e); + break; + case Keys.Escape: + Visible = false; + Parent.Focus (); + e.Handled = true; + OnEditingCancelled (e); + break; + } + } + + protected override void OnLostFocus (EventArgs e) + { + if (Visible) { + OnEditingFinished (e); + } + } + + protected void OnEditingCancelled (EventArgs e) + { + EventHandler eh = (EventHandler)(Events[EditingCancelledEvent]); + if (eh != null) + eh (this, e); + } + + protected void OnEditingFinished (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [EditingFinishedEvent]); + if (eh != null) + eh (this, e); + } + + static object EditingCancelledEvent = new object (); + public event EventHandler EditingCancelled { + add { Events.AddHandler (EditingCancelledEvent, value); } + remove { Events.RemoveHandler (EditingCancelledEvent, value); } + } + + static object EditingFinishedEvent = new object (); + public event EventHandler EditingFinished { + add { Events.AddHandler (EditingFinishedEvent, value); } + remove { Events.AddHandler (EditingFinishedEvent, value); } + } + } +} + diff --git a/source/ShiftUI/Widgets/LinkLabel.cs b/source/ShiftUI/Widgets/LinkLabel.cs new file mode 100644 index 0000000..3654449 --- /dev/null +++ b/source/ShiftUI/Widgets/LinkLabel.cs @@ -0,0 +1,1120 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// Chris Toshok +// Everaldo Canuto +// +// Based on work by: +// Daniel Carrera, dcarrera@math.toronto.edu (stubbed out) +// Jaak Simm (jaaksimm@firm.ee) (stubbed out) +// + +using System.ComponentModel; +using System.Collections; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Runtime.InteropServices; +using ShiftUI.Theming; +using System; + +namespace ShiftUI +{ + [DefaultEvent("LinkClicked")] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + [ToolboxItem ("ShiftUI.Design.AutoSizeToolboxItem," + Consts.AssemblySystem_Design)] + [ToolboxWidget] + public class LinkLabel : Label, IButtonWidget + { + /* Encapsulates a piece of text (regular or link)*/ + internal class Piece + { + public string text; + public int start; + public int length; + public LinkLabel.Link link; // Empty link indicates regular text + public Region region; + + public Piece (int start, int length, string text, Link link) + { + this.start = start; + this.length = length; + this.text = text; + this.link = link; + } + } + + private Color active_link_color; + private Color disabled_link_color; + private Color link_color; + private Color visited_color; + private LinkArea link_area; + private LinkBehavior link_behavior; + private LinkCollection link_collection; + private ArrayList links = new ArrayList(); + internal Link[] sorted_links; + private bool link_visited; + internal Piece[] pieces; + private Cursor override_cursor; + private DialogResult dialog_result; + + private Link active_link; + private Link hovered_link; + /* this is an index instead of a Link because we have + * to search through sorted links for the new one */ + private int focused_index; + + #region Events + static object LinkClickedEvent = new object (); + + public event LinkLabelLinkClickedEventHandler LinkClicked { + add { Events.AddHandler (LinkClickedEvent, value); } + remove { Events.RemoveHandler (LinkClickedEvent, value); } + } + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler TabStopChanged { + add { base.TabStopChanged += value; } + remove { base.TabStopChanged -= value; } + } + #endregion // Events + + public LinkLabel () + { + LinkArea = new LinkArea (0, -1); + link_behavior = LinkBehavior.SystemDefault; + link_visited = false; + pieces = null; + focused_index = -1; + + string_format.FormatFlags |= StringFormatFlags.NoClip; + + ActiveLinkColor = Color.Red; + DisabledLinkColor = ThemeEngine.Current.ColorGrayText; + LinkColor = Color.FromArgb (255, 0, 0, 255); + VisitedLinkColor = Color.FromArgb (255, 128, 0, 128); + SetStyle (Widgetstyles.Selectable, false); + SetStyle (Widgetstyles.ResizeRedraw | + Widgetstyles.UserPaint | + Widgetstyles.AllPaintingInWmPaint | + Widgetstyles.SupportsTransparentBackColor | + Widgetstyles.Opaque | + Widgetstyles.OptimizedDoubleBuffer + , true); + CreateLinkPieces (); + } + + #region Public Properties + + public Color ActiveLinkColor { + get { return active_link_color; } + set { + if (active_link_color == value) + return; + + active_link_color = value; + Invalidate (); + } + } + + public Color DisabledLinkColor { + + get { return disabled_link_color; } + set { + if (disabled_link_color == value) + return; + + disabled_link_color = value; + Invalidate (); + } + } + + public Color LinkColor { + get { return link_color; } + set { + if (link_color == value) + return; + + link_color = value; + Invalidate (); + } + } + + public Color VisitedLinkColor { + get { return visited_color;} + set { + if (visited_color == value) + return; + + visited_color = value; + Invalidate (); + } + } + + [Localizable (true)] + //[Editor ("ShiftUI.Design.LinkAreaEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + [RefreshProperties (RefreshProperties.Repaint)] + public LinkArea LinkArea { + get { return link_area;} + set { + + if (value.Start <0 || value.Length < -1) + throw new ArgumentException (); + + Links.Clear (); + + if (!value.IsEmpty) { + Links.Add (value.Start, value.Length); + + link_area = value; + Invalidate (); + } + } + } + + [DefaultValue (LinkBehavior.SystemDefault)] + public LinkBehavior LinkBehavior { + + get { return link_behavior;} + set { + if (link_behavior == value) + return; + + link_behavior = value; + Invalidate (); + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public LinkLabel.LinkCollection Links { + get { + if (link_collection == null) + link_collection = new LinkCollection (this); + return link_collection; + } + } + + [DefaultValue (false)] + public bool LinkVisited { + get { return link_visited;} + set { + if (link_visited == value) + return; + + link_visited = value; + Invalidate (); + } + } + + protected Cursor OverrideCursor { + get { + if (override_cursor == null) + override_cursor = Cursors.Hand; + return override_cursor; + } + set { override_cursor = value; } + } + + [RefreshProperties(RefreshProperties.Repaint)] + public override string Text { + get { return base.Text; } + set { + if (base.Text == value) + return; + + base.Text = value; + CreateLinkPieces (); + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new FlatStyle FlatStyle { + get { return base.FlatStyle; } + set { + if (base.FlatStyle == value) + return; + + base.FlatStyle = value; + } + } + + [RefreshProperties (RefreshProperties.Repaint)] + public new Padding Padding { + get { return base.Padding; } + set { + if (base.Padding == value) + return; + + base.Padding = value; + CreateLinkPieces (); + } + } + + #endregion // Public Properties + + DialogResult IButtonWidget.DialogResult { + get { return dialog_result; } + set { dialog_result = value; } + } + + + void IButtonWidget.NotifyDefault (bool value) + { + } + + void IButtonWidget.PerformClick () + { + } + + #region Public Methods + protected override AccessibleObject CreateAccessibilityInstance () + { + return base.CreateAccessibilityInstance(); + } + + protected override void CreateHandle () + { + base.CreateHandle (); + CreateLinkPieces (); + } + + protected override void OnAutoSizeChanged (EventArgs e) + { + base.OnAutoSizeChanged (e); + } + + protected override void OnEnabledChanged (EventArgs e) + { + base.OnEnabledChanged (e); + Invalidate (); + } + + protected override void OnFontChanged (EventArgs e) + { + base.OnFontChanged (e); + CreateLinkPieces (); + } + + protected override void OnGotFocus (EventArgs e) + { + base.OnGotFocus (e); + + // And yes it can actually be null..... arghh.. + if (sorted_links == null) + return; + + // Set focus to the first enabled link piece + if (focused_index == -1) { + if ((Widget.ModifierKeys & Keys.Shift) == 0) { + for (int i = 0; i < sorted_links.Length; i ++) { + if (sorted_links[i].Enabled) { + focused_index = i; + break; + } + } + } else { + if (focused_index == -1) + focused_index = sorted_links.Length; + + for (int n = focused_index - 1; n >= 0; n--) { + if (sorted_links[n].Enabled) { + sorted_links[n].Focused = true; + focused_index = n; + return; + } + } + } + } + + if (focused_index != -1) + sorted_links[focused_index].Focused = true; + } + + protected override void OnKeyDown (KeyEventArgs e) + { + if (e.KeyCode == Keys.Return) { + if (focused_index != -1) + OnLinkClicked (new LinkLabelLinkClickedEventArgs (sorted_links[focused_index])); + } + + base.OnKeyDown(e); + } + + protected virtual void OnLinkClicked (LinkLabelLinkClickedEventArgs e) + { + LinkLabelLinkClickedEventHandler eh = (LinkLabelLinkClickedEventHandler)(Events [LinkClickedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnLostFocus (EventArgs e) + { + base.OnLostFocus (e); + + // Clean focus in link pieces + if (focused_index != -1) + sorted_links[focused_index].Focused = false; + } + + protected override void OnMouseDown (MouseEventArgs e) + { + if (!Enabled) return; + + base.OnMouseDown (e); + + for (int i = 0; i < sorted_links.Length; i ++) { + if (sorted_links[i].Contains (e.X, e.Y) && sorted_links[i].Enabled) { + sorted_links[i].Active = true; + if (focused_index != -1) + sorted_links[focused_index].Focused = false; + active_link = sorted_links[i]; + focused_index = i; + sorted_links[focused_index].Focused = true; + break; + } + } + } + + protected override void OnMouseLeave(EventArgs e) + { + if (!Enabled) return; + base.OnMouseLeave (e); + UpdateHover (null); + } + + protected override void OnPaddingChanged (EventArgs e) + { + base.OnPaddingChanged (e); + } + + private void UpdateHover (Link link) + { + if (link == hovered_link) + return; + + if (hovered_link != null) + hovered_link.Hovered = false; + + hovered_link = link; + + if (hovered_link != null) + hovered_link.Hovered = true; + + Cursor = (hovered_link != null) ? OverrideCursor : Cursors.Default; + + /* XXX this shouldn't be here. the + * Link.Invalidate machinery should be enough, + * but it seems the piece regions don't + * contain the area with the underline. this + * can be seen easily when you click on a link + * and the focus rectangle shows up (it's too + * far up), and also the bottom few pixels of + * a linklabel aren't active when it comes to + * hovering */ + Invalidate (); + } + + protected override void OnMouseMove (MouseEventArgs e) + { + UpdateHover (PointInLink (e.X, e.Y)); + base.OnMouseMove (e); + } + + protected override void OnMouseUp (MouseEventArgs e) + { + if (!Enabled) return; + + base.OnMouseUp (e); + + if (active_link == null) + return; + + Link clicked_link = (PointInLink (e.X, e.Y) == active_link) ? active_link : null; + + active_link.Active = false; + active_link = null; + + if (clicked_link != null) + OnLinkClicked (new LinkLabelLinkClickedEventArgs (clicked_link, e.Button)); + } + + protected override void OnClick (EventArgs e) + { + if (active_link != null && this.Capture) { + this.Capture = false; + } + base.OnClick (e); + } + + protected override void OnPaint (PaintEventArgs e) + { + // We need to invoke paintbackground because control is opaque + // and can have transparent colors. + base.InvokePaintBackground (this, e); + + ThemeElements.LinkLabelPainter.Draw (e.Graphics, e.ClipRectangle, this); + // Do not call base.OnPaint since it's the Label class + } + + protected override void OnPaintBackground (PaintEventArgs e) + { + base.OnPaintBackground (e); + } + + protected override void OnTextAlignChanged (EventArgs e) + { + CreateLinkPieces (); + base.OnTextAlignChanged (e); + } + + protected override void OnTextChanged (EventArgs e) + { + CreateLinkPieces (); + base.OnTextChanged (e); + } + + protected Link PointInLink (int x, int y) + { + for (int i = 0; i < sorted_links.Length; i ++) + if (sorted_links[i].Contains (x, y)) + return sorted_links[i]; + + return null; + } + + protected override bool ProcessDialogKey (Keys keyData) + { + if ((keyData & Keys.KeyCode) == Keys.Tab) { + Select (true, (keyData & Keys.Shift) == 0); + return true; + } + return base.ProcessDialogKey (keyData); + } + + protected override void Select (bool directed, bool forward) + { + if (directed) { + if (focused_index != -1) { + sorted_links[focused_index].Focused = false; + focused_index = -1; + } + + if (forward) { + for (int n = focused_index + 1; n < sorted_links.Length; n++) { + if (sorted_links[n].Enabled) { + sorted_links[n].Focused = true; + focused_index = n; + base.Select (directed, forward); + return; + } + } + } else { + if (focused_index == -1) + focused_index = sorted_links.Length; + + for (int n = focused_index - 1; n >= 0; n--) { + if (sorted_links[n].Enabled) { + sorted_links[n].Focused = true; + focused_index = n; + base.Select (directed, forward); + return; + } + } + } + + focused_index = -1; + + if (Parent != null) + Parent.SelectNextWidget (this, forward, false, true, true); + } + } + + protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified) + { + base.SetBoundsCore (x, y, width, height, specified); + CreateLinkPieces(); + } + + protected override void WndProc (ref Message msg) + { + base.WndProc (ref msg); + } + + #endregion //Public Methods + + #region Private Methods + + private ArrayList CreatePiecesFromText (int start, int len, Link link) + { + ArrayList rv = new ArrayList (); + + if (start + len > Text.Length) + len = Text.Length - start; + if (len < 0) + return rv; + + string t = Text.Substring (start, len); + + int ps = 0; + for (int i = 0; i < t.Length; i ++) { + if (t[i] == '\n') { + if (i != 0) { + Piece p = new Piece (start + ps, i + 1 - ps, t.Substring (ps, i+1-ps), link); + rv.Add (p); + } + ps = i+1; + } + } + if (ps < t.Length) { + Piece p = new Piece (start + ps, t.Length - ps, t.Substring (ps, t.Length-ps), link); + rv.Add (p); + } + + return rv; + } + + private void CreateLinkPieces () + { + if (Text.Length == 0) { + SetStyle (Widgetstyles.Selectable, false); + TabStop = false; + link_area.Start = 0; + link_area.Length = 0; + return; + } + + if (Links.Count == 1 && Links[0].Start == 0 && Links[0].Length == -1) + Links[0].Length = Text.Length; + + SortLinks (); + + // Set the LinkArea values based on first link. + if (Links.Count > 0) { + link_area.Start = Links[0].Start; + link_area.Length = Links[0].Length; + } else { + link_area.Start = 0; + link_area.Length = 0; + } + + TabStop = (LinkArea.Length > 0); + SetStyle (Widgetstyles.Selectable, TabStop); + + /* don't bother doing the rest if our handle hasn't been created */ + if (!IsHandleCreated) + return; + + ArrayList pieces_list = new ArrayList (); + + int current_end = 0; + + for (int l = 0; l < sorted_links.Length; l ++) { + int new_link_start = sorted_links[l].Start; + + if (new_link_start > current_end) { + /* create/push a piece + * containing the text between + * the previous/new link */ + ArrayList text_pieces = CreatePiecesFromText (current_end, new_link_start - current_end, null); + pieces_list.AddRange (text_pieces); + } + + /* now create a group of pieces for + * the new link (split up by \n's) */ + ArrayList link_pieces = CreatePiecesFromText (new_link_start, sorted_links[l].Length, sorted_links[l]); + pieces_list.AddRange (link_pieces); + sorted_links[l].pieces.AddRange (link_pieces); + + current_end = sorted_links[l].Start + sorted_links[l].Length; + } + if (current_end < Text.Length) { + ArrayList text_pieces = CreatePiecesFromText (current_end, Text.Length - current_end, null); + pieces_list.AddRange (text_pieces); + } + + pieces = new Piece[pieces_list.Count]; + pieces_list.CopyTo (pieces, 0); + + CharacterRange[] ranges = new CharacterRange[pieces.Length]; + + for(int i = 0; i < pieces.Length; i++) + ranges[i] = new CharacterRange (pieces[i].start, pieces[i].length); + + string_format.SetMeasurableCharacterRanges (ranges); + + Region[] regions = TextRenderer.MeasureCharacterRanges (Text, + ThemeEngine.Current.GetLinkFont (this), + PaddingClientRectangle, + string_format); + + for (int i = 0; i < pieces.Length; i ++) { + pieces[i].region = regions[i]; + pieces[i].region.Translate (Padding.Left, Padding.Top); + } + + Invalidate (); + } + + private void SortLinks () + { + if (sorted_links != null) + return; + + sorted_links = new Link [Links.Count]; + ((ICollection)Links).CopyTo (sorted_links, 0); + + Array.Sort (sorted_links, new LinkComparer ()); + } + + /* Check if the links overlap */ + private void CheckLinks () + { + SortLinks (); + + int current_end = 0; + + for (int i = 0; i < sorted_links.Length; i++) { + if (sorted_links[i].Start < current_end) + throw new InvalidOperationException ("Overlapping link regions."); + current_end = sorted_links[i].Start + sorted_links[i].Length; + } + } + + #endregion // Private Methods + + // + // ShiftUI.LinkLabel.Link + // + [TypeConverter (typeof (LinkConverter))] + public class Link + { + private bool enabled; + internal int length; + private object linkData; + private int start; + private bool visited; + private LinkLabel owner; + private bool hovered; + internal ArrayList pieces; + private bool focused; + private bool active; + private string description; + private string name; + private object tag; + + internal Link (LinkLabel owner) + { + focused = false; + enabled = true; + visited = false; + length = start = 0; + linkData = null; + this.owner = owner; + pieces = new ArrayList (); + name = string.Empty; + } + + public Link () + { + this.enabled = true; + this.name = string.Empty; + this.pieces = new ArrayList (); + } + + public Link (int start, int length) : this () + { + this.start = start; + this.length = length; + } + + public Link (int start, int length, Object linkData) : this (start, length) + { + this.linkData = linkData; + } + + #region Public Properties + public string Description { + get { return this.description; } + set { this.description = value; } + } + + [DefaultValue ("")] + public string Name { + get { return this.name; } + set { this.name = value; } + } + + [Bindable (true)] + [Localizable (false)] + [DefaultValue (null)] + [TypeConverter (typeof (StringConverter))] + public Object Tag { + get { return this.tag; } + set { this.tag = value; } + } + + [DefaultValue (true)] + public bool Enabled { + get { return enabled; } + set { + if (enabled != value) + Invalidate (); + + enabled = value; + } + } + + public int Length { + get { + if (length == -1) { + return owner.Text.Length; + } + + return length; + } + set { + if (length == value) + return; + + length = value; + + owner.CreateLinkPieces (); + } + } + + [DefaultValue (null)] + public object LinkData { + get { return linkData; } + set { linkData = value; } + } + + public int Start { + get { return start; } + set { + if (start == value) + return; + + start = value; + + owner.sorted_links = null; + owner.CreateLinkPieces (); + } + } + + [DefaultValue (false)] + public bool Visited { + get { return visited; } + set { + if (visited != value) + Invalidate (); + + visited = value; + } + } + + internal bool Hovered { + get { return hovered; } + set { + if (hovered != value) + Invalidate (); + hovered = value; + } + } + + internal bool Focused { + get { return focused; } + set { + if (focused != value) + Invalidate (); + focused = value; + } + } + + internal bool Active { + get { return active; } + set { + if (active != value) + Invalidate (); + active = value; + } + } + + internal LinkLabel Owner { + set { owner = value; } + } + #endregion + + private void Invalidate () + { + for (int i = 0; i < pieces.Count; i ++) + owner.Invalidate (((Piece)pieces[i]).region); + } + + internal bool Contains (int x, int y) + { + foreach (Piece p in pieces) { + if (p.region.IsVisible (new Point (x,y))) + return true; + } + return false; + } + } + + class LinkComparer : IComparer + { + public int Compare (object x, object y) + { + Link l1 = (Link)x; + Link l2 = (Link)y; + + return l1.Start - l2.Start; + } + } + + // + // ShiftUI.LinkLabel.LinkCollection + // + public class LinkCollection : IList, ICollection, IEnumerable + { + private LinkLabel owner; + private bool links_added; + + public LinkCollection (LinkLabel owner) + { + if (owner == null) + throw new ArgumentNullException ("owner"); + + this.owner = owner; + } + + [Browsable (false)] + public int Count { + get { return owner.links.Count; } + } + + public bool IsReadOnly { + get { return false; } + } + + public virtual LinkLabel.Link this[int index] { + get { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException(); + + return (LinkLabel.Link) owner.links[index]; + } + set { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException(); + + owner.links[index] = value; + } + } + + public virtual Link this[string key] { + get { + if (string.IsNullOrEmpty (key)) + return null; + + foreach (Link l in owner.links) + if (string.Compare (l.Name, key, true) == 0) + return l; + + return null; + } + } + + public int Add (Link value) + { + value.Owner = owner; + /* remove the default 0,-1 link */ + if (IsDefault) { + /* don't call Clear() here to save the additional CreateLinkPieces */ + owner.links.Clear (); + } + + int idx = owner.links.Add (value); + links_added = true; + + owner.sorted_links = null; + owner.CheckLinks (); + owner.CreateLinkPieces (); + + return idx; + } + + public Link Add (int start, int length) + { + return Add (start, length, null); + } + + internal bool IsDefault { + get { + return (Count == 1 + && this[0].Start == 0 + && this[0].length == -1); + } + } + + public Link Add (int start, int length, object linkData) + { + Link link = new Link (owner); + link.Length = length; + link.Start = start; + link.LinkData = linkData; + + int idx = Add (link); + + return (Link) owner.links[idx]; + } + + public virtual void Clear () + { + owner.links.Clear(); + owner.sorted_links = null; + owner.CreateLinkPieces (); + } + + public bool Contains (Link link) + { + return owner.links.Contains (link); + } + + public virtual bool ContainsKey (string key) + { + return !(this[key] == null); + } + + public IEnumerator GetEnumerator () + { + return owner.links.GetEnumerator (); + } + + public int IndexOf (Link link) + { + return owner.links.IndexOf (link); + } + + public virtual int IndexOfKey (string key) + { + if (string.IsNullOrEmpty (key)) + return -1; + + return IndexOf (this[key]); + } + + public bool LinksAdded { + get { return this.links_added; } + } + + public void Remove (LinkLabel.Link value) + { + owner.links.Remove (value); + owner.sorted_links = null; + owner.CreateLinkPieces (); + } + + public virtual void RemoveByKey (string key) + { + Remove (this[key]); + } + + public void RemoveAt (int index) + { + if (index >= Count) + throw new ArgumentOutOfRangeException ("Invalid value for array index"); + + owner.links.Remove (owner.links[index]); + owner.sorted_links = null; + owner.CreateLinkPieces (); + } + + bool IList.IsFixedSize { + get {return false;} + } + + object IList.this[int index] { + get { return owner.links[index]; } + set { owner.links[index] = value; } + } + + object ICollection.SyncRoot { + get {return this;} + } + + bool ICollection.IsSynchronized { + get {return false;} + } + + void ICollection.CopyTo (Array dest, int index) + { + owner.links.CopyTo (dest, index); + } + + int IList.Add (object value) + { + int idx = owner.links.Add (value); + owner.sorted_links = null; + owner.CheckLinks (); + owner.CreateLinkPieces (); + return idx; + } + + bool IList.Contains (object link) + { + return Contains ((Link) link); + } + + int IList.IndexOf (object link) + { + return owner.links.IndexOf (link); + } + + void IList.Insert (int index, object value) + { + owner.links.Insert (index, value); + owner.sorted_links = null; + owner.CheckLinks (); + owner.CreateLinkPieces (); + } + + void IList.Remove (object value) + { + Remove ((Link) value); + } + } + + [RefreshProperties (RefreshProperties.Repaint)] + public new bool UseCompatibleTextRendering { + get { + return use_compatible_text_rendering; + } + set { + use_compatible_text_rendering = value; + } + } + } +} diff --git a/source/ShiftUI/Widgets/ListBox.cs b/source/ShiftUI/Widgets/ListBox.cs new file mode 100644 index 0000000..ed705f6 --- /dev/null +++ b/source/ShiftUI/Widgets/ListBox.cs @@ -0,0 +1,3093 @@ +/// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// Mike Kestner +// + +// COMPLETE + +using System; +using System.Drawing; +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.ComponentModel.Design.Serialization; +using System.Globalization; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Collections.Generic; + +namespace ShiftUI +{ + [DefaultProperty("Items")] + [DefaultEvent("SelectedIndexChanged")] + //[Designer ("ShiftUI.Design.ListBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [DefaultBindingProperty ("SelectedValue")] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + [ToolboxWidget] + public class ListBox : ListWidget + { + public const int DefaultItemHeight = 13; + public const int NoMatches = -1; + + internal enum ItemNavigation + { + First, + Last, + Next, + Previous, + NextPage, + PreviousPage, + PreviousColumn, + NextColumn + } + + Hashtable item_heights; + private int item_height = -1; + private int column_width = 0; + private int requested_height; + private DrawMode draw_mode = DrawMode.Normal; + private int horizontal_extent = 0; + private bool horizontal_scrollbar = false; + private bool integral_height = true; + private bool multicolumn = false; + private bool scroll_always_visible = false; + private SelectedIndexCollection selected_indices; + private SelectedObjectCollection selected_items; + private SelectionMode selection_mode = SelectionMode.One; + private bool sorted = false; + private bool use_tabstops = true; + private int column_width_internal = 120; + private ImplicitVScrollBar vscrollbar; + private ImplicitHScrollBar hscrollbar; + private int hbar_offset; + private bool suspend_layout; + private bool ctrl_pressed = false; + private bool shift_pressed = false; + private bool explicit_item_height = false; + private int top_index = 0; + private int last_visible_index = 0; + private Rectangle items_area; + private int focused_item = -1; + private ObjectCollection items; + private IntegerCollection custom_tab_offsets; + private Padding padding; + private bool use_custom_tab_offsets; + + public ListBox () + { + items = CreateItemCollection (); + selected_indices = new SelectedIndexCollection (this); + selected_items = new SelectedObjectCollection (this); + + requested_height = bounds.Height; + InternalBorderStyle = BorderStyle.Fixed3D; + BackColor = ThemeEngine.Current.ColorControl; + + /* Vertical scrollbar */ + vscrollbar = new ImplicitVScrollBar (); + vscrollbar.Minimum = 0; + vscrollbar.SmallChange = 1; + vscrollbar.LargeChange = 1; + vscrollbar.Maximum = 0; + vscrollbar.ValueChanged += new EventHandler (VerticalScrollEvent); + vscrollbar.Visible = false; + + /* Horizontal scrollbar */ + hscrollbar = new ImplicitHScrollBar (); + hscrollbar.Minimum = 0; + hscrollbar.SmallChange = 1; + hscrollbar.LargeChange = 1; + hscrollbar.Maximum = 0; + hscrollbar.Visible = false; + hscrollbar.ValueChanged += new EventHandler (HorizontalScrollEvent); + + Widgets.AddImplicit (vscrollbar); + Widgets.AddImplicit (hscrollbar); + + /* Events */ + MouseDown += new MouseEventHandler (OnMouseDownLB); + MouseMove += new MouseEventHandler (OnMouseMoveLB); + MouseUp += new MouseEventHandler (OnMouseUpLB); + MouseWheel += new MouseEventHandler (OnMouseWheelLB); + KeyUp += new KeyEventHandler (OnKeyUpLB); + GotFocus += new EventHandler (OnGotFocus); + LostFocus += new EventHandler (OnLostFocus); + + SetStyle (Widgetstyles.UserPaint, false); + + custom_tab_offsets = new IntegerCollection (this); + } + + #region Events + static object DrawItemEvent = new object (); + static object MeasureItemEvent = new object (); + static object SelectedIndexChangedEvent = new object (); + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageChanged { + add { base.BackgroundImageChanged += value; } + remove { base.BackgroundImageChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageLayoutChanged { + add { base.BackgroundImageLayoutChanged += value; } + remove { base.BackgroundImageLayoutChanged -= value; } + } + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler Click { + add { base.Click += value; } + remove { base.Click -= value; } + } + + public event DrawItemEventHandler DrawItem { + add { Events.AddHandler (DrawItemEvent, value); } + remove { Events.RemoveHandler (DrawItemEvent, value); } + } + + public event MeasureItemEventHandler MeasureItem { + add { Events.AddHandler (MeasureItemEvent, value); } + remove { Events.RemoveHandler (MeasureItemEvent, value); } + } + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event MouseEventHandler MouseClick { + add { base.MouseClick += value; } + remove { base.MouseClick -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler PaddingChanged { + add { base.PaddingChanged += value; } + remove { base.PaddingChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event PaintEventHandler Paint { + add { base.Paint += value; } + remove { base.Paint -= value; } + } + + public event EventHandler SelectedIndexChanged { + add { Events.AddHandler (SelectedIndexChangedEvent, value); } + remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + #endregion // Events + + #region UIA Framework Events + //NOTE: + // We are using Reflection to add/remove internal events. + // Class ListProvider uses the events. + // + //Event used to generate UIA Selection Pattern + static object UIASelectionModeChangedEvent = new object (); + + internal event EventHandler UIASelectionModeChanged { + add { Events.AddHandler (UIASelectionModeChangedEvent, value); } + remove { Events.RemoveHandler (UIASelectionModeChangedEvent, value); } + } + + internal void OnUIASelectionModeChangedEvent () + { + EventHandler eh = (EventHandler) Events [UIASelectionModeChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + + static object UIAFocusedItemChangedEvent = new object (); + + internal event EventHandler UIAFocusedItemChanged { + add { Events.AddHandler (UIAFocusedItemChangedEvent, value); } + remove { Events.RemoveHandler (UIAFocusedItemChangedEvent, value); } + } + + internal void OnUIAFocusedItemChangedEvent () + { + EventHandler eh = (EventHandler) Events [UIAFocusedItemChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + #endregion UIA Framework Events + + #region Public Properties + public override Color BackColor { + get { return base.BackColor; } + set { + if (base.BackColor == value) + return; + + base.BackColor = value; + base.Refresh (); // Careful. Calling the base method is not the same that calling + } // the overriden one that refresh also all the items + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override Image BackgroundImage { + get { return base.BackgroundImage; } + set { + base.BackgroundImage = value; + base.Refresh (); + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + [DefaultValue (BorderStyle.Fixed3D)] + [DispId(-504)] + public BorderStyle BorderStyle { + get { return InternalBorderStyle; } + set { + InternalBorderStyle = value; + UpdateListBoxBounds (); + } + } + + [DefaultValue (0)] + [Localizable (true)] + public int ColumnWidth { + get { return column_width; } + set { + if (value < 0) + throw new ArgumentException ("A value less than zero is assigned to the property."); + + column_width = value; + + if (value == 0) + ColumnWidthInternal = 120; + else + ColumnWidthInternal = value; + + base.Refresh (); + } + } + + protected override CreateParams CreateParams { + get { return base.CreateParams;} + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + public IntegerCollection CustomTabOffsets { + get { return custom_tab_offsets; } + } + + protected override Size DefaultSize { + get { return new Size (120, 96); } + } + + [RefreshProperties(RefreshProperties.Repaint)] + [DefaultValue (DrawMode.Normal)] + public virtual DrawMode DrawMode { + get { return draw_mode; } + set { + if (!Enum.IsDefined (typeof (DrawMode), value)) + throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for DrawMode", value)); + + if (value == DrawMode.OwnerDrawVariable && multicolumn == true) + throw new ArgumentException ("Cannot have variable height and multicolumn"); + + if (draw_mode == value) + return; + + draw_mode = value; + + if (draw_mode == DrawMode.OwnerDrawVariable) + item_heights = new Hashtable (); + else + item_heights = null; + + if (Parent != null) + Parent.PerformLayout (this, "DrawMode"); + base.Refresh (); + } + } + + public override Font Font { + get { return base.Font; } + set { base.Font = value; } + } + + public override Color ForeColor { + get { return base.ForeColor; } + set { + if (base.ForeColor == value) + return; + + base.ForeColor = value; + base.Refresh (); + } + } + + [DefaultValue (0)] + [Localizable (true)] + public int HorizontalExtent { + get { return horizontal_extent; } + set { + if (horizontal_extent == value) + return; + + horizontal_extent = value; + base.Refresh (); + } + } + + [DefaultValue (false)] + [Localizable (true)] + public bool HorizontalScrollbar { + get { return horizontal_scrollbar; } + set { + if (horizontal_scrollbar == value) + return; + + horizontal_scrollbar = value; + UpdateScrollBars (); + base.Refresh (); + } + } + + [DefaultValue (true)] + [Localizable (true)] + [RefreshProperties(RefreshProperties.Repaint)] + public bool IntegralHeight { + get { return integral_height; } + set { + if (integral_height == value) + return; + + integral_height = value; + UpdateListBoxBounds (); + } + } + + [DefaultValue (13)] + [Localizable (true)] + [RefreshProperties(RefreshProperties.Repaint)] + public virtual int ItemHeight { + get { + if (item_height == -1) { + SizeF sz = TextRenderer.MeasureString ("The quick brown Fox", Font); + item_height = (int) sz.Height; + } + return item_height; + } + set { + if (value > 255) + throw new ArgumentOutOfRangeException ("The ItemHeight property was set beyond 255 pixels"); + + explicit_item_height = true; + if (item_height == value) + return; + + item_height = value; + if (IntegralHeight) + UpdateListBoxBounds (); + LayoutListBox (); + } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + [Localizable (true)] + //[Editor ("ShiftUI.Design.ListWidgetstringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + [MergableProperty (false)] + public ObjectCollection Items { + get { return items; } + } + + [DefaultValue (false)] + public bool MultiColumn { + get { return multicolumn; } + set { + if (multicolumn == value) + return; + + if (value == true && DrawMode == DrawMode.OwnerDrawVariable) + throw new ArgumentException ("A multicolumn ListBox cannot have a variable-sized height."); + + multicolumn = value; + LayoutListBox (); + Invalidate (); + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Padding Padding { + get { return padding; } + set { padding = value; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public int PreferredHeight { + get { + int itemsHeight = 0; + if (draw_mode == DrawMode.Normal) + itemsHeight = FontHeight * items.Count; + else if (draw_mode == DrawMode.OwnerDrawFixed) + itemsHeight = ItemHeight * items.Count; + else if (draw_mode == DrawMode.OwnerDrawVariable) { + for (int i = 0; i < items.Count; i++) + itemsHeight += (int) item_heights [Items [i]]; + } + + return itemsHeight; + } + } + + public override RightToLeft RightToLeft { + get { return base.RightToLeft; } + set { + base.RightToLeft = value; + if (base.RightToLeft == RightToLeft.Yes) + StringFormat.Alignment = StringAlignment.Far; + else + StringFormat.Alignment = StringAlignment.Near; + base.Refresh (); + } + } + + // Only affects the Vertical ScrollBar + [DefaultValue (false)] + [Localizable (true)] + public bool ScrollAlwaysVisible { + get { return scroll_always_visible; } + set { + if (scroll_always_visible == value) + return; + + scroll_always_visible = value; + UpdateScrollBars (); + } + } + + [Bindable(true)] + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override int SelectedIndex { + get { + if (selected_indices == null) + return -1; + + return selected_indices.Count > 0 ? selected_indices [0] : -1; + } + set { + if (value < -1 || value >= Items.Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + if (SelectionMode == SelectionMode.None) + throw new ArgumentException ("cannot call this method if SelectionMode is SelectionMode.None"); + + if (value == -1) + selected_indices.Clear (); + else + selected_indices.Add (value); + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public SelectedIndexCollection SelectedIndices { + get { return selected_indices; } + } + + [Bindable(true)] + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public object SelectedItem { + get { + if (SelectedItems.Count > 0) + return SelectedItems[0]; + else + return null; + } + set { + if (value != null && !Items.Contains (value)) + return; // FIXME: this is probably an exception + + SelectedIndex = value == null ? - 1 : Items.IndexOf (value); + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public SelectedObjectCollection SelectedItems { + get {return selected_items;} + } + + [DefaultValue (SelectionMode.One)] + public virtual SelectionMode SelectionMode { + get { return selection_mode; } + set { + if (!Enum.IsDefined (typeof (SelectionMode), value)) + throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for SelectionMode", value)); + + if (selection_mode == value) + return; + + selection_mode = value; + + switch (selection_mode) { + case SelectionMode.None: + SelectedIndices.Clear (); + break; + + case SelectionMode.One: + // FIXME: Probably this can be improved + ArrayList old_selection = (ArrayList) SelectedIndices.List.Clone (); + for (int i = 1; i < old_selection.Count; i++) + SelectedIndices.Remove ((int)old_selection [i]); + break; + + default: + break; + } + + // UIA Framework: Generates SelectionModeChanged event. + OnUIASelectionModeChangedEvent (); + } + } + + [DefaultValue (false)] + public bool Sorted { + get { return sorted; } + set { + if (sorted == value) + return; + + sorted = value; + if (sorted) + Sort (); + } + } + + [Bindable (false)] + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public override string Text { + get { + if (SelectionMode != SelectionMode.None && SelectedIndex != -1) + return GetItemText (SelectedItem); + + return base.Text; + } + set { + + base.Text = value; + + if (SelectionMode == SelectionMode.None) + return; + + int index; + + index = FindStringExact (value); + + if (index == -1) + return; + + SelectedIndex = index; + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public int TopIndex { + get { return top_index; } + set { + if (value == top_index) + return; + + if (value < 0 || value >= Items.Count) + return; + + int page_size = (items_area.Height / ItemHeight); + + if (Items.Count < page_size) + value = 0; + else if (!multicolumn) + top_index = Math.Min (value, Items.Count - page_size); + else + top_index = value; + + UpdateTopItem (); + base.Refresh (); + } + } + + [Browsable (false)] + [DefaultValue (false)] + public bool UseCustomTabOffsets { + get { return use_custom_tab_offsets; } + set { + if (use_custom_tab_offsets != value) { + use_custom_tab_offsets = value; + CalculateTabStops (); + } + } + } + + [DefaultValue (true)] + public bool UseTabStops { + get { return use_tabstops; } + set { + if (use_tabstops == value) + return; + + use_tabstops = value; + CalculateTabStops (); + } + } + + protected override bool AllowSelection { + get { + return SelectionMode != SelectionMode.None; + } + } + #endregion Public Properties + + #region Private Properties + + private int ColumnWidthInternal { + get { return column_width_internal; } + set { column_width_internal = value; } + } + + private int row_count = 1; + private int RowCount { + get { + return MultiColumn ? row_count : Items.Count; + } + } + + #endregion Private Properties + + #region UIA Framework Properties + + internal ScrollBar UIAHScrollBar { + get { return hscrollbar; } + } + + internal ScrollBar UIAVScrollBar { + get { return vscrollbar; } + } + + #endregion UIA Framework Properties + + #region Public Methods + [Obsolete ("this method has been deprecated")] + protected virtual void AddItemsCore (object[] value) + { + Items.AddRange (value); + } + + public void BeginUpdate () + { + suspend_layout = true; + } + + public void ClearSelected () + { + selected_indices.Clear (); + } + + protected virtual ObjectCollection CreateItemCollection () + { + return new ObjectCollection (this); + } + + public void EndUpdate () + { + suspend_layout = false; + LayoutListBox (); + base.Refresh (); + } + + public int FindString (String s) + { + return FindString (s, -1); + } + + public int FindString (string s, int startIndex) + { + if (Items.Count == 0) + return -1; // No exception throwing if empty + + if (startIndex < -1 || startIndex >= Items.Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + startIndex = (startIndex == Items.Count - 1) ? 0 : startIndex + 1; + + int i = startIndex; + while (true) { + string text = GetItemText (Items [i]); + if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (text, s, + CompareOptions.IgnoreCase)) + return i; + + i = (i == Items.Count - 1) ? 0 : i + 1; + if (i == startIndex) + break; + } + + return NoMatches; + } + + public int FindStringExact (string s) + { + return FindStringExact (s, -1); + } + + public int FindStringExact (string s, int startIndex) + { + if (Items.Count == 0) + return -1; // No exception throwing if empty + + if (startIndex < -1 || startIndex >= Items.Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + startIndex = (startIndex + 1 == Items.Count) ? 0 : startIndex + 1; + + int i = startIndex; + while (true) { + if (String.Compare (GetItemText (Items[i]), s, true) == 0) + return i; + + i = (i + 1 == Items.Count) ? 0 : i + 1; + if (i == startIndex) + break; + } + + return NoMatches; + } + + public int GetItemHeight (int index) + { + if (index < 0 || index >= Items.Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + if (DrawMode == DrawMode.OwnerDrawVariable && IsHandleCreated == true) { + + object o = Items [index]; + if (item_heights.Contains (o)) + return (int) item_heights [o]; + + MeasureItemEventArgs args = new MeasureItemEventArgs (DeviceContext, index, ItemHeight); + OnMeasureItem (args); + item_heights [o] = args.ItemHeight; + return args.ItemHeight; + } + + return ItemHeight; + } + + public Rectangle GetItemRectangle (int index) + { + if (index < 0 || index >= Items.Count) + throw new ArgumentOutOfRangeException ("GetItemRectangle index out of range."); + + Rectangle rect = new Rectangle (); + + if (MultiColumn) { + int col = index / RowCount; + int y = index; + if (y < 0) // We convert it to valid positive value + y += RowCount * (top_index / RowCount); + rect.Y = (y % RowCount) * ItemHeight; + rect.X = (col - (top_index / RowCount)) * ColumnWidthInternal; + rect.Height = ItemHeight; + rect.Width = ColumnWidthInternal; + } else { + rect.X = 0; + rect.Height = GetItemHeight (index); + rect.Width = items_area.Width; + + if (DrawMode == DrawMode.OwnerDrawVariable) { + rect.Y = 0; + if (index >= top_index) { + for (int i = top_index; i < index; i++) { + rect.Y += GetItemHeight (i); + } + } else { + for (int i = index; i < top_index; i++) { + rect.Y -= GetItemHeight (i); + } + } + } else { + rect.Y = ItemHeight * (index - top_index); + } + } + + if (this is CheckedListBox) + rect.Width += 15; + + return rect; + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override Rectangle GetScaledBounds (Rectangle bounds, SizeF factor, BoundsSpecified specified) + { + bounds.Height = requested_height; + + return base.GetScaledBounds (bounds, factor, specified); + } + + public bool GetSelected (int index) + { + if (index < 0 || index >= Items.Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + return SelectedIndices.Contains (index); + } + + public int IndexFromPoint (Point p) + { + return IndexFromPoint (p.X, p.Y); + } + + // Only returns visible points + public int IndexFromPoint (int x, int y) + { + + if (Items.Count == 0) { + return -1; + } + + for (int i = top_index; i <= last_visible_index; i++) { + if (GetItemRectangle (i).Contains (x,y) == true) + return i; + } + + return -1; + } + + protected override void OnChangeUICues (UICuesEventArgs e) + { + base.OnChangeUICues (e); + } + + protected override void OnDataSourceChanged (EventArgs e) + { + base.OnDataSourceChanged (e); + BindDataItems (); + + if (DataSource == null || DataManager == null) { + SelectedIndex = -1; + } else { + SelectedIndex = DataManager.Position; + } + } + + protected override void OnDisplayMemberChanged (EventArgs e) + { + base.OnDisplayMemberChanged (e); + + if (DataManager == null || !IsHandleCreated) + return; + + BindDataItems (); + base.Refresh (); + } + + protected virtual void OnDrawItem (DrawItemEventArgs e) + { + switch (DrawMode) { + case DrawMode.OwnerDrawFixed: + case DrawMode.OwnerDrawVariable: + DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]); + if (eh != null) + eh (this, e); + + break; + + default: + ThemeEngine.Current.DrawListBoxItem (this, e); + break; + } + } + + protected override void OnFontChanged (EventArgs e) + { + base.OnFontChanged (e); + + if (use_tabstops) + StringFormat.SetTabStops (0, new float [] {(float)(Font.Height * 3.7)}); + + if (explicit_item_height) { + base.Refresh (); + } else { + SizeF sz = TextRenderer.MeasureString ("The quick brown Fox", Font); + item_height = (int) sz.Height; + if (IntegralHeight) + UpdateListBoxBounds (); + LayoutListBox (); + } + } + + protected override void OnHandleCreated (EventArgs e) + { + base.OnHandleCreated (e); + + if (IntegralHeight) + UpdateListBoxBounds (); + + LayoutListBox (); + EnsureVisible (focused_item); + } + + protected override void OnHandleDestroyed (EventArgs e) + { + base.OnHandleDestroyed (e); + } + + protected virtual void OnMeasureItem (MeasureItemEventArgs e) + { + if (draw_mode != DrawMode.OwnerDrawVariable) + return; + + MeasureItemEventHandler eh = (MeasureItemEventHandler)(Events [MeasureItemEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnParentChanged (EventArgs e) + { + base.OnParentChanged (e); + } + + protected override void OnResize (EventArgs e) + { + base.OnResize (e); + if (canvas_size.IsEmpty || MultiColumn) + LayoutListBox (); + + Invalidate (); + } + + protected override void OnSelectedIndexChanged (EventArgs e) + { + base.OnSelectedIndexChanged (e); + + EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnSelectedValueChanged (EventArgs e) + { + base.OnSelectedValueChanged (e); + } + + public override void Refresh () + { + if (draw_mode == DrawMode.OwnerDrawVariable) + item_heights.Clear (); + + base.Refresh (); + } + + protected override void RefreshItem (int index) + { + if (index < 0 || index >= Items.Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + if (draw_mode == DrawMode.OwnerDrawVariable) + item_heights.Remove (Items [index]); + } + + protected override void RefreshItems () + { + for (int i = 0; i < Items.Count; i++) { + RefreshItem (i); + } + + LayoutListBox (); + Refresh (); + } + + public override void ResetBackColor () + { + base.ResetBackColor (); + } + + public override void ResetForeColor () + { + base.ResetForeColor (); + } + + protected override void ScaleWidget (SizeF factor, BoundsSpecified specified) + { + base.ScaleWidget (factor, specified); + } + + private int SnapHeightToIntegral (int height) + { + int border; + + switch (border_style) { + case BorderStyle.Fixed3D: + border = ThemeEngine.Current.Border3DSize.Height; + break; + case BorderStyle.FixedSingle: + border = ThemeEngine.Current.BorderSize.Height; + break; + case BorderStyle.None: + default: + border = 0; + break; + } + + height -= (2 * border); + height -= height % ItemHeight; + height += (2 * border); + + return height; + } + + protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified) + { + if ((specified & BoundsSpecified.Height) == BoundsSpecified.Height) + requested_height = height; + + if (IntegralHeight && IsHandleCreated) + height = SnapHeightToIntegral (height); + + base.SetBoundsCore (x, y, width, height, specified); + UpdateScrollBars (); + last_visible_index = LastVisibleItem (); + } + + protected override void SetItemCore (int index, object value) + { + if (index < 0 || index >= Items.Count) + return; + + Items[index] = value; + } + + protected override void SetItemsCore (IList value) + { + BeginUpdate (); + try { + Items.Clear (); + Items.AddItems (value); + } finally { + EndUpdate (); + } + } + + public void SetSelected (int index, bool value) + { + if (index < 0 || index >= Items.Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + if (SelectionMode == SelectionMode.None) + throw new InvalidOperationException (); + + if (value) + SelectedIndices.Add (index); + else + SelectedIndices.Remove (index); + } + + protected virtual void Sort () + { + Sort (true); + } + + // + // Sometimes we could need to Sort, and request a Refresh + // in a different place, to not have the painting done twice + // + void Sort (bool paint) + { + if (Items.Count == 0) + return; + + Items.Sort (); + + if (paint) + base.Refresh (); + } + + public override string ToString () + { + return base.ToString (); + } + + protected virtual void WmReflectCommand (ref Message m) + { + } + + protected override void WndProc (ref Message m) + { + if ((Msg)m.Msg == Msg.WM_KEYDOWN) { + if (ProcessKeyMessage (ref m)) + m.Result = IntPtr.Zero; + else { + HandleKeyDown ((Keys)m.WParam.ToInt32 ()); + DefWndProc (ref m); + } + + return; + } + + base.WndProc (ref m); + } + + #endregion Public Methods + + #region Private Methods + + private void CalculateTabStops () + { + if (use_tabstops) { + if (use_custom_tab_offsets) { + float[] f = new float[custom_tab_offsets.Count]; + custom_tab_offsets.CopyTo (f, 0); + StringFormat.SetTabStops (0, f); + } + else + StringFormat.SetTabStops (0, new float[] { (float)(Font.Height * 3.7) }); + } else + StringFormat.SetTabStops (0, new float[0]); + + this.Invalidate (); + } + + private Size canvas_size; + + private void LayoutListBox () + { + if (!IsHandleCreated || suspend_layout) + return; + + if (MultiColumn) + LayoutMultiColumn (); + else + LayoutSingleColumn (); + + last_visible_index = LastVisibleItem (); + UpdateScrollBars (); + } + + private void LayoutSingleColumn () + { + int height, width; + + switch (DrawMode) { + case DrawMode.OwnerDrawVariable: + height = 0; + width = HorizontalExtent; + for (int i = 0; i < Items.Count; i++) { + height += GetItemHeight (i); + } + break; + + case DrawMode.OwnerDrawFixed: + height = Items.Count * ItemHeight; + width = HorizontalExtent; + break; + + case DrawMode.Normal: + default: + height = Items.Count * ItemHeight; + width = 0; + for (int i = 0; i < Items.Count; i++) { + SizeF sz = TextRenderer.MeasureString (GetItemText (Items[i]), Font); + int t = (int)sz.Width; + + if (this is CheckedListBox) + t += 15; + + if (t > width) + width = t; + } + break; + } + + canvas_size = new Size (width, height); + } + + private void LayoutMultiColumn () + { + int usable_height = ClientRectangle.Height - (ScrollAlwaysVisible ? hscrollbar.Height : 0); + row_count = Math.Max (1, usable_height / ItemHeight); + + int cols = (int) Math.Ceiling ((float)Items.Count / (float) row_count); + Size sz = new Size (cols * ColumnWidthInternal, row_count * ItemHeight); + if (!ScrollAlwaysVisible && sz.Width > ClientRectangle.Width && row_count > 1) { + usable_height = ClientRectangle.Height - hscrollbar.Height; + row_count = Math.Max (1, usable_height / ItemHeight); + cols = (int) Math.Ceiling ((float)Items.Count / (float) row_count); + sz = new Size (cols * ColumnWidthInternal, row_count * ItemHeight); + } + canvas_size = sz; + } + + internal void Draw (Rectangle clip, Graphics dc) + { + Theme theme = ThemeEngine.Current; + + if (hscrollbar.Visible && vscrollbar.Visible) { + // Paint the dead space in the bottom right corner + Rectangle rect = new Rectangle (hscrollbar.Right, vscrollbar.Bottom, vscrollbar.Width, hscrollbar.Height); + if (rect.IntersectsWith (clip)) + dc.FillRectangle (theme.ResPool.GetSolidBrush (theme.ColorControl), rect); + } + + dc.FillRectangle (theme.ResPool.GetSolidBrush (BackColor), items_area); + + if (Items.Count == 0) + return; + + for (int i = top_index; i <= last_visible_index; i++) { + Rectangle rect = GetItemDisplayRectangle (i, top_index); + + if (!clip.IntersectsWith (rect)) + continue; + + DrawItemState state = DrawItemState.None; + + if (SelectedIndices.Contains (i)) + state |= DrawItemState.Selected; + + if (has_focus && FocusedItem == i) + state |= DrawItemState.Focus; + + if (MultiColumn == false && hscrollbar != null && hscrollbar.Visible) { + rect.X -= hscrollbar.Value; + rect.Width += hscrollbar.Value; + } + + Color fore_color = !Enabled ? ThemeEngine.Current.ColorGrayText : + (state & DrawItemState.Selected) != 0 ? ThemeEngine.Current.ColorHighlightText : ForeColor; + OnDrawItem (new DrawItemEventArgs (dc, Font, rect, i, state, fore_color, BackColor)); + } + } + + // Converts a GetItemRectangle to a one that we can display + internal Rectangle GetItemDisplayRectangle (int index, int first_displayble) + { + Rectangle item_rect; + Rectangle first_item_rect = GetItemRectangle (first_displayble); + item_rect = GetItemRectangle (index); + item_rect.X -= first_item_rect.X; + item_rect.Y -= first_item_rect.Y; + + // Subtract the checkboxes from the width + if (this is CheckedListBox) + item_rect.Width -= 14; + + return item_rect; + } + + // Value Changed + private void HorizontalScrollEvent (object sender, EventArgs e) + { + if (multicolumn) { + int top_item = top_index; + int last_item = last_visible_index; + + top_index = RowCount * hscrollbar.Value; + last_visible_index = LastVisibleItem (); + + if (top_item != top_index || last_item != last_visible_index) + Invalidate (items_area); + } + else { + int old_offset = hbar_offset; + hbar_offset = hscrollbar.Value; + + if (hbar_offset < 0) + hbar_offset = 0; + + if (IsHandleCreated) { + XplatUI.ScrollWindow (Handle, items_area, old_offset - hbar_offset, 0, false); + + // Invalidate the previous selection border, to keep it properly updated. + Rectangle selection_border_area = new Rectangle (items_area.Width - (hbar_offset - old_offset) - 3, 0, + 3, items_area.Height); + Invalidate (selection_border_area); + } + } + } + + // Only returns visible points. The diference of with IndexFromPoint is that the rectangle + // has screen coordinates + private int IndexAtClientPoint (int x, int y) + { + if (Items.Count == 0) + return -1; + + if (x < 0) + x = 0; + else if (x > ClientRectangle.Right) + x = ClientRectangle.Right; + + if (y < 0) + y = 0; + else if (y > ClientRectangle.Bottom) + y = ClientRectangle.Bottom; + + for (int i = top_index; i <= last_visible_index; i++) + if (GetItemDisplayRectangle (i, top_index).Contains (x, y)) + return i; + + return -1; + } + + internal override bool IsInputCharInternal (char charCode) + { + return true; + } + + private int LastVisibleItem () + { + Rectangle item_rect; + int top_y = items_area.Y + items_area.Height; + int i = 0; + + if (top_index >= Items.Count) + return top_index; + + for (i = top_index; i < Items.Count; i++) { + item_rect = GetItemDisplayRectangle (i, top_index); + if (MultiColumn) { + if (item_rect.X > items_area.Width) + return i - 1; + } else { + if (item_rect.Y + item_rect.Height > top_y) + return i; + } + } + return i - 1; + } + + private void UpdateTopItem () + { + if (MultiColumn) { + int col = top_index / RowCount; + + if (col > hscrollbar.Maximum) + hscrollbar.Value = hscrollbar.Maximum; + else + hscrollbar.Value = col; + } else { + if (top_index > vscrollbar.Maximum) + vscrollbar.Value = vscrollbar.Maximum; + else + vscrollbar.Value = top_index; + Scroll (vscrollbar, vscrollbar.Value - top_index); + } + } + + // Navigates to the indicated item and returns the new item + private int NavigateItemVisually (ItemNavigation navigation) + { + int page_size, columns, selected_index = -1; + + if (multicolumn) { + columns = items_area.Width / ColumnWidthInternal; + page_size = columns * RowCount; + if (page_size == 0) { + page_size = RowCount; + } + } else { + page_size = items_area.Height / ItemHeight; + } + + switch (navigation) { + + case ItemNavigation.PreviousColumn: { + if (SelectedIndex - RowCount < 0) { + return -1; + } + + if (SelectedIndex - RowCount < top_index) { + top_index = SelectedIndex - RowCount; + UpdateTopItem (); + } + + selected_index = SelectedIndex - RowCount; + break; + } + + case ItemNavigation.NextColumn: { + if (SelectedIndex + RowCount >= Items.Count) { + break; + } + + if (SelectedIndex + RowCount > last_visible_index) { + top_index = SelectedIndex; + UpdateTopItem (); + } + + selected_index = SelectedIndex + RowCount; + break; + } + + case ItemNavigation.First: { + top_index = 0; + selected_index = 0; + UpdateTopItem (); + break; + } + + case ItemNavigation.Last: { + + int rows = items_area.Height / ItemHeight; + + if (multicolumn) { + selected_index = Items.Count - 1; + break; + } + if (Items.Count < rows) { + top_index = 0; + selected_index = Items.Count - 1; + UpdateTopItem (); + } else { + top_index = Items.Count - rows; + selected_index = Items.Count - 1; + UpdateTopItem (); + } + break; + } + + case ItemNavigation.Next: { + if (FocusedItem == Items.Count - 1) + return -1; + + if (multicolumn) { + selected_index = FocusedItem + 1; + break; + } + + int bottom = 0; + ArrayList heights = new ArrayList (); + if (draw_mode == DrawMode.OwnerDrawVariable) { + for (int i = top_index; i <= FocusedItem + 1; i++) { + int h = GetItemHeight (i); + bottom += h; + heights.Add (h); + } + } else { + bottom = ((FocusedItem + 1) - top_index + 1) * ItemHeight; + } + + if (bottom >= items_area.Height) { + int overhang = bottom - items_area.Height; + + int offset = 0; + if (draw_mode == DrawMode.OwnerDrawVariable) + while (overhang > 0) + overhang -= (int) heights [offset]; + else + offset = (int) Math.Ceiling ((float)overhang / (float) ItemHeight); + top_index += offset; + UpdateTopItem (); + } + selected_index = FocusedItem + 1; + break; + } + + case ItemNavigation.Previous: { + if (FocusedItem > 0) { + if (FocusedItem - 1 < top_index) { + top_index--; + UpdateTopItem (); + } + selected_index = FocusedItem - 1; + } + break; + } + + case ItemNavigation.NextPage: { + if (Items.Count < page_size) { + NavigateItemVisually (ItemNavigation.Last); + break; + } + + if (FocusedItem + page_size - 1 >= Items.Count) { + top_index = Items.Count - page_size; + UpdateTopItem (); + selected_index = Items.Count - 1; + } + else { + if (FocusedItem + page_size - 1 > last_visible_index) { + top_index = FocusedItem; + UpdateTopItem (); + } + + selected_index = FocusedItem + page_size - 1; + } + + break; + } + + case ItemNavigation.PreviousPage: { + + int rows = items_area.Height / ItemHeight; + if (FocusedItem - (rows - 1) <= 0) { + top_index = 0; + UpdateTopItem (); + selected_index = 0; + } + else { + if (SelectedIndex - (rows - 1) < top_index) { + top_index = FocusedItem - (rows - 1); + UpdateTopItem (); + } + + selected_index = FocusedItem - (rows - 1); + } + + break; + } + default: + break; + } + + return selected_index; + } + + + private void OnGotFocus (object sender, EventArgs e) + { + if (Items.Count == 0) + return; + + if (FocusedItem == -1) + FocusedItem = 0; + + InvalidateItem (FocusedItem); + } + + private void OnLostFocus (object sender, EventArgs e) + { + if (FocusedItem != -1) + InvalidateItem (FocusedItem); + } + + private bool KeySearch (Keys key) + { + char c = (char) key; + if (!Char.IsLetterOrDigit (c)) + return false; + + int idx = FindString (c.ToString (), SelectedIndex); + if (idx != ListBox.NoMatches) + SelectedIndex = idx; + + return true; + } + + internal void HandleKeyDown (Keys key) + { + int new_item = -1; + + if (Items.Count == 0) + return; + + if (KeySearch (key)) + return; + + switch (key) { + + case Keys.ControlKey: + ctrl_pressed = true; + break; + + case Keys.ShiftKey: + shift_pressed = true; + break; + + case Keys.Home: + new_item = NavigateItemVisually (ItemNavigation.First); + break; + + case Keys.End: + new_item = NavigateItemVisually (ItemNavigation.Last); + break; + + case Keys.Up: + new_item = NavigateItemVisually (ItemNavigation.Previous); + break; + + case Keys.Down: + new_item = NavigateItemVisually (ItemNavigation.Next); + break; + + case Keys.PageUp: + new_item = NavigateItemVisually (ItemNavigation.PreviousPage); + break; + + case Keys.PageDown: + new_item = NavigateItemVisually (ItemNavigation.NextPage); + break; + + case Keys.Right: + if (multicolumn == true) { + new_item = NavigateItemVisually (ItemNavigation.NextColumn); + } + break; + + case Keys.Left: + if (multicolumn == true) { + new_item = NavigateItemVisually (ItemNavigation.PreviousColumn); + } + break; + + case Keys.Space: + if (selection_mode == SelectionMode.MultiSimple) { + SelectedItemFromNavigation (FocusedItem); + } + break; + + + default: + break; + } + + if (new_item != -1) { + FocusedItem = new_item; + + if (selection_mode != SelectionMode.MultiSimple) + SelectedItemFromNavigation (new_item); + } + } + + private void OnKeyUpLB (object sender, KeyEventArgs e) + { + switch (e.KeyCode) { + case Keys.ControlKey: + ctrl_pressed = false; + break; + case Keys.ShiftKey: + shift_pressed = false; + break; + default: + break; + } + } + + internal void InvalidateItem (int index) + { + if (!IsHandleCreated) + return; + Rectangle bounds = GetItemDisplayRectangle (index, top_index); + if (ClientRectangle.IntersectsWith (bounds)) + Invalidate (bounds); + } + + internal virtual void OnItemClick (int index) + { + OnSelectedIndexChanged (EventArgs.Empty); + OnSelectedValueChanged (EventArgs.Empty); + } + + int anchor = -1; + int[] prev_selection; + bool button_pressed = false; + Point button_pressed_loc = new Point (-1, -1); + + private void SelectExtended (int index) + { + SuspendLayout (); + + ArrayList new_selection = new ArrayList (); + int start = anchor < index ? anchor : index; + int end = anchor > index ? anchor : index; + for (int i = start; i <= end; i++) + new_selection.Add (i); + + if (ctrl_pressed) + foreach (int i in prev_selection) + if (!new_selection.Contains (i)) + new_selection.Add (i); + + // Need to make a copy since we can't enumerate and modify the collection + // at the same time + ArrayList sel_indices = (ArrayList) selected_indices.List.Clone (); + foreach (int i in sel_indices) + if (!new_selection.Contains (i)) + selected_indices.Remove (i); + + foreach (int i in new_selection) + if (!sel_indices.Contains (i)) + selected_indices.AddCore (i); + ResumeLayout (); + } + + private void OnMouseDownLB (object sender, MouseEventArgs e) + { + // Only do stuff with the left mouse button + if ((e.Button & MouseButtons.Left) == 0) + return; + + int index = IndexAtClientPoint (e.X, e.Y); + if (index == -1) + return; + + switch (SelectionMode) { + case SelectionMode.One: + SelectedIndices.AddCore (index); // Unselects previous one + break; + + case SelectionMode.MultiSimple: + if (SelectedIndices.Contains (index)) + SelectedIndices.RemoveCore (index); + else + SelectedIndices.AddCore (index); + break; + + case SelectionMode.MultiExtended: + shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0; + ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Widget) != 0; + + if (shift_pressed) { + SelectedIndices.ClearCore (); + SelectExtended (index); + break; + } + + anchor = index; + + if (ctrl_pressed) { + prev_selection = new int [SelectedIndices.Count]; + SelectedIndices.CopyTo (prev_selection, 0); + + if (SelectedIndices.Contains (index)) + SelectedIndices.RemoveCore (index); + else + SelectedIndices.AddCore (index); + + break; + } + + SelectedIndices.ClearCore (); + SelectedIndices.AddCore (index); + break; + + case SelectionMode.None: + break; + default: + return; + } + + button_pressed = true; + button_pressed_loc = new Point (e.X, e.Y); + FocusedItem = index; + } + + private void OnMouseMoveLB (object sender, MouseEventArgs e) + { + // Don't take into account MouseMove events generated with MouseDown + if (!button_pressed || button_pressed_loc == new Point (e.X, e.Y)) + return; + + int index = IndexAtClientPoint (e.X, e.Y); + if (index == -1) + return; + + switch (SelectionMode) { + case SelectionMode.One: + SelectedIndices.AddCore (index); // Unselects previous one + break; + + case SelectionMode.MultiSimple: + break; + + case SelectionMode.MultiExtended: + SelectExtended (index); + break; + + case SelectionMode.None: + break; + default: + return; + } + + FocusedItem = index; + } + + internal override void OnDragDropEnd (DragDropEffects effects) + { + // In the case of a DnD operation (started on MouseDown) + // there will be no MouseUp event, so we need to reset + // the state here + button_pressed = false; + } + + private void OnMouseUpLB (object sender, MouseEventArgs e) + { + // Only do stuff with the left mouse button + if ((e.Button & MouseButtons.Left) == 0) + return; + + if (e.Clicks > 1) { + OnDoubleClick (EventArgs.Empty); + OnMouseDoubleClick (e); + } + else if (e.Clicks == 1) { + OnClick (EventArgs.Empty); + OnMouseClick (e); + } + + if (!button_pressed) + return; + + int index = IndexAtClientPoint (e.X, e.Y); + OnItemClick (index); + button_pressed = ctrl_pressed = shift_pressed = false; + } + + private void Scroll (ScrollBar scrollbar, int delta) + { + if (delta == 0 || !scrollbar.Visible || !scrollbar.Enabled) + return; + + int max; + if (scrollbar == hscrollbar) + max = hscrollbar.Maximum - (items_area.Width / ColumnWidthInternal) + 1; + else + max = vscrollbar.Maximum - (items_area.Height / ItemHeight) + 1; + + int val = scrollbar.Value + delta; + if (val > max) + val = max; + else if (val < scrollbar.Minimum) + val = scrollbar.Minimum; + scrollbar.Value = val; + } + + private void OnMouseWheelLB (object sender, MouseEventArgs me) + { + if (Items.Count == 0) + return; + + int lines = me.Delta / 120; + + if (MultiColumn) + Scroll (hscrollbar, -SystemInformation.MouseWheelScrollLines * lines); + else + Scroll (vscrollbar, -lines); + } + + internal override void OnPaintInternal (PaintEventArgs pevent) + { + if (suspend_layout) + return; + + Draw (pevent.ClipRectangle, pevent.Graphics); + } + + internal void RepositionScrollBars () + { + if (vscrollbar.is_visible) { + vscrollbar.Size = new Size (vscrollbar.Width, items_area.Height); + vscrollbar.Location = new Point (items_area.Width, 0); + } + + if (hscrollbar.is_visible) { + hscrollbar.Size = new Size (items_area.Width, hscrollbar.Height); + hscrollbar.Location = new Point (0, items_area.Height); + } + } + + // An item navigation operation (mouse or keyboard) has caused to select a new item + internal void SelectedItemFromNavigation (int index) + { + switch (SelectionMode) { + case SelectionMode.None: + // .Net doesn't select the item, only ensures that it's visible + // and fires the selection related events + EnsureVisible (index); + OnSelectedIndexChanged (EventArgs.Empty); + OnSelectedValueChanged (EventArgs.Empty); + break; + case SelectionMode.One: { + SelectedIndex = index; + break; + } + case SelectionMode.MultiSimple: { + if (SelectedIndex == -1) { + SelectedIndex = index; + } else { + + if (SelectedIndices.Contains (index)) + SelectedIndices.Remove (index); + else { + SelectedIndices.AddCore (index); + + OnSelectedIndexChanged (EventArgs.Empty); + OnSelectedValueChanged (EventArgs.Empty); + } + } + break; + } + + case SelectionMode.MultiExtended: { + if (SelectedIndex == -1) { + SelectedIndex = index; + } else { + + if (ctrl_pressed == false && shift_pressed == false) { + SelectedIndices.Clear (); + } + + if (shift_pressed == true) { + ShiftSelection (index); + } else { // ctrl_pressed or single item + SelectedIndices.AddCore (index); + + } + + OnSelectedIndexChanged (EventArgs.Empty); + OnSelectedValueChanged (EventArgs.Empty); + } + break; + } + + default: + break; + } + } + + private void ShiftSelection (int index) + { + int shorter_item = -1, dist = Items.Count + 1, cur_dist; + + foreach (int idx in selected_indices) { + if (idx > index) { + cur_dist = idx - index; + } else { + cur_dist = index - idx; + } + + if (cur_dist < dist) { + dist = cur_dist; + shorter_item = idx; + } + } + + if (shorter_item != -1) { + int start, end; + + if (shorter_item > index) { + start = index; + end = shorter_item; + } else { + start = shorter_item; + end = index; + } + + selected_indices.Clear (); + for (int idx = start; idx <= end; idx++) { + selected_indices.AddCore (idx); + } + } + } + + internal int FocusedItem { + get { return focused_item; } + set { + if (focused_item == value) + return; + + int prev = focused_item; + + focused_item = value; + + if (has_focus == false) + return; + + if (prev != -1) + InvalidateItem (prev); + + if (value != -1) + InvalidateItem (value); + + // UIA Framework: Generates FocusedItemChanged event. + OnUIAFocusedItemChangedEvent (); + } + } + + StringFormat string_format; + internal StringFormat StringFormat { + get { + if (string_format == null) { + string_format = new StringFormat (); + string_format.FormatFlags = StringFormatFlags.NoWrap; + + if (RightToLeft == RightToLeft.Yes) + string_format.Alignment = StringAlignment.Far; + else + string_format.Alignment = StringAlignment.Near; + CalculateTabStops (); + } + return string_format; + } + } + + internal virtual void CollectionChanged () + { + if (sorted) + Sort (false); + + if (Items.Count == 0) { + selected_indices.List.Clear (); + focused_item = -1; + top_index = 0; + } + if (Items.Count <= focused_item) + focused_item = Items.Count - 1; + + if (!IsHandleCreated || suspend_layout) + return; + + LayoutListBox (); + + base.Refresh (); + } + + void EnsureVisible (int index) + { + if (!IsHandleCreated || index == -1) + return; + + if (index < top_index) { + top_index = index; + UpdateTopItem (); + Invalidate (); + } else if (!multicolumn) { + int rows = items_area.Height / ItemHeight; + if (index >= (top_index + rows)) + top_index = index - rows + 1; + + UpdateTopItem (); + } else { + int rows = Math.Max (1, items_area.Height / ItemHeight); + int cols = Math.Max (1, items_area.Width / ColumnWidthInternal); + + if (index >= (top_index + (rows * cols))) { + int incolumn = index / rows; + top_index = (incolumn - (cols - 1)) * rows; + + UpdateTopItem (); + Invalidate (); + } + } + } + + private void UpdateListBoxBounds () + { + if (IsHandleCreated) + SetBoundsInternal (bounds.X, bounds.Y, bounds.Width, IntegralHeight ? SnapHeightToIntegral (requested_height) : requested_height, BoundsSpecified.None); + } + + private void UpdateScrollBars () + { + items_area = ClientRectangle; + if (UpdateHorizontalScrollBar ()) { + items_area.Height -= hscrollbar.Height; + if (UpdateVerticalScrollBar ()) { + items_area.Width -= vscrollbar.Width; + UpdateHorizontalScrollBar (); + } + } else if (UpdateVerticalScrollBar ()) { + items_area.Width -= vscrollbar.Width; + if (UpdateHorizontalScrollBar ()) { + items_area.Height -= hscrollbar.Height; + UpdateVerticalScrollBar (); + } + } + + RepositionScrollBars (); + } + + /* Determines if the horizontal scrollbar has to be displyed */ + private bool UpdateHorizontalScrollBar () + { + bool show = false; + bool enabled = true; + + if (MultiColumn) { + if (canvas_size.Width > items_area.Width) { + show = true; + hscrollbar.Maximum = canvas_size.Width / ColumnWidthInternal - 1; + } else if (ScrollAlwaysVisible == true) { + enabled = false; + show = true; + hscrollbar.Maximum = 0; + } + } else if (canvas_size.Width > ClientRectangle.Width && HorizontalScrollbar) { + show = true; + hscrollbar.Maximum = canvas_size.Width; + hscrollbar.LargeChange = Math.Max (0, items_area.Width); + } else if (scroll_always_visible && horizontal_scrollbar) { + show = true; + enabled = false; + hscrollbar.Maximum = 0; + } + + hbar_offset = hscrollbar.Value; + hscrollbar.Enabled = enabled; + hscrollbar.Visible = show; + + return show; + } + + /* Determines if the vertical scrollbar has to be displyed */ + private bool UpdateVerticalScrollBar () + { + if (MultiColumn || (Items.Count == 0 && !scroll_always_visible)) { + vscrollbar.Visible = false; + return false; + } else if (Items.Count == 0) { + vscrollbar.Visible = true; + vscrollbar.Enabled = false; + vscrollbar.Maximum = 0; + return true; + } + + bool show = false; + bool enabled = true; + if (canvas_size.Height > items_area.Height) { + show = true; + vscrollbar.Maximum = Items.Count - 1; + vscrollbar.LargeChange = Math.Max (items_area.Height / ItemHeight, 0); + } else if (ScrollAlwaysVisible) { + show = true; + enabled = false; + vscrollbar.Maximum = 0; + } + + vscrollbar.Enabled = enabled; + vscrollbar.Visible = show; + + return show; + } + + // Value Changed + private void VerticalScrollEvent (object sender, EventArgs e) + { + int top_item = top_index; + + top_index = /*row_count + */ vscrollbar.Value; + last_visible_index = LastVisibleItem (); + + int delta = (top_item - top_index) * ItemHeight; + if (DrawMode == DrawMode.OwnerDrawVariable) { + delta = 0; + + if (top_index < top_item) + for (int i = top_index; i < top_item; i++) + delta += GetItemHeight (i); + else + for (int i = top_item; i < top_index; i++) + delta -= GetItemHeight (i); + } + + if (IsHandleCreated) + XplatUI.ScrollWindow (Handle, items_area, 0, delta, false); + } + + #endregion Private Methods + + public class IntegerCollection : IList, ICollection, IEnumerable + { + private ListBox owner; + private List list; + + #region Public Constructor + public IntegerCollection (ListBox owner) + { + this.owner = owner; + list = new List (); + } + #endregion + + #region Public Properties + [Browsable (false)] + public int Count { + get { return list.Count; } + } + + public int this [int index] { + get { return list[index]; } + set { list[index] = value; owner.CalculateTabStops (); } + } + #endregion + + #region Public Methods + public int Add (int item) + { + // This collection does not allow duplicates + if (!list.Contains (item)) { + list.Add (item); + list.Sort (); + owner.CalculateTabStops (); + } + + return list.IndexOf (item); + } + + public void AddRange (int[] items) + { + AddItems (items); + } + + public void AddRange (IntegerCollection value) + { + AddItems (value); + } + + void AddItems (IList items) + { + if (items == null) + throw new ArgumentNullException ("items"); + + foreach (int i in items) + if (!list.Contains (i)) + list.Add (i); + + list.Sort (); + } + + public void Clear () + { + list.Clear (); + owner.CalculateTabStops (); + } + + public bool Contains (int item) + { + return list.Contains (item); + } + + public void CopyTo (Array destination, int index) + { + for (int i = 0; i < list.Count; i++) + destination.SetValue (list[i], index++); + } + + public int IndexOf (int item) + { + return list.IndexOf (item); + } + + public void Remove (int item) + { + list.Remove (item); + list.Sort (); + owner.CalculateTabStops (); + } + + public void RemoveAt (int index) + { + if (index < 0) + throw new IndexOutOfRangeException (); + + list.RemoveAt (index); + list.Sort (); + owner.CalculateTabStops (); + } + #endregion + + #region IEnumerable Members + IEnumerator IEnumerable.GetEnumerator () + { + return list.GetEnumerator (); + } + #endregion + + #region IList Members + int IList.Add (object item) + { + int? intValue = item as int?; + if (!intValue.HasValue) + throw new ArgumentException ("item"); + return Add (intValue.Value); + } + + void IList.Clear () + { + Clear (); + } + + bool IList.Contains (object item) + { + int? intValue = item as int?; + if (!intValue.HasValue) + return false; + return Contains (intValue.Value); + } + + int IList.IndexOf (object item) + { + int? intValue = item as int?; + if (!intValue.HasValue) + return -1; + return IndexOf (intValue.Value); + } + + void IList.Insert (int index, object value) + { + throw new NotSupportedException (string.Format ( + CultureInfo.InvariantCulture, "No items " + + "can be inserted into {0}, since it is" + + " a sorted collection.", this.GetType ())); + } + + bool IList.IsFixedSize + { + get { return false; } + } + + bool IList.IsReadOnly + { + get { return false; } + } + + void IList.Remove (object value) + { + int? intValue = value as int?; + if (!intValue.HasValue) + throw new ArgumentException ("value"); + + Remove (intValue.Value); + } + + void IList.RemoveAt (int index) + { + RemoveAt (index); + } + + object IList.this[int index] { + get { return this[index]; } + set { this[index] = (int)value; } + } + #endregion + + #region ICollection Members + bool ICollection.IsSynchronized { + get { return true; } + } + + object ICollection.SyncRoot { + get { return this; } + } + #endregion + } + + [ListBindable (false)] + public class ObjectCollection : IList, ICollection, IEnumerable + { + internal class ListObjectComparer : IComparer + { + public int Compare (object a, object b) + { + string str1 = a.ToString (); + string str2 = b.ToString (); + return str1.CompareTo (str2); + } + } + + private ListBox owner; + internal ArrayList object_items = new ArrayList (); + + #region UIA Framework Events + //NOTE: + // We are using Reflection to add/remove internal events. + // Class ListProvider uses the events. + // + //Event used to generate UIA StructureChangedEvent + static object UIACollectionChangedEvent = new object (); + + internal event CollectionChangeEventHandler UIACollectionChanged { + add { owner.Events.AddHandler (UIACollectionChangedEvent, value); } + remove { owner.Events.RemoveHandler (UIACollectionChangedEvent, value); } + } + + internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args) + { + CollectionChangeEventHandler eh + = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent]; + if (eh != null) + eh (owner, args); + } + #endregion UIA Framework Events + + public ObjectCollection (ListBox owner) + { + this.owner = owner; + } + + public ObjectCollection (ListBox owner, object[] value) + { + this.owner = owner; + AddRange (value); + } + + public ObjectCollection (ListBox owner, ObjectCollection value) + { + this.owner = owner; + AddRange (value); + } + + #region Public Properties + public int Count { + get { return object_items.Count; } + } + + public bool IsReadOnly { + get { return false; } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public virtual object this [int index] { + get { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + return object_items[index]; + } + set { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + if (value == null) + throw new ArgumentNullException ("value"); + + //UIA Framework event: Item Removed + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, object_items [index])); + + object_items[index] = value; + + //UIA Framework event: Item Added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value)); + + owner.CollectionChanged (); + } + } + + bool ICollection.IsSynchronized { + get { return false; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + bool IList.IsFixedSize { + get { return false; } + } + + #endregion Public Properties + + #region Public Methods + public int Add (object item) + { + int idx; + object[] selectedItems = null; + + // we need to remember the original selected items so that we can update the indices + if (owner.sorted) { + selectedItems = new object[owner.SelectedItems.Count]; + owner.SelectedItems.CopyTo (selectedItems, 0); + } + + idx = AddItem (item); + owner.CollectionChanged (); + + // If we are sorted, the item probably moved indexes, get the real one + if (owner.sorted) { + // update indices of selected items + owner.SelectedIndices.Clear (); + for (int i = 0; i < selectedItems.Length; i++) { + owner.SelectedIndex = this.IndexOf (selectedItems [i]); + } + return this.IndexOf (item); + } + + return idx; + } + + public void AddRange (object[] items) + { + AddItems (items); + } + + public void AddRange (ObjectCollection value) + { + AddItems (value); + } + + internal void AddItems (IList items) + { + if (items == null) + throw new ArgumentNullException ("items"); + + foreach (object mi in items) + AddItem (mi); + + owner.CollectionChanged (); + } + + public virtual void Clear () + { + owner.selected_indices.ClearCore (); + object_items.Clear (); + owner.CollectionChanged (); + + //UIA Framework event: Items list cleared + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null)); + } + + public bool Contains (object value) + { + if (value == null) + throw new ArgumentNullException ("value"); + + return object_items.Contains (value); + } + + public void CopyTo (object[] destination, int arrayIndex) + { + object_items.CopyTo (destination, arrayIndex); + } + + void ICollection.CopyTo (Array destination, int index) + { + object_items.CopyTo (destination, index); + } + + public IEnumerator GetEnumerator () + { + return object_items.GetEnumerator (); + } + + int IList.Add (object item) + { + return Add (item); + } + + public int IndexOf (object value) + { + if (value == null) + throw new ArgumentNullException ("value"); + + return object_items.IndexOf (value); + } + + public void Insert (int index, object item) + { + if (index < 0 || index > Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + if (item == null) + throw new ArgumentNullException ("item"); + + owner.BeginUpdate (); + object_items.Insert (index, item); + owner.CollectionChanged (); + owner.EndUpdate (); + + //UIA Framework event: Item Added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item)); + } + + public void Remove (object value) + { + if (value == null) + return; + + int index = IndexOf (value); + if (index != -1) + RemoveAt (index); + } + + public void RemoveAt (int index) + { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + //UIA Framework element removed + object removed = object_items [index]; + UpdateSelection (index); + object_items.RemoveAt (index); + owner.CollectionChanged (); + + //UIA Framework event: Item Removed + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, removed)); + } + #endregion Public Methods + + #region Private Methods + internal int AddItem (object item) + { + if (item == null) + throw new ArgumentNullException ("item"); + + int cnt = object_items.Count; + object_items.Add (item); + + //UIA Framework event: Item Added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item)); + + return cnt; + } + + // we receive the index to be removed + void UpdateSelection (int removed_index) + { + owner.selected_indices.Remove (removed_index); + + if (owner.selection_mode != SelectionMode.None) { + int last_idx = object_items.Count - 1; + + // if the last item was selected, remove it from selection, + // since it will become invalid after the removal + if (owner.selected_indices.Contains (last_idx)) { + owner.selected_indices.Remove (last_idx); + + // in SelectionMode.One try to put the selection on the new last item + int new_idx = last_idx - 1; + if (owner.selection_mode == SelectionMode.One && new_idx > -1) + owner.selected_indices.Add (new_idx); + } + } + + } + + internal void Sort () + { + object_items.Sort (new ListObjectComparer ()); + } + + #endregion Private Methods + } + + public class SelectedIndexCollection : IList, ICollection, IEnumerable + { + private ListBox owner; + ArrayList selection; + bool sorting_needed; // Selection state retrieval is done sorted - we do it lazyly + + #region UIA Framework Events + + //NOTE: + // We are using Reflection to add/remove internal events. + // Class ListProvider uses the events. + // + //Event used to generate UIA StructureChangedEvent + static object UIACollectionChangedEvent = new object (); + + internal event CollectionChangeEventHandler UIACollectionChanged { + add { owner.Events.AddHandler (UIACollectionChangedEvent, value); } + remove { owner.Events.RemoveHandler (UIACollectionChangedEvent, value); } + } + + internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args) + { + CollectionChangeEventHandler eh + = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent]; + if (eh != null) + eh (owner, args); + } + + #endregion UIA Framework Events + + + public SelectedIndexCollection (ListBox owner) + { + this.owner = owner; + selection = new ArrayList (); + } + + #region Public Properties + [Browsable (false)] + public int Count { + get { return selection.Count; } + } + + public bool IsReadOnly { + get { return true; } + } + + public int this [int index] { + get { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + CheckSorted (); + return (int)selection [index]; + } + } + + bool ICollection.IsSynchronized { + get { return true; } + } + + bool IList.IsFixedSize{ + get { return true; } + } + + object ICollection.SyncRoot { + get { return selection; } + } + + #endregion Public Properties + + #region Public Methods + public void Add (int index) + { + if (AddCore (index)) { + owner.OnSelectedIndexChanged (EventArgs.Empty); + owner.OnSelectedValueChanged (EventArgs.Empty); + } + } + + // Need to separate selection logic from events, + // since selection changes using keys/mouse handle them their own way + internal bool AddCore (int index) + { + if (selection.Contains (index)) + return false; + + if (index == -1) // Weird MS behaviour + return false; + if (index < -1 || index >= owner.Items.Count) + throw new ArgumentOutOfRangeException ("index"); + if (owner.selection_mode == SelectionMode.None) + throw new InvalidOperationException ("Cannot call this method when selection mode is SelectionMode.None"); + + if (owner.selection_mode == SelectionMode.One && Count > 0) // Unselect previously selected item + RemoveCore ((int)selection [0]); + + selection.Add (index); + sorting_needed = true; + owner.EnsureVisible (index); + owner.FocusedItem = index; + owner.InvalidateItem (index); + + // UIA Framework event: Selected item added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, index)); + + return true; + } + + public void Clear () + { + if (ClearCore ()) { + owner.OnSelectedIndexChanged (EventArgs.Empty); + owner.OnSelectedValueChanged (EventArgs.Empty); + } + } + + internal bool ClearCore () + { + if (selection.Count == 0) + return false; + + foreach (int index in selection) + owner.InvalidateItem (index); + + selection.Clear (); + + // UIA Framework event: Selected items list updated + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, -1)); + + return true; + } + + public bool Contains (int selectedIndex) + { + foreach (int index in selection) + if (index == selectedIndex) + return true; + return false; + } + + public void CopyTo (Array destination, int index) + { + CheckSorted (); + selection.CopyTo (destination, index); + } + + public IEnumerator GetEnumerator () + { + CheckSorted (); + return selection.GetEnumerator (); + } + + // FIXME: Probably we can avoid sorting when calling + // IndexOf (imagine a scenario where multiple removal of items + // happens) + public void Remove (int index) + { + // Separate logic from events here too + if (RemoveCore (index)) { + owner.OnSelectedIndexChanged (EventArgs.Empty); + owner.OnSelectedValueChanged (EventArgs.Empty); + } + } + + internal bool RemoveCore (int index) + { + int idx = IndexOf (index); + if (idx == -1) + return false; + + selection.RemoveAt (idx); + owner.InvalidateItem (index); + + // UIA Framework event: Selected item removed from selection + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, index)); + + return true; + } + + int IList.Add (object value) + { + throw new NotSupportedException (); + } + + void IList.Clear () + { + throw new NotSupportedException (); + } + + bool IList.Contains (object selectedIndex) + { + return Contains ((int)selectedIndex); + } + + int IList.IndexOf (object selectedIndex) + { + return IndexOf ((int) selectedIndex); + } + + void IList.Insert (int index, object value) + { + throw new NotSupportedException (); + } + + void IList.Remove (object value) + { + throw new NotSupportedException (); + } + + void IList.RemoveAt (int index) + { + throw new NotSupportedException (); + } + + object IList.this[int index]{ + get { return this [index]; } + set {throw new NotImplementedException (); } + } + + public int IndexOf (int selectedIndex) + { + CheckSorted (); + + for (int i = 0; i < selection.Count; i++) + if ((int)selection [i] == selectedIndex) + return i; + + return -1; + } + #endregion Public Methods + internal ArrayList List { + get { + CheckSorted (); + return selection; + } + } + + void CheckSorted () + { + if (sorting_needed) { + sorting_needed = false; + selection.Sort (); + } + } + } + + public class SelectedObjectCollection : IList, ICollection, IEnumerable + { + private ListBox owner; + + public SelectedObjectCollection (ListBox owner) + { + this.owner = owner; + } + + #region Public Properties + public int Count { + get { return owner.selected_indices.Count; } + } + + public bool IsReadOnly { + get { return true; } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public object this [int index] { + get { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("Index of out range"); + + return owner.items [owner.selected_indices [index]]; + } + set {throw new NotSupportedException ();} + } + + bool ICollection.IsSynchronized { + get { return true; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + bool IList.IsFixedSize { + get { return true; } + } + + #endregion Public Properties + + #region Public Methods + public void Add (object value) + { + if (owner.selection_mode == SelectionMode.None) + throw new ArgumentException ("Cannot call this method if SelectionMode is SelectionMode.None"); + + int idx = owner.items.IndexOf (value); + if (idx == -1) + return; + + owner.selected_indices.Add (idx); + } + + public void Clear () + { + owner.selected_indices.Clear (); + } + + public bool Contains (object selectedObject) + { + int idx = owner.items.IndexOf (selectedObject); + return idx == -1 ? false : owner.selected_indices.Contains (idx); + } + + public void CopyTo (Array destination, int index) + { + for (int i = 0; i < Count; i++) + destination.SetValue (this [i], index++); + } + + public void Remove (object value) + { + if (value == null) + return; + + int idx = owner.items.IndexOf (value); + if (idx == -1) + return; + + owner.selected_indices.Remove (idx); + } + + int IList.Add (object value) + { + throw new NotSupportedException (); + } + + void IList.Clear () + { + throw new NotSupportedException (); + } + + void IList.Insert (int index, object value) + { + throw new NotSupportedException (); + } + + void IList.Remove (object value) + { + throw new NotSupportedException (); + } + + void IList.RemoveAt (int index) + { + throw new NotSupportedException (); + } + + public int IndexOf (object selectedObject) + { + int idx = owner.items.IndexOf (selectedObject); + return idx == -1 ? -1 : owner.selected_indices.IndexOf (idx); + } + + public IEnumerator GetEnumerator () + { + //FIXME: write an enumerator that uses selection.GetEnumerator + // so that invalidation is write on selection changes + object [] items = new object [Count]; + for (int i = 0; i < Count; i++) { + items [i] = owner.items [owner.selected_indices [i]]; + } + + return items.GetEnumerator (); + } + + #endregion Public Methods + } + } +} diff --git a/source/ShiftUI/Widgets/ListControl.cs b/source/ShiftUI/Widgets/ListControl.cs new file mode 100644 index 0000000..4b01499 --- /dev/null +++ b/source/ShiftUI/Widgets/ListControl.cs @@ -0,0 +1,509 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// +// + +// COMPLETE + +using System; +using System.Drawing; +using System.Collections; +using System.ComponentModel; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + [LookupBindingProperties ("DataSource", "DisplayMember", "ValueMember", "SelectedValue")] + public abstract class ListWidget : Widget + { + + private object data_source; + private BindingMemberInfo value_member; + private string display_member; + private CurrencyManager data_manager; + private BindingContext last_binding_context; + private IFormatProvider format_info; + private string format_string = string.Empty; + private bool formatting_enabled; + + protected ListWidget () + { + value_member = new BindingMemberInfo (string.Empty); + display_member = string.Empty; + SetStyle (Widgetstyles.StandardClick | Widgetstyles.UserPaint | Widgetstyles.UseTextForAccessibility, false); + } + + #region Events + static object DataSourceChangedEvent = new object (); + static object DisplayMemberChangedEvent = new object (); + static object FormatEvent = new object (); + static object FormatInfoChangedEvent = new object (); + static object FormatStringChangedEvent = new object (); + static object FormattingEnabledChangedEvent = new object (); + static object SelectedValueChangedEvent = new object (); + static object ValueMemberChangedEvent = new object (); + + public event EventHandler DataSourceChanged { + add { Events.AddHandler (DataSourceChangedEvent, value); } + remove { Events.RemoveHandler (DataSourceChangedEvent, value); } + } + + public event EventHandler DisplayMemberChanged { + add { Events.AddHandler (DisplayMemberChangedEvent, value); } + remove { Events.RemoveHandler (DisplayMemberChangedEvent, value); } + } + + public event ListWidgetConvertEventHandler Format { + add { Events.AddHandler (FormatEvent, value); } + remove { Events.RemoveHandler (FormatEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public event EventHandler FormatInfoChanged { + add { Events.AddHandler (FormatInfoChangedEvent, value); } + remove { Events.RemoveHandler (FormatInfoChangedEvent, value); } + } + + public event EventHandler FormatStringChanged { + add { Events.AddHandler (FormatStringChangedEvent, value); } + remove { Events.RemoveHandler (FormatStringChangedEvent, value); } + } + + public event EventHandler FormattingEnabledChanged { + add { Events.AddHandler (FormattingEnabledChangedEvent, value); } + remove { Events.RemoveHandler (FormattingEnabledChangedEvent, value); } + } + + public event EventHandler SelectedValueChanged { + add { Events.AddHandler (SelectedValueChangedEvent, value); } + remove { Events.RemoveHandler (SelectedValueChangedEvent, value); } + } + + public event EventHandler ValueMemberChanged { + add { Events.AddHandler (ValueMemberChangedEvent, value); } + remove { Events.RemoveHandler (ValueMemberChangedEvent, value); } + } + + #endregion // Events + + #region .NET 2.0 Public Properties + [Browsable (false)] + [DefaultValue (null)] + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public IFormatProvider FormatInfo { + get { return format_info; } + set { + if (format_info != value) { + format_info = value; + RefreshItems (); + OnFormatInfoChanged (EventArgs.Empty); + } + } + } + + [DefaultValue ("")] + [MergableProperty (false)] + //[Editor ("ShiftUI.Design.FormatStringEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + public string FormatString { + get { return format_string; } + set { + if (format_string != value) { + format_string = value; + RefreshItems (); + OnFormatStringChanged (EventArgs.Empty); + } + } + } + + [DefaultValue (false)] + public bool FormattingEnabled { + get { return formatting_enabled; } + set { + if (formatting_enabled != value) { + formatting_enabled = value; + RefreshItems (); + OnFormattingEnabledChanged (EventArgs.Empty); + } + } + } + #endregion + + #region Public Properties + + [DefaultValue(null)] + [RefreshProperties(RefreshProperties.Repaint)] + [AttributeProvider (typeof (IListSource))] + [MWFCategory("Data")] + public object DataSource { + get { return data_source; } + set { + if (data_source == value) + return; + + if (value == null) + display_member = String.Empty; + else if (!(value is IList || value is IListSource)) + throw new Exception ("Complex DataBinding accepts as a data source " + + "either an IList or an IListSource"); + + data_source = value; + ConnectToDataSource (); + OnDataSourceChanged (EventArgs.Empty); + } + } + + [DefaultValue("")] + //[Editor("ShiftUI.Design.DataMemberFieldEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))] + [TypeConverter("ShiftUI.Design.DataMemberFieldConverter, " + Consts.AssemblySystem_Design)] + [MWFCategory("Data")] + public string DisplayMember { + get { + return display_member; + } + set { + if (value == null) + value = String.Empty; + + if (display_member == value) { + return; + } + + display_member = value; + ConnectToDataSource (); + OnDisplayMemberChanged (EventArgs.Empty); + } + } + + public abstract int SelectedIndex { + get; + set; + } + + [Bindable(BindableSupport.Yes)] + [Browsable(false)] + [DefaultValue(null)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public object SelectedValue { + get { + if (data_manager == null || SelectedIndex == -1) + return null; + + object item = data_manager [SelectedIndex]; + object fil = FilterItemOnProperty (item, ValueMember); + return fil; + } + set { + if (data_manager == null) + return; + + if (value == null) + throw new ArgumentNullException ("value"); + + PropertyDescriptorCollection col = data_manager.GetItemProperties (); + PropertyDescriptor prop = col.Find (ValueMember, true); + + for (int i = 0; i < data_manager.Count; i++) { + if (value.Equals (prop.GetValue (data_manager [i]))) { + SelectedIndex = i; + return; + } + } + SelectedIndex = -1; + } + } + + [DefaultValue("")] + //[Editor("ShiftUI.Design.DataMemberFieldEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))] + [MWFCategory("Data")] + public string ValueMember { + get { return value_member.BindingMember; } + set { + BindingMemberInfo new_value = new BindingMemberInfo (value); + + if (value_member.Equals (new_value)) + return; + + value_member = new_value; + + if (display_member == string.Empty) + DisplayMember = value_member.BindingMember; + + ConnectToDataSource (); + OnValueMemberChanged (EventArgs.Empty); + } + } + + protected virtual bool AllowSelection { + get { return true; } + } + + #endregion Public Properties + + #region Private Properties + + internal override bool ScaleChildrenInternal { + get { return false; } + } + + #endregion Private Properties + + #region Public Methods + + protected object FilterItemOnProperty (object item) + { + return FilterItemOnProperty (item, string.Empty); + } + + protected object FilterItemOnProperty (object item, string field) + { + if (item == null) + return null; + + if (field == null || field == string.Empty) + return item; + + PropertyDescriptor prop = null; + + if (data_manager != null) { + PropertyDescriptorCollection col = data_manager.GetItemProperties (); + prop = col.Find (field, true); + } else { + PropertyDescriptorCollection properties = TypeDescriptor.GetProperties (item); + prop = properties.Find (field, true); + } + + if (prop == null) + return item; + + return prop.GetValue (item); + } + + public string GetItemText (object item) + { + object o = FilterItemOnProperty (item, DisplayMember); + + if (o == null) + o = item; + + string retval = o.ToString (); + + if (FormattingEnabled) { + ListWidgetConvertEventArgs e = new ListWidgetConvertEventArgs (o, typeof (string), item); + OnFormat (e); + + // The user provided their own value + if (e.Value.ToString () != retval) + return e.Value.ToString (); + + if (o is IFormattable) + return ((IFormattable)o).ToString (string.IsNullOrEmpty (FormatString) ? null : FormatString, FormatInfo); + } + + return retval; + } + + protected CurrencyManager DataManager { + get { return data_manager; } + } + + // Used only by ListBox to avoid to break Listbox's member signature + protected override bool IsInputKey (Keys keyData) + { + switch (keyData) { + case Keys.Up: + case Keys.Down: + case Keys.PageUp: + case Keys.PageDown: + case Keys.Right: + case Keys.Left: + case Keys.End: + case Keys.Home: + case Keys.ControlKey: + case Keys.Space: + case Keys.ShiftKey: + return true; + + default: + return false; + } + } + + // Since this event is fired twice for the same binding context instance + // (when the Widget is added to the form and when the form is shown), + // we only take into account the first time it happens + protected override void OnBindingContextChanged (EventArgs e) + { + base.OnBindingContextChanged (e); + if (last_binding_context == BindingContext) + return; + + last_binding_context = BindingContext; + ConnectToDataSource (); + + if (DataManager != null) { + SetItemsCore (DataManager.List); + if (AllowSelection) + SelectedIndex = DataManager.Position; + } + } + + protected virtual void OnDataSourceChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [DataSourceChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnDisplayMemberChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [DisplayMemberChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnFormat (ListWidgetConvertEventArgs e) + { + ListWidgetConvertEventHandler eh = (ListWidgetConvertEventHandler)(Events[FormatEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnFormatInfoChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events[FormatInfoChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnFormatStringChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events[FormatStringChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnFormattingEnabledChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events[FormattingEnabledChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnSelectedIndexChanged (EventArgs e) + { + if (data_manager == null) + return; + if (data_manager.Position == SelectedIndex) + return; + data_manager.Position = SelectedIndex; + } + + protected virtual void OnSelectedValueChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [SelectedValueChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnValueMemberChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [ValueMemberChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected abstract void RefreshItem (int index); + + protected virtual void RefreshItems () + { + } + + protected virtual void SetItemCore (int index, object value) + { + } + + protected abstract void SetItemsCore (IList items); + + #endregion Public Methods + + #region Private Methods + + internal void BindDataItems () + { + SetItemsCore (data_manager != null ? data_manager.List : new object [0]); + } + + private void ConnectToDataSource () + { + if (BindingContext == null) + return; + + CurrencyManager newDataMgr = null; + if (data_source != null) + newDataMgr = (CurrencyManager) BindingContext [data_source]; + if (newDataMgr != data_manager) { + if (data_manager != null) { + // Disconnect handlers from previous manager + data_manager.PositionChanged -= new EventHandler (OnPositionChanged); + data_manager.ItemChanged -= new ItemChangedEventHandler (OnItemChanged); + } + if (newDataMgr != null) { + newDataMgr.PositionChanged += new EventHandler (OnPositionChanged); + newDataMgr.ItemChanged += new ItemChangedEventHandler (OnItemChanged); + } + data_manager = newDataMgr; + } + } + + private void OnItemChanged (object sender, ItemChangedEventArgs e) + { + /* if the list has changed, tell our subclass to re-bind */ + if (e.Index == -1) + SetItemsCore (data_manager.List); + else + RefreshItem (e.Index); + + /* For the first added item, ItemChanged is fired _after_ PositionChanged, + * so we need to set Index _only_ for that case - normally we would do that + * in PositionChanged handler */ + if (AllowSelection && SelectedIndex == -1 && data_manager.Count == 1) + SelectedIndex = data_manager.Position; + } + + private void OnPositionChanged (object sender, EventArgs e) + { + /* For the first added item, PositionChanged is fired + * _before_ ItemChanged (items not yet added), which leave us in a temporary + * invalid state */ + if (AllowSelection && data_manager.Count > 1) + SelectedIndex = data_manager.Position; + } + + #endregion Private Methods + } +} diff --git a/source/ShiftUI/Widgets/ListView.cs b/source/ShiftUI/Widgets/ListView.cs new file mode 100644 index 0000000..a2706a3 --- /dev/null +++ b/source/ShiftUI/Widgets/ListView.cs @@ -0,0 +1,6155 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Ravindra Kumar (rkumar@novell.com) +// Jordi Mas i Hernandez, jordi@ximian.com +// Mike Kestner (mkestner@novell.com) +// Daniel Nauck (dna(at)mono-project(dot)de) +// Carlos Alberto Cortez +// + + +// NOT COMPLETE + + +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Globalization; +using System.Collections.Generic; +using System; + +namespace ShiftUI +{ + [DefaultEvent ("SelectedIndexChanged")] + [DefaultProperty ("Items")] + //[Designer ("ShiftUI.Design.ListViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + [Docking (DockingBehavior.Ask)] + [ToolboxWidget] + public class ListView : Widget + { + private ItemActivation activation = ItemActivation.Standard; + private ListViewAlignment alignment = ListViewAlignment.Top; + private bool allow_column_reorder; + private bool auto_arrange = true; + private bool check_boxes; + private readonly CheckedIndexCollection checked_indices; + private readonly CheckedListViewItemCollection checked_items; + private readonly ColumnHeaderCollection columns; + internal int focused_item_index = -1; + private bool full_row_select; + private bool grid_lines; + private ColumnHeaderStyle header_style = ColumnHeaderStyle.Clickable; + private bool hide_selection = true; + private bool hover_selection; + private IComparer item_sorter; + private readonly ListViewItemCollection items; + private readonly ListViewGroupCollection groups; + private bool owner_draw; + private bool show_groups = true; + private bool label_edit; + private bool label_wrap = true; + private bool multiselect = true; + private bool scrollable = true; + private bool hover_pending; + private readonly SelectedIndexCollection selected_indices; + private readonly SelectedListViewItemCollection selected_items; + private SortOrder sort_order = SortOrder.None; + private ImageList state_image_list; + internal bool updating; + private View view = View.LargeIcon; + private int layout_wd; // We might draw more than our client area + private int layout_ht; // therefore we need to have these two. + internal HeaderControl header_control; + internal ItemControl item_control; + internal ScrollBar h_scroll; // used for scrolling horizontally + internal ScrollBar v_scroll; // used for scrolling vertically + internal int h_marker; // Position markers for scrolling + internal int v_marker; + private int keysearch_tickcnt; + private string keysearch_text; + static private readonly int keysearch_keydelay = 1000; + private int[] reordered_column_indices; + private int[] reordered_items_indices; + private Point [] items_location; + private ItemMatrixLocation [] items_matrix_location; + private Size item_size; // used for caching item size + private int custom_column_width; // used when using Columns with SmallIcon/List views + private int hot_item_index = -1; + private bool hot_tracking; + private ListViewInsertionMark insertion_mark; + private bool show_item_tooltips; + private ToolTip item_tooltip; + private Size tile_size; + private bool virtual_mode; + private int virtual_list_size; + private bool right_to_left_layout; + // selection is available after the first time the handle is created, *even* if later + // the handle is either recreated or destroyed - so keep this info around. + private bool is_selection_available; + + // internal variables + internal ImageList large_image_list; + internal ImageList small_image_list; + internal Size text_size = Size.Empty; + + #region Events + static object AfterLabelEditEvent = new object (); + static object BeforeLabelEditEvent = new object (); + static object ColumnClickEvent = new object (); + static object ItemActivateEvent = new object (); + static object ItemCheckEvent = new object (); + static object ItemDragEvent = new object (); + static object SelectedIndexChangedEvent = new object (); + static object DrawColumnHeaderEvent = new object(); + static object DrawItemEvent = new object(); + static object DrawSubItemEvent = new object(); + static object ItemCheckedEvent = new object (); + static object ItemMouseHoverEvent = new object (); + static object ItemSelectionChangedEvent = new object (); + static object CacheVirtualItemsEvent = new object (); + static object RetrieveVirtualItemEvent = new object (); + static object RightToLeftLayoutChangedEvent = new object (); + static object SearchForVirtualItemEvent = new object (); + static object VirtualItemsSelectionRangeChangedEvent = new object (); + + public event LabelEditEventHandler AfterLabelEdit { + add { Events.AddHandler (AfterLabelEditEvent, value); } + remove { Events.RemoveHandler (AfterLabelEditEvent, value); } + } + + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageLayoutChanged { + add { base.BackgroundImageLayoutChanged += value; } + remove { base.BackgroundImageLayoutChanged -= value; } + } + + public event LabelEditEventHandler BeforeLabelEdit { + add { Events.AddHandler (BeforeLabelEditEvent, value); } + remove { Events.RemoveHandler (BeforeLabelEditEvent, value); } + } + + public event ColumnClickEventHandler ColumnClick { + add { Events.AddHandler (ColumnClickEvent, value); } + remove { Events.RemoveHandler (ColumnClickEvent, value); } + } + + public event DrawListViewColumnHeaderEventHandler DrawColumnHeader { + add { Events.AddHandler(DrawColumnHeaderEvent, value); } + remove { Events.RemoveHandler(DrawColumnHeaderEvent, value); } + } + + public event DrawListViewItemEventHandler DrawItem { + add { Events.AddHandler(DrawItemEvent, value); } + remove { Events.RemoveHandler(DrawItemEvent, value); } + } + + public event DrawListViewSubItemEventHandler DrawSubItem { + add { Events.AddHandler(DrawSubItemEvent, value); } + remove { Events.RemoveHandler(DrawSubItemEvent, value); } + } + + public event EventHandler ItemActivate { + add { Events.AddHandler (ItemActivateEvent, value); } + remove { Events.RemoveHandler (ItemActivateEvent, value); } + } + + public event ItemCheckEventHandler ItemCheck { + add { Events.AddHandler (ItemCheckEvent, value); } + remove { Events.RemoveHandler (ItemCheckEvent, value); } + } + + public event ItemCheckedEventHandler ItemChecked { + add { Events.AddHandler (ItemCheckedEvent, value); } + remove { Events.RemoveHandler (ItemCheckedEvent, value); } + } + + public event ItemDragEventHandler ItemDrag { + add { Events.AddHandler (ItemDragEvent, value); } + remove { Events.RemoveHandler (ItemDragEvent, value); } + } + + public event ListViewItemMouseHoverEventHandler ItemMouseHover { + add { Events.AddHandler (ItemMouseHoverEvent, value); } + remove { Events.RemoveHandler (ItemMouseHoverEvent, value); } + } + + public event ListViewItemSelectionChangedEventHandler ItemSelectionChanged { + add { Events.AddHandler (ItemSelectionChangedEvent, value); } + remove { Events.RemoveHandler (ItemSelectionChangedEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler PaddingChanged { + add { base.PaddingChanged += value; } + remove { base.PaddingChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event PaintEventHandler Paint { + add { base.Paint += value; } + remove { base.Paint -= value; } + } + + public event EventHandler SelectedIndexChanged { + add { Events.AddHandler (SelectedIndexChangedEvent, value); } + remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + + public event CacheVirtualItemsEventHandler CacheVirtualItems { + add { Events.AddHandler (CacheVirtualItemsEvent, value); } + remove { Events.RemoveHandler (CacheVirtualItemsEvent, value); } + } + + public event RetrieveVirtualItemEventHandler RetrieveVirtualItem { + add { Events.AddHandler (RetrieveVirtualItemEvent, value); } + remove { Events.RemoveHandler (RetrieveVirtualItemEvent, value); } + } + + public event EventHandler RightToLeftLayoutChanged { + add { Events.AddHandler (RightToLeftLayoutChangedEvent, value); } + remove { Events.RemoveHandler (RightToLeftLayoutChangedEvent, value); } + } + + public event SearchForVirtualItemEventHandler SearchForVirtualItem { + add { Events.AddHandler (SearchForVirtualItemEvent, value); } + remove { Events.AddHandler (SearchForVirtualItemEvent, value); } + } + + public event ListViewVirtualItemsSelectionRangeChangedEventHandler VirtualItemsSelectionRangeChanged { + add { Events.AddHandler (VirtualItemsSelectionRangeChangedEvent, value); } + remove { Events.RemoveHandler (VirtualItemsSelectionRangeChangedEvent, value); } + } + + #endregion // Events + + #region Public Constructors + public ListView () + { + background_color = ThemeEngine.Current.ColorWindow; + groups = new ListViewGroupCollection (this); + items = new ListViewItemCollection (this); + items.Changed += new CollectionChangedHandler (OnItemsChanged); + checked_indices = new CheckedIndexCollection (this); + checked_items = new CheckedListViewItemCollection (this); + columns = new ColumnHeaderCollection (this); + foreground_color = SystemColors.WindowText; + selected_indices = new SelectedIndexCollection (this); + selected_items = new SelectedListViewItemCollection (this); + items_location = new Point [16]; + items_matrix_location = new ItemMatrixLocation [16]; + reordered_items_indices = new int [16]; + item_tooltip = new ToolTip (); + item_tooltip.Active = false; + insertion_mark = new ListViewInsertionMark (this); + + InternalBorderStyle = BorderStyle.Fixed3D; + + header_control = new HeaderControl (this); + header_control.Visible = false; + Widgets.AddImplicit (header_control); + + item_control = new ItemControl (this); + Widgets.AddImplicit (item_control); + + h_scroll = new ImplicitHScrollBar (); + Widgets.AddImplicit (this.h_scroll); + + v_scroll = new ImplicitVScrollBar (); + Widgets.AddImplicit (this.v_scroll); + + h_marker = v_marker = 0; + keysearch_tickcnt = 0; + + // scroll bars are disabled initially + h_scroll.Visible = false; + h_scroll.ValueChanged += new EventHandler(HorizontalScroller); + v_scroll.Visible = false; + v_scroll.ValueChanged += new EventHandler(VerticalScroller); + + // event handlers + base.KeyDown += new KeyEventHandler(ListView_KeyDown); + SizeChanged += new EventHandler (ListView_SizeChanged); + GotFocus += new EventHandler (FocusChanged); + LostFocus += new EventHandler (FocusChanged); + MouseWheel += new MouseEventHandler(ListView_MouseWheel); + MouseEnter += new EventHandler (ListView_MouseEnter); + Invalidated += new InvalidateEventHandler (ListView_Invalidated); + + BackgroundImageTiled = false; + + this.SetStyle (Widgetstyles.UserPaint | Widgetstyles.StandardClick + | Widgetstyles.UseTextForAccessibility + , false); + } + #endregion // Public Constructors + + #region Private Internal Properties + internal Size CheckBoxSize { + get { + if (this.check_boxes) { + if (this.state_image_list != null) + return this.state_image_list.ImageSize; + else + return ThemeEngine.Current.ListViewCheckBoxSize; + } + return Size.Empty; + } + } + + internal Size ItemSize { + get { + if (view != View.Details) + return item_size; + + Size size = new Size (); + size.Height = item_size.Height; + for (int i = 0; i < columns.Count; i++) + size.Width += columns [i].Wd; + + return size; + } + set { + item_size = value; + } + } + + internal int HotItemIndex { + get { + return hot_item_index; + } + set { + hot_item_index = value; + } + } + + internal bool UsingGroups { + get { + return show_groups && groups.Count > 0 && view != View.List && + Application.VisualStylesEnabled; + } + } + + internal override bool ScaleChildrenInternal { + get { return false; } + } + + internal bool UseCustomColumnWidth { + get { + return (view == View.List || view == View.SmallIcon) && columns.Count > 0; + } + } + + internal ColumnHeader EnteredColumnHeader { + get { + return header_control.EnteredColumnHeader; + } + } + #endregion // Private Internal Properties + + #region Protected Properties + protected override CreateParams CreateParams { + get { return base.CreateParams; } + } + + protected override Size DefaultSize { + get { return ThemeEngine.Current.ListViewDefaultSize; } + } + protected override bool DoubleBuffered { + get { + return base.DoubleBuffered; + } + set { + base.DoubleBuffered = value; + } + } + #endregion // Protected Properties + + #region Public Instance Properties + [DefaultValue (ItemActivation.Standard)] + public ItemActivation Activation { + get { return activation; } + set { + if (value != ItemActivation.Standard && value != ItemActivation.OneClick && + value != ItemActivation.TwoClick) { + throw new InvalidEnumArgumentException (string.Format + ("Enum argument value '{0}' is not valid for Activation", value)); + } + if (hot_tracking && value != ItemActivation.OneClick) + throw new ArgumentException ("When HotTracking is on, activation must be ItemActivation.OneClick"); + + activation = value; + } + } + + [DefaultValue (ListViewAlignment.Top)] + [Localizable (true)] + public ListViewAlignment Alignment { + get { return alignment; } + set { + if (value != ListViewAlignment.Default && value != ListViewAlignment.Left && + value != ListViewAlignment.SnapToGrid && value != ListViewAlignment.Top) { + throw new InvalidEnumArgumentException (string.Format + ("Enum argument value '{0}' is not valid for Alignment", value)); + } + + if (this.alignment != value) { + alignment = value; + // alignment does not matter in Details/List views + if (this.view == View.LargeIcon || this.View == View.SmallIcon) + this.Redraw (true); + } + } + } + + [DefaultValue (false)] + public bool AllowColumnReorder { + get { return allow_column_reorder; } + set { allow_column_reorder = value; } + } + + [DefaultValue (true)] + public bool AutoArrange { + get { return auto_arrange; } + set { + if (auto_arrange != value) { + auto_arrange = value; + // autoarrange does not matter in Details/List views + if (this.view == View.LargeIcon || this.View == View.SmallIcon) + this.Redraw (true); + } + } + } + + public override Color BackColor { + get { + if (background_color.IsEmpty) + return ThemeEngine.Current.ColorWindow; + else + return background_color; + } + set { + background_color = value; + item_control.BackColor = value; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override ImageLayout BackgroundImageLayout { + get { + return base.BackgroundImageLayout; + } + set { + base.BackgroundImageLayout = value; + } + } + + [DefaultValue (false)] + public bool BackgroundImageTiled { + get { + return item_control.BackgroundImageLayout == ImageLayout.Tile; + } + set { + ImageLayout new_image_layout = value ? ImageLayout.Tile : ImageLayout.None; + if (new_image_layout == item_control.BackgroundImageLayout) + return; + + item_control.BackgroundImageLayout = new_image_layout; + } + } + + [DefaultValue (BorderStyle.Fixed3D)] + [DispId (-504)] + public BorderStyle BorderStyle { + get { return InternalBorderStyle; } + set { InternalBorderStyle = value; } + } + + [DefaultValue (false)] + public bool CheckBoxes { + get { return check_boxes; } + set { + if (check_boxes != value) { + if (value && View == View.Tile) + throw new NotSupportedException ("CheckBoxes are not" + + " supported in Tile view. Choose a different" + + " view or set CheckBoxes to false."); + + check_boxes = value; + this.Redraw (true); + + //UIA Framework: Event used by ListView to set/unset Toggle Pattern + OnUIACheckBoxesChanged (); + } + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public CheckedIndexCollection CheckedIndices { + get { return checked_indices; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public CheckedListViewItemCollection CheckedItems { + get { return checked_items; } + } + + //[Editor ("ShiftUI.Design.ColumnHeaderCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + [Localizable (true)] + [MergableProperty (false)] + public ColumnHeaderCollection Columns { + get { return columns; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public ListViewItem FocusedItem { + get { + if (focused_item_index == -1) + return null; + + return GetItemAtDisplayIndex (focused_item_index); + } + set { + if (value == null || value.ListView != this || + !IsHandleCreated) + return; + + SetFocusedItem (value.DisplayIndex); + } + } + + public override Color ForeColor { + get { + if (foreground_color.IsEmpty) + return ThemeEngine.Current.ColorWindowText; + else + return foreground_color; + } + set { foreground_color = value; } + } + + [DefaultValue (false)] + public bool FullRowSelect { + get { return full_row_select; } + set { + if (full_row_select != value) { + full_row_select = value; + InvalidateSelection (); + } + } + } + + [DefaultValue (false)] + public bool GridLines { + get { return grid_lines; } + set { + if (grid_lines != value) { + grid_lines = value; + this.Redraw (false); + } + } + } + + [DefaultValue (ColumnHeaderStyle.Clickable)] + public ColumnHeaderStyle HeaderStyle { + get { return header_style; } + set { + if (header_style == value) + return; + + switch (value) { + case ColumnHeaderStyle.Clickable: + case ColumnHeaderStyle.Nonclickable: + case ColumnHeaderStyle.None: + break; + default: + throw new InvalidEnumArgumentException (string.Format + ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value)); + } + + header_style = value; + if (view == View.Details) + Redraw (true); + } + } + + [DefaultValue (true)] + public bool HideSelection { + get { return hide_selection; } + set { + if (hide_selection != value) { + hide_selection = value; + InvalidateSelection (); + } + } + } + + [DefaultValue (false)] + public bool HotTracking { + get { + return hot_tracking; + } + set { + if (hot_tracking == value) + return; + + hot_tracking = value; + if (hot_tracking) { + hover_selection = true; + activation = ItemActivation.OneClick; + } + } + } + + [DefaultValue (false)] + public bool HoverSelection { + get { return hover_selection; } + set { + if (hot_tracking && value == false) + throw new ArgumentException ("When HotTracking is on, hover selection must be true"); + hover_selection = value; + } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + [Browsable (false)] + public ListViewInsertionMark InsertionMark { + get { + return insertion_mark; + } + } + + //[Editor ("ShiftUI.Design.ListViewItemCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + [Localizable (true)] + [MergableProperty (false)] + public ListViewItemCollection Items { + get { return items; } + } + + [DefaultValue (false)] + public bool LabelEdit { + get { return label_edit; } + set { + if (value != label_edit) { + label_edit = value; + + // UIA Framework: Event used by Value Pattern in ListView.ListItem provider + OnUIALabelEditChanged (); + } + + } + } + + [DefaultValue (true)] + [Localizable (true)] + public bool LabelWrap { + get { return label_wrap; } + set { + if (label_wrap != value) { + label_wrap = value; + this.Redraw (true); + } + } + } + + [DefaultValue (null)] + public ImageList LargeImageList { + get { return large_image_list; } + set { + large_image_list = value; + this.Redraw (true); + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public IComparer ListViewItemSorter { + get { + if (View != View.SmallIcon && View != View.LargeIcon && item_sorter is ItemComparer) + return null; + return item_sorter; + } + set { + if (item_sorter != value) { + item_sorter = value; + Sort (); + } + } + } + + [DefaultValue (true)] + public bool MultiSelect { + get { return multiselect; } + set { + if (value != multiselect) { + multiselect = value; + + // UIA Framework: Event used by Selection Pattern in ListView.ListItem provider + OnUIAMultiSelectChanged (); + } + } + } + + + [DefaultValue(false)] + public bool OwnerDraw { + get { return owner_draw; } + set { + owner_draw = value; + Redraw (true); + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Padding Padding { + get { + return base.Padding; + } + set { + base.Padding = value; + } + } + + [MonoTODO ("RTL not supported")] + [Localizable (true)] + [DefaultValue (false)] + public virtual bool RightToLeftLayout { + get { return right_to_left_layout; } + set { + if (right_to_left_layout != value) { + right_to_left_layout = value; + OnRightToLeftLayoutChanged (EventArgs.Empty); + } + } + } + + [DefaultValue (true)] + public bool Scrollable { + get { return scrollable; } + set { + if (scrollable != value) { + scrollable = value; + this.Redraw (true); + } + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public SelectedIndexCollection SelectedIndices { + get { return selected_indices; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public SelectedListViewItemCollection SelectedItems { + get { return selected_items; } + } + + [DefaultValue(true)] + public bool ShowGroups { + get { return show_groups; } + set { + if (show_groups != value) { + show_groups = value; + Redraw(true); + + // UIA Framework: Used to update a11y Tree + OnUIAShowGroupsChanged (); + } + } + } + + [LocalizableAttribute (true)] + [MergableProperty (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + //[Editor ("ShiftUI.Design.ListViewGroupCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + public ListViewGroupCollection Groups { + get { return groups; } + } + + [DefaultValue (false)] + public bool ShowItemToolTips { + get { + return show_item_tooltips; + } + set { + show_item_tooltips = value; + item_tooltip.Active = false; + } + } + + [DefaultValue (null)] + public ImageList SmallImageList { + get { return small_image_list; } + set { + small_image_list = value; + this.Redraw (true); + } + } + + [DefaultValue (SortOrder.None)] + public SortOrder Sorting { + get { return sort_order; } + set { + if (!Enum.IsDefined (typeof (SortOrder), value)) { + throw new InvalidEnumArgumentException ("value", (int) value, + typeof (SortOrder)); + } + + if (sort_order == value) + return; + + sort_order = value; + + if (virtual_mode) // Sorting is not allowed in virtual mode + return; + + if (value == SortOrder.None) { + if (item_sorter != null) { + // ListViewItemSorter should never be reset for SmallIcon + // and LargeIcon view + if (View != View.SmallIcon && View != View.LargeIcon) + item_sorter = null; + } + this.Redraw (false); + } else { + if (item_sorter == null) + item_sorter = new ItemComparer (value); + if (item_sorter is ItemComparer) { + item_sorter = new ItemComparer (value); + } + Sort (); + } + } + } + + private void OnImageListChanged (object sender, EventArgs args) + { + item_control.Invalidate (); + } + + [DefaultValue (null)] + public ImageList StateImageList { + get { return state_image_list; } + set { + if (state_image_list == value) + return; + + if (state_image_list != null) + state_image_list.Images.Changed -= new EventHandler (OnImageListChanged); + + state_image_list = value; + + if (state_image_list != null) + state_image_list.Images.Changed += new EventHandler (OnImageListChanged); + + this.Redraw (true); + } + } + + [Bindable (false)] + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override string Text { + get { return base.Text; } + set { + if (value == base.Text) + return; + + base.Text = value; + this.Redraw (true); + } + } + + [Browsable (true)] + public Size TileSize { + get { + return tile_size; + } + set { + if (value.Width <= 0 || value.Height <= 0) + throw new ArgumentOutOfRangeException ("value"); + + tile_size = value; + if (view == View.Tile) + Redraw (true); + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public ListViewItem TopItem { + get { + if (view == View.LargeIcon || view == View.SmallIcon || view == View.Tile) + throw new InvalidOperationException ("Cannot get the top item in LargeIcon, SmallIcon or Tile view."); + // there is no item + if (this.items.Count == 0) + return null; + // if contents are not scrolled + // it is the first item + else if (h_marker == 0 && v_marker == 0) + return this.items [0]; + // do a hit test for the scrolled position + else { + int header_offset = header_control.Height; + for (int i = 0; i < items.Count; i++) { + Point item_loc = GetItemLocation (i); + if (item_loc.X >= 0 && item_loc.Y - header_offset >= 0) + return items [i]; + } + return null; + } + } + set { + if (view == View.LargeIcon || view == View.SmallIcon || view == View.Tile) + throw new InvalidOperationException ("Cannot set the top item in LargeIcon, SmallIcon or Tile view."); + + // .Net doesn't throw any exception in the cases below + if (value == null || value.ListView != this) + return; + + // Take advantage this property is only valid for Details view. + SetScrollValue (v_scroll, item_size.Height * value.Index); + } + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + [DefaultValue (true)] + [Browsable (false)] + [MonoInternalNote ("Stub, not implemented")] + public bool UseCompatibleStateImageBehavior { + get { + return false; + } + set { + } + } + + [DefaultValue (View.LargeIcon)] + public View View { + get { return view; } + set { + if (!Enum.IsDefined (typeof (View), value)) + throw new InvalidEnumArgumentException ("value", (int) value, + typeof (View)); + + if (view != value) { + if (CheckBoxes && value == View.Tile) + throw new NotSupportedException ("CheckBoxes are not" + + " supported in Tile view. Choose a different" + + " view or set CheckBoxes to false."); + if (VirtualMode && value == View.Tile) + throw new NotSupportedException ("VirtualMode is" + + " not supported in Tile view. Choose a different" + + " view or set ViewMode to false."); + + h_scroll.Value = v_scroll.Value = 0; + view = value; + Redraw (true); + + // UIA Framework: Event used to update UIA Tree. + OnUIAViewChanged (); + } + } + } + + [DefaultValue (false)] + [RefreshProperties (RefreshProperties.Repaint)] + public bool VirtualMode { + get { + return virtual_mode; + } + set { + if (virtual_mode == value) + return; + + if (!virtual_mode && items.Count > 0) + throw new InvalidOperationException (); + if (value && view == View.Tile) + throw new NotSupportedException ("VirtualMode is" + + " not supported in Tile view. Choose a different" + + " view or set ViewMode to false."); + + virtual_mode = value; + Redraw (true); + } + } + + [DefaultValue (0)] + [RefreshProperties (RefreshProperties.Repaint)] + public int VirtualListSize { + get { + return virtual_list_size; + } + set { + if (value < 0) + throw new ArgumentException ("value"); + + if (virtual_list_size == value) + return; + + virtual_list_size = value; + if (virtual_mode) { + focused_item_index = -1; + selected_indices.Reset (); + Redraw (true); + } + } + } + #endregion // Public Instance Properties + + #region Internal Methods Properties + + internal int FirstVisibleIndex { + get { + // there is no item + if (this.items.Count == 0) + return 0; + + if (h_marker == 0 && v_marker == 0) + return 0; + + Size item_size = ItemSize; + // In virtual mode we always have fixed positions, and we can infer the positon easily + if (virtual_mode) { + int first = 0; + switch (view) { + case View.Details: + first = v_marker / item_size.Height; + break; + case View.LargeIcon: + case View.SmallIcon: + first = (v_marker / (item_size.Height + y_spacing)) * cols; + break; + case View.List: + first = (h_marker / (item_size.Width * x_spacing)) * rows; + break; + } + + if (first >= items.Count) + first = items.Count; + + return first; + } + for (int i = 0; i < items.Count; i++) { + Rectangle item_rect = new Rectangle (GetItemLocation (i), item_size); + if (item_rect.Right >= 0 && item_rect.Bottom >= 0) + return i; + } + + return 0; + } + } + + + internal int LastVisibleIndex { + get { + for (int i = FirstVisibleIndex; i < Items.Count; i++) { + if (View == View.List || Alignment == ListViewAlignment.Left) { + if (GetItemLocation (i).X > item_control.ClientRectangle.Right) + return i - 1; + } else { + if (GetItemLocation (i).Y > item_control.ClientRectangle.Bottom) + return i - 1; + } + } + + return Items.Count - 1; + } + } + + internal void OnSelectedIndexChanged () + { + if (is_selection_available) + OnSelectedIndexChanged (EventArgs.Empty); + } + + internal int TotalWidth { + get { return Math.Max (this.Width, this.layout_wd); } + } + + internal int TotalHeight { + get { return Math.Max (this.Height, this.layout_ht); } + } + + internal void Redraw (bool recalculate) + { + // Avoid calculations when control is being updated + if (updating) + return; + // VirtualMode doesn't do any calculations until handle is created + if (virtual_mode && !IsHandleCreated) + return; + + + if (recalculate) + CalculateListView (this.alignment); + + Invalidate (true); + } + + void InvalidateSelection () + { + foreach (int selected_index in SelectedIndices) + items [selected_index].Invalidate (); + } + + const int text_padding = 15; + + internal Size GetChildColumnSize (int index) + { + Size ret_size = Size.Empty; + ColumnHeader col = this.columns [index]; + + if (col.Width == -2) { // autosize = max(items, columnheader) + Size size = Size.Ceiling (TextRenderer.MeasureString + (col.Text, this.Font)); + size.Width += text_padding; + ret_size = BiggestItem (index); + if (size.Width > ret_size.Width) + ret_size = size; + } + else { // -1 and all the values < -2 are put under one category + ret_size = BiggestItem (index); + // fall back to empty columns' width if no subitem is available for a column + if (ret_size.IsEmpty) { + ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth; + if (col.Text.Length > 0) + ret_size.Height = Size.Ceiling (TextRenderer.MeasureString + (col.Text, this.Font)).Height; + else + ret_size.Height = this.Font.Height; + } + } + + ret_size.Height += text_padding; + + // adjust the size for icon and checkbox for 0th column + if (index == 0) { + ret_size.Width += (this.CheckBoxSize.Width + 4); + if (this.small_image_list != null) + ret_size.Width += this.small_image_list.ImageSize.Width; + } + return ret_size; + } + + // Returns the size of biggest item text in a column + // or the sum of the text and indent count if we are on 2.0 + private Size BiggestItem (int col) + { + Size temp = Size.Empty; + Size ret_size = Size.Empty; + bool use_indent_count = small_image_list != null; + + // VirtualMode uses the first item text size + if (virtual_mode && items.Count > 0) { + ListViewItem item = items [0]; + ret_size = Size.Ceiling (TextRenderer.MeasureString (item.SubItems[col].Text, + Font)); + + if (use_indent_count) + ret_size.Width += item.IndentCount * small_image_list.ImageSize.Width; + } else { + // 0th column holds the item text, we check the size of + // the various subitems falling in that column and get + // the biggest one's size. + foreach (ListViewItem item in items) { + if (col >= item.SubItems.Count) + continue; + + temp = Size.Ceiling (TextRenderer.MeasureString + (item.SubItems [col].Text, Font)); + + if (use_indent_count) + temp.Width += item.IndentCount * small_image_list.ImageSize.Width; + + if (temp.Width > ret_size.Width) + ret_size = temp; + } + } + + // adjustment for space in Details view + if (!ret_size.IsEmpty && view == View.Details) + ret_size.Width += ThemeEngine.Current.ListViewItemPaddingWidth; + + return ret_size; + } + + const int max_wrap_padding = 30; + + // Sets the size of the biggest item text as per the view + private void CalcTextSize () + { + // clear the old value + text_size = Size.Empty; + + if (items.Count == 0) + return; + + text_size = BiggestItem (0); + + if (view == View.LargeIcon && this.label_wrap) { + Size temp = Size.Empty; + if (this.check_boxes) + temp.Width += 2 * this.CheckBoxSize.Width; + int icon_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width; + temp.Width += icon_w + max_wrap_padding; + // wrapping is done for two lines only + if (text_size.Width > temp.Width) { + text_size.Width = temp.Width; + text_size.Height *= 2; + } + } + else if (view == View.List) { + // in list view max text shown in determined by the + // control width, even if scolling is enabled. + int max_wd = this.Width - (this.CheckBoxSize.Width - 2); + if (this.small_image_list != null) + max_wd -= this.small_image_list.ImageSize.Width; + + if (text_size.Width > max_wd) + text_size.Width = max_wd; + } + + // we do the default settings, if we have got 0's + if (text_size.Height <= 0) + text_size.Height = this.Font.Height; + if (text_size.Width <= 0) + text_size.Width = this.Width; + + // little adjustment + text_size.Width += 2; + text_size.Height += 2; + } + + private void SetScrollValue (ScrollBar scrollbar, int val) + { + int max; + if (scrollbar == h_scroll) + max = h_scroll.Maximum - h_scroll.LargeChange + 1; + else + max = v_scroll.Maximum - v_scroll.LargeChange + 1; + + if (val > max) + val = max; + else if (val < scrollbar.Minimum) + val = scrollbar.Minimum; + + scrollbar.Value = val; + } + + private void Scroll (ScrollBar scrollbar, int delta) + { + if (delta == 0 || !scrollbar.Visible) + return; + + SetScrollValue (scrollbar, scrollbar.Value + delta); + } + + private void CalculateScrollBars () + { + Rectangle client_area = ClientRectangle; + int height = client_area.Height; + int width = client_area.Width; + Size item_size; + + if (!scrollable) { + h_scroll.Visible = false; + v_scroll.Visible = false; + item_control.Size = new Size (width, height); + header_control.Width = width; + return; + } + + // Don't calculate if the view is not displayable + if (client_area.Height < 0 || client_area.Width < 0) + return; + + // making a scroll bar visible might make + // other scroll bar visible + if (layout_wd > client_area.Right) { + h_scroll.Visible = true; + if ((layout_ht + h_scroll.Height) > client_area.Bottom) + v_scroll.Visible = true; + else + v_scroll.Visible = false; + } else if (layout_ht > client_area.Bottom) { + v_scroll.Visible = true; + if ((layout_wd + v_scroll.Width) > client_area.Right) + h_scroll.Visible = true; + else + h_scroll.Visible = false; + } else { + h_scroll.Visible = false; + v_scroll.Visible = false; + } + + + item_size = ItemSize; + + if (h_scroll.is_visible) { + h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height); + h_scroll.Minimum = 0; + + // if v_scroll is visible, adjust the maximum of the + // h_scroll to account for the width of v_scroll + if (v_scroll.Visible) { + h_scroll.Maximum = layout_wd + v_scroll.Width; + h_scroll.Width = client_area.Width - v_scroll.Width; + } + else { + h_scroll.Maximum = layout_wd; + h_scroll.Width = client_area.Width; + } + + if (view == View.List) + h_scroll.SmallChange = item_size.Width + ThemeEngine.Current.ListViewHorizontalSpacing; + else + h_scroll.SmallChange = Font.Height; + + h_scroll.LargeChange = client_area.Width; + height -= h_scroll.Height; + } + + if (v_scroll.is_visible) { + v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y); + v_scroll.Minimum = 0; + + // if h_scroll is visible, adjust the height of + // v_scroll to account for the height of h_scroll + if (h_scroll.Visible) { + v_scroll.Maximum = layout_ht + h_scroll.Height; + v_scroll.Height = client_area.Height > h_scroll.Height ? client_area.Height - h_scroll.Height : 0; + } else { + v_scroll.Maximum = layout_ht; + v_scroll.Height = client_area.Height; + } + + if (view == View.Details) { + // Need to update Maximum if using LargeChange with value other than the visible area + int headerPlusOneItem = header_control.Height + item_size.Height; + v_scroll.LargeChange = v_scroll.Height > headerPlusOneItem ? v_scroll.Height - headerPlusOneItem : 0; + v_scroll.Maximum = v_scroll.Maximum > headerPlusOneItem ? v_scroll.Maximum - headerPlusOneItem : 0; + } else + v_scroll.LargeChange = v_scroll.Height; + + v_scroll.SmallChange = item_size.Height; + width -= v_scroll.Width; + } + + item_control.Size = new Size (width, height); + + if (header_control.is_visible) + header_control.Width = width; + } + + internal int GetReorderedColumnIndex (ColumnHeader column) + { + if (reordered_column_indices == null) + return column.Index; + + for (int i = 0; i < Columns.Count; i++) + if (reordered_column_indices [i] == column.Index) + return i; + + return -1; + } + + internal ColumnHeader GetReorderedColumn (int index) + { + if (reordered_column_indices == null) + return Columns [index]; + else + return Columns [reordered_column_indices [index]]; + } + + internal void ReorderColumn (ColumnHeader col, int index, bool fireEvent) + { + if (fireEvent) { + ColumnReorderedEventHandler eh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]); + if (eh != null){ + ColumnReorderedEventArgs args = new ColumnReorderedEventArgs (col.Index, index, col); + + eh (this, args); + if (args.Cancel) { + header_control.Invalidate (); + item_control.Invalidate (); + return; + } + } + } + int column_count = Columns.Count; + + if (reordered_column_indices == null) { + reordered_column_indices = new int [column_count]; + for (int i = 0; i < column_count; i++) + reordered_column_indices [i] = i; + } + + if (reordered_column_indices [index] == col.Index) + return; + + int[] curr = reordered_column_indices; + int [] result = new int [column_count]; + int curr_idx = 0; + for (int i = 0; i < column_count; i++) { + if (curr_idx < column_count && curr [curr_idx] == col.Index) + curr_idx++; + + if (i == index) + result [i] = col.Index; + else + result [i] = curr [curr_idx++]; + } + + ReorderColumns (result, true); + } + + internal void ReorderColumns (int [] display_indices, bool redraw) + { + reordered_column_indices = display_indices; + for (int i = 0; i < Columns.Count; i++) { + ColumnHeader col = Columns [i]; + col.InternalDisplayIndex = reordered_column_indices [i]; + } + if (redraw && view == View.Details && IsHandleCreated) { + LayoutDetails (); + header_control.Invalidate (); + item_control.Invalidate (); + } + } + + internal void AddColumn (ColumnHeader newCol, int index, bool redraw) + { + int column_count = Columns.Count; + newCol.SetListView (this); + + int [] display_indices = new int [column_count]; + for (int i = 0; i < column_count; i++) { + ColumnHeader col = Columns [i]; + if (i == index) { + display_indices [i] = index; + } else { + int display_index = col.InternalDisplayIndex; + if (display_index < index) { + display_indices [i] = display_index; + } else { + display_indices [i] = (display_index + 1); + } + } + } + + ReorderColumns (display_indices, redraw); + Invalidate (); + } + + Size LargeIconItemSize + { + get { + int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width; + int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height; + int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h); + int w = Math.Max (text_size.Width, image_w); + + if (check_boxes) + w += 2 + CheckBoxSize.Width; + + return new Size (w, h); + } + } + + Size SmallIconItemSize { + get { + int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width; + int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height; + int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h)); + int w = text_size.Width + image_w; + + if (check_boxes) + w += 2 + CheckBoxSize.Width; + + return new Size (w, h); + } + } + + Size TileItemSize { + get { + // Calculate tile size if needed + // It appears that using Font.Size instead of a SizeF value can give us + // a slightly better approach to the proportions defined in .Net + if (tile_size == Size.Empty) { + int image_w = LargeImageList == null ? 0 : LargeImageList.ImageSize.Width; + int image_h = LargeImageList == null ? 0 : LargeImageList.ImageSize.Height; + int w = (int)Font.Size * ThemeEngine.Current.ListViewTileWidthFactor + image_w + 4; + int h = Math.Max ((int)Font.Size * ThemeEngine.Current.ListViewTileHeightFactor, image_h); + + tile_size = new Size (w, h); + } + + return tile_size; + } + } + + int GetDetailsItemHeight () + { + int item_height; + int checkbox_height = CheckBoxes ? CheckBoxSize.Height : 0; + int small_image_height = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height; + item_height = Math.Max (checkbox_height, text_size.Height); + item_height = Math.Max (item_height, small_image_height); + return item_height; + } + + void SetItemLocation (int index, int x, int y, int row, int col) + { + Point old_location = items_location [index]; + if (old_location.X == x && old_location.Y == y) + return; + + items_location [index] = new Point (x, y); + items_matrix_location [index] = new ItemMatrixLocation (row, col); + + // + // Initial position matches item's position in ListViewItemCollection + // + reordered_items_indices [index] = index; + } + + + void ShiftItemsPositions (int from, int to, bool forward) + { + if (forward) { + for (int i = to + 1; i > from; i--) { + reordered_items_indices [i] = reordered_items_indices [i - 1]; + + ListViewItem item = items [reordered_items_indices [i]]; + item.Invalidate (); + item.DisplayIndex = i; + item.Invalidate (); + } + } else { + for (int i = from - 1; i < to; i++) { + reordered_items_indices [i] = reordered_items_indices [i + 1]; + + ListViewItem item = items [reordered_items_indices [i]]; + item.Invalidate (); + item.DisplayIndex = i; + item.Invalidate (); + } + } + } + + internal void ChangeItemLocation (int display_index, Point new_pos) + { + int new_display_index = GetDisplayIndexFromLocation (new_pos); + if (new_display_index == display_index) + return; + + int item_index = reordered_items_indices [display_index]; + ListViewItem item = items [item_index]; + + bool forward = new_display_index < display_index; + int index_from, index_to; + if (forward) { + index_from = new_display_index; + index_to = display_index - 1; + } else { + index_from = display_index + 1; + index_to = new_display_index; + } + + ShiftItemsPositions (index_from, index_to, forward); + + reordered_items_indices [new_display_index] = item_index; + + item.Invalidate (); + item.DisplayIndex = new_display_index; + item.Invalidate (); + } + + int GetDisplayIndexFromLocation (Point loc) + { + int display_index = -1; + Rectangle item_area; + + // First item + if (loc.X < 0 || loc.Y < 0) + return 0; + + // Adjustment to put in the next position refered by 'loc' + loc.X -= item_size.Width / 2; + if (loc.X < 0) + loc.X = 0; + + for (int i = 0; i < items.Count; i++) { + item_area = new Rectangle (GetItemLocation (i), item_size); + item_area.Inflate (ThemeEngine.Current.ListViewHorizontalSpacing, + ThemeEngine.Current.ListViewVerticalSpacing); + + if (item_area.Contains (loc)) { + display_index = i; + break; + } + } + + // Put in in last position + if (display_index == -1) + display_index = items.Count - 1; + + return display_index; + } + + // When using groups, the items with no group assigned + // belong to the DefaultGroup + int GetDefaultGroupItems () + { + int count = 0; + foreach (ListViewItem item in items) + if (item.Group == null) + count++; + + return count; + } + + // cache the spacing to let virtualmode compute the positions on the fly + int x_spacing; + int y_spacing; + int rows; + int cols; + int[,] item_index_matrix; + + void CalculateRowsAndCols (Size item_size, bool left_aligned, int x_spacing, int y_spacing) + { + Rectangle area = ClientRectangle; + + if (UseCustomColumnWidth) + CalculateCustomColumnWidth (); + if (UsingGroups) { + // When groups are used the alignment is always top-aligned + rows = 0; + cols = 0; + int items = 0; + + groups.DefaultGroup.ItemCount = GetDefaultGroupItems (); + for (int i = 0; i < groups.InternalCount; i++) { + ListViewGroup group = groups.GetInternalGroup (i); + int items_in_group = group.GetActualItemCount (); + + if (items_in_group == 0) + continue; + + int group_cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(item_size.Width + x_spacing)); + if (group_cols <= 0) + group_cols = 1; + int group_rows = (int) Math.Ceiling ((double)items_in_group / (double)group_cols); + + group.starting_row = rows; + group.rows = group_rows; + group.starting_item = items; + group.current_item = 0; // Reset layout + + cols = Math.Max (group_cols, cols); + rows += group_rows; + items += items_in_group; + } + } else + { + // Simple matrix if no groups are used + if (left_aligned) { + rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(item_size.Height + y_spacing)); + if (rows <= 0) + rows = 1; + cols = (int) Math.Ceiling ((double)items.Count / (double)rows); + } else { + if (UseCustomColumnWidth) + cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width) / (double)(custom_column_width)); + else + cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(item_size.Width + x_spacing)); + + if (cols < 1) + cols = 1; + + rows = (int) Math.Ceiling ((double)items.Count / (double)cols); + } + } + + item_index_matrix = new int [rows, cols]; + } + + // When using custom column width, we look for the minimum one + void CalculateCustomColumnWidth () + { + int min_width = Int32.MaxValue; + for (int i = 0; i < columns.Count; i++) { + int col_width = columns [i].Width; + + if (col_width < min_width) + min_width = col_width; + } + + custom_column_width = min_width; + } + + void LayoutIcons (Size item_size, bool left_aligned, int x_spacing, int y_spacing) + { + header_control.Visible = false; + header_control.Size = Size.Empty; + item_control.Visible = true; + item_control.Location = Point.Empty; + ItemSize = item_size; // Cache item size + this.x_spacing = x_spacing; + this.y_spacing = y_spacing; + + if (items.Count == 0) + return; + + Size sz = item_size; + + CalculateRowsAndCols (sz, left_aligned, x_spacing, y_spacing); + + layout_wd = UseCustomColumnWidth ? cols * custom_column_width : cols * (sz.Width + x_spacing) - x_spacing; + layout_ht = rows * (sz.Height + y_spacing) - y_spacing; + + if (virtual_mode) { // no actual assignment is needed on items for virtual mode + item_control.Size = new Size (layout_wd, layout_ht); + return; + } + + bool using_groups = UsingGroups; + if (using_groups) // the groups layout will override layout_ht + CalculateGroupsLayout (sz, y_spacing, 0); + + int row = 0, col = 0; + int x = 0, y = 0; + int display_index = 0; + + for (int i = 0; i < items.Count; i++) { + ListViewItem item = items [i]; + if (using_groups) { + ListViewGroup group = item.Group; + if (group == null) + group = groups.DefaultGroup; + + Point group_items_loc = group.items_area_location; + int current_item = group.current_item++; + int starting_row = group.starting_row; + + display_index = group.starting_item + current_item; + row = (current_item / cols); + col = current_item % cols; + + x = UseCustomColumnWidth ? col * custom_column_width : col * (item_size.Width + x_spacing); + y = row * (item_size.Height + y_spacing) + group_items_loc.Y; + + SetItemLocation (display_index, x, y, row + starting_row, col); + SetItemAtDisplayIndex (display_index, i); + item_index_matrix [row + starting_row, col] = i; + + } else + { + x = UseCustomColumnWidth ? col * custom_column_width : col * (item_size.Width + x_spacing); + y = row * (item_size.Height + y_spacing); + display_index = i; // Same as item index in Items + + SetItemLocation (i, x, y, row, col); + item_index_matrix [row, col] = i; + + if (left_aligned) { + row++; + if (row == rows) { + row = 0; + col++; + } + } else { + if (++col == cols) { + col = 0; + row++; + } + } + } + + item.Layout (); + item.DisplayIndex = display_index; + item.SetPosition (new Point (x, y)); + } + + item_control.Size = new Size (layout_wd, layout_ht); + } + + void CalculateGroupsLayout (Size item_size, int y_spacing, int y_origin) + { + int y = y_origin; + bool details = view == View.Details; + + for (int i = 0; i < groups.InternalCount; i++) { + ListViewGroup group = groups.GetInternalGroup (i); + if (group.ItemCount == 0) + continue; + + y += LayoutGroupHeader (group, y, item_size.Height, y_spacing, details ? group.ItemCount : group.rows); + } + + layout_ht = y; // Update height taking into account Groups' headers heights + } + + int LayoutGroupHeader (ListViewGroup group, int y_origin, int item_height, int y_spacing, int rows) + { + Rectangle client_area = ClientRectangle; + int header_height = Font.Height + 15; // one line height + some padding + + group.HeaderBounds = new Rectangle (0, y_origin, client_area.Width - v_scroll.Width, header_height); + group.items_area_location = new Point (0, y_origin + header_height); + + int items_area_height = ((item_height + y_spacing) * rows); + return header_height + items_area_height + 10; // Add a small bottom margin + } + + void CalculateDetailsGroupItemsCount () + { + int items = 0; + + groups.DefaultGroup.ItemCount = GetDefaultGroupItems (); + for (int i = 0; i < groups.InternalCount; i++) { + ListViewGroup group = groups.GetInternalGroup (i); + int items_in_group = group.GetActualItemCount (); + + if (items_in_group == 0) + continue; + + group.starting_item = items; + group.current_item = 0; // Reset layout. + items += items_in_group; + } + } + + void LayoutHeader () + { + int x = 0; + for (int i = 0; i < Columns.Count; i++) { + ColumnHeader col = GetReorderedColumn (i); + col.X = x; + col.Y = 0; + col.CalcColumnHeader (); + x += col.Wd; + } + + layout_wd = x; + + if (x < ClientRectangle.Width) + x = ClientRectangle.Width; + + if (header_style == ColumnHeaderStyle.None) { + header_control.Visible = false; + header_control.Size = Size.Empty; + layout_wd = ClientRectangle.Width; + } else { + header_control.Width = x; + header_control.Height = columns.Count > 0 ? columns [0].Ht : ThemeEngine.Current.ListViewGetHeaderHeight (this, Font); + header_control.Visible = true; + } + } + + void LayoutDetails () + { + LayoutHeader (); + + if (columns.Count == 0) { + item_control.Visible = false; + layout_wd = ClientRectangle.Width; + layout_ht = ClientRectangle.Height; + return; + } + + item_control.Visible = true; + item_control.Location = Point.Empty; + item_control.Width = ClientRectangle.Width; + AdjustChildrenZOrder (); + + int item_height = GetDetailsItemHeight (); + ItemSize = new Size (0, item_height); // We only cache Height for details view + int y = header_control.Height; + layout_ht = y + (item_height * items.Count); + if (items.Count > 0 && grid_lines) // some space for bottom gridline + layout_ht += 2; + + bool using_groups = UsingGroups; + if (using_groups) { + // Observe that this routines will override our layout_ht value + CalculateDetailsGroupItemsCount (); + CalculateGroupsLayout (ItemSize, 2, y); + } + + if (virtual_mode) // no assgination on items is needed + return; + + for (int i = 0; i < items.Count; i++) { + ListViewItem item = items [i]; + + int display_index; + int item_y; + + if (using_groups) { + ListViewGroup group = item.Group; + if (group == null) + group = groups.DefaultGroup; + + int current_item = group.current_item++; + Point group_items_loc = group.items_area_location; + display_index = group.starting_item + current_item; + + y = item_y = current_item * (item_height + 2) + group_items_loc.Y; + SetItemLocation (display_index, 0, item_y, 0, 0); + SetItemAtDisplayIndex (display_index, i); + } else + { + display_index = i; + item_y = y; + SetItemLocation (i, 0, item_y, 0, 0); + y += item_height; + } + + item.Layout (); + item.DisplayIndex = display_index; + item.SetPosition (new Point (0, item_y)); + } + } + + // Need to make sure HeaderControl is on top, and we can't simply use BringToFront since + // these Widgets are implicit, so we need to re-populate our collection. + void AdjustChildrenZOrder () + { + SuspendLayout (); + Widgets.ClearImplicit (); + Widgets.AddImplicit (header_control); + Widgets.AddImplicit (item_control); + Widgets.AddImplicit (h_scroll); + Widgets.AddImplicit (v_scroll); + ResumeLayout (); + } + + private void AdjustItemsPositionArray (int count) + { + // In virtual mode we compute the positions on the fly. + if (virtual_mode) + return; + if (items_location.Length >= count) + return; + + // items_location, items_matrix_location and reordered_items_indices must keep the same length + count = Math.Max (count, items_location.Length * 2); + items_location = new Point [count]; + items_matrix_location = new ItemMatrixLocation [count]; + reordered_items_indices = new int [count]; + } + + private void CalculateListView (ListViewAlignment align) + { + CalcTextSize (); + + AdjustItemsPositionArray (items.Count); + + switch (view) { + case View.Details: + LayoutDetails (); + break; + + case View.SmallIcon: + LayoutIcons (SmallIconItemSize, alignment == ListViewAlignment.Left, + ThemeEngine.Current.ListViewHorizontalSpacing, 2); + break; + + case View.LargeIcon: + LayoutIcons (LargeIconItemSize, alignment == ListViewAlignment.Left, + ThemeEngine.Current.ListViewHorizontalSpacing, + ThemeEngine.Current.ListViewVerticalSpacing); + break; + + case View.List: + LayoutIcons (SmallIconItemSize, true, + ThemeEngine.Current.ListViewHorizontalSpacing, 2); + break; + case View.Tile: + if (!Application.VisualStylesEnabled) + goto case View.LargeIcon; + + LayoutIcons (TileItemSize, alignment == ListViewAlignment.Left, + ThemeEngine.Current.ListViewHorizontalSpacing, + ThemeEngine.Current.ListViewVerticalSpacing); + break; + } + + CalculateScrollBars (); + } + + internal Point GetItemLocation (int index) + { + Point loc = Point.Empty; + if (virtual_mode) + loc = GetFixedItemLocation (index); + else + loc = items_location [index]; + + loc.X -= h_marker; // Adjust to scroll + loc.Y -= v_marker; + + return loc; + } + + Point GetFixedItemLocation (int index) + { + Point loc = Point.Empty; + + switch (view) { + case View.LargeIcon: + case View.SmallIcon: + loc.X = index % cols * (item_size.Width + x_spacing); + loc.Y = index / cols * (item_size.Height + y_spacing); + break; + case View.List: + loc.X = index / rows * (item_size.Width + x_spacing); + loc.Y = index % rows * (item_size.Height + y_spacing); + break; + case View.Details: + loc.Y = header_control.Height + (index * item_size.Height); + break; + } + + return loc; + } + + internal int GetItemIndex (int display_index) + { + if (virtual_mode) + return display_index; // no reordering in virtual mode. + return reordered_items_indices [display_index]; + } + + internal ListViewItem GetItemAtDisplayIndex (int display_index) + { + // in virtual mode there's no reordering at all. + if (virtual_mode) + return items [display_index]; + return items [reordered_items_indices [display_index]]; + } + + internal void SetItemAtDisplayIndex (int display_index, int index) + { + reordered_items_indices [display_index] = index; + } + + private bool KeySearchString (KeyEventArgs ke) + { + int current_tickcnt = Environment.TickCount; + if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) { + keysearch_text = string.Empty; + } + + if (!Char.IsLetterOrDigit ((char)ke.KeyCode)) + return false; + + keysearch_text += (char)ke.KeyCode; + keysearch_tickcnt = current_tickcnt; + + int prev_focused = FocusedItem == null ? 0 : FocusedItem.DisplayIndex; + int start = prev_focused + 1 < Items.Count ? prev_focused + 1 : 0; + + ListViewItem item = FindItemWithText (keysearch_text, false, start, true, true); + if (item != null && prev_focused != item.DisplayIndex) { + selected_indices.Clear (); + + SetFocusedItem (item.DisplayIndex); + item.Selected = true; + EnsureVisible (GetItemIndex (item.DisplayIndex)); + } + + return true; + } + + private void OnItemsChanged () + { + ResetSearchString (); + } + + private void ResetSearchString () + { + keysearch_text = String.Empty; + } + + int GetAdjustedIndex (Keys key) + { + int result = -1; + + if (View == View.Details) { + switch (key) { + case Keys.Up: + result = FocusedItem.DisplayIndex - 1; + break; + case Keys.Down: + result = FocusedItem.DisplayIndex + 1; + if (result == items.Count) + result = -1; + break; + case Keys.PageDown: + int last_index = LastVisibleIndex; + Rectangle item_rect = new Rectangle (GetItemLocation (last_index), ItemSize); + if (item_rect.Bottom > item_control.ClientRectangle.Bottom) + last_index--; + if (FocusedItem.DisplayIndex == last_index) { + if (FocusedItem.DisplayIndex < Items.Count - 1) { + int page_size = item_control.Height / ItemSize.Height - 1; + result = FocusedItem.DisplayIndex + page_size - 1; + if (result >= Items.Count) + result = Items.Count - 1; + } + } else + result = last_index; + break; + case Keys.PageUp: + int first_index = FirstVisibleIndex; + if (GetItemLocation (first_index).Y < 0) + first_index++; + if (FocusedItem.DisplayIndex == first_index) { + if (first_index > 0) { + int page_size = item_control.Height / ItemSize.Height - 1; + result = first_index - page_size + 1; + if (result < 0) + result = 0; + } + } else + result = first_index; + break; + } + return result; + } + + if (virtual_mode) + return GetFixedAdjustedIndex (key); + + ItemMatrixLocation item_matrix_location = items_matrix_location [FocusedItem.DisplayIndex]; + int row = item_matrix_location.Row; + int col = item_matrix_location.Col; + + int adjusted_index = -1; + + switch (key) { + case Keys.Left: + if (col == 0) + return -1; + adjusted_index = item_index_matrix [row, col - 1]; + break; + + case Keys.Right: + if (col == (cols - 1)) + return -1; + while (item_index_matrix [row, col + 1] == 0) { + row--; + if (row < 0) + return -1; + } + adjusted_index = item_index_matrix [row, col + 1]; + break; + + case Keys.Up: + if (row == 0) + return -1; + while (item_index_matrix [row - 1, col] == 0 && row != 1) { + col--; + if (col < 0) + return -1; + } + adjusted_index = item_index_matrix [row - 1, col]; + break; + + case Keys.Down: + if (row == (rows - 1) || row == Items.Count - 1) + return -1; + while (item_index_matrix [row + 1, col] == 0) { + col--; + if (col < 0) + return -1; + } + adjusted_index = item_index_matrix [row + 1, col]; + break; + + default: + return -1; + } + + return items [adjusted_index].DisplayIndex; + } + + // Used for virtual mode, where items *cannot* be re-arranged + int GetFixedAdjustedIndex (Keys key) + { + int result; + + switch (key) { + case Keys.Left: + if (view == View.List) + result = focused_item_index - rows; + else + result = focused_item_index - 1; + break; + case Keys.Right: + if (view == View.List) + result = focused_item_index + rows; + else + result = focused_item_index + 1; + break; + case Keys.Up: + if (view != View.List) + result = focused_item_index - cols; + else + result = focused_item_index - 1; + break; + case Keys.Down: + if (view != View.List) + result = focused_item_index + cols; + else + result = focused_item_index + 1; + break; + default: + return -1; + + } + + if (result < 0 || result >= items.Count) + result = focused_item_index; + + return result; + } + + ListViewItem selection_start; + + private bool SelectItems (ArrayList sel_items) + { + bool changed = false; + foreach (ListViewItem item in SelectedItems) + if (!sel_items.Contains (item)) { + item.Selected = false; + changed = true; + } + foreach (ListViewItem item in sel_items) + if (!item.Selected) { + item.Selected = true; + changed = true; + } + return changed; + } + + private void UpdateMultiSelection (int index, bool reselect) + { + bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0; + bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Widget) != 0; + ListViewItem item = GetItemAtDisplayIndex (index); + + if (shift_pressed && selection_start != null) { + ArrayList list = new ArrayList (); + int start_index = selection_start.DisplayIndex; + int start = Math.Min (start_index, index); + int end = Math.Max (start_index, index); + if (View == View.Details) { + for (int i = start; i <= end; i++) + list.Add (GetItemAtDisplayIndex (i)); + } else { + ItemMatrixLocation start_item_matrix_location = items_matrix_location [start]; + ItemMatrixLocation end_item_matrix_location = items_matrix_location [end]; + int left = Math.Min (start_item_matrix_location.Col, end_item_matrix_location.Col); + int right = Math.Max (start_item_matrix_location.Col, end_item_matrix_location.Col); + int top = Math.Min (start_item_matrix_location.Row, end_item_matrix_location.Row); + int bottom = Math.Max (start_item_matrix_location.Row, end_item_matrix_location.Row); + + for (int i = 0; i < items.Count; i++) { + ItemMatrixLocation item_matrix_loc = items_matrix_location [i]; + + if (item_matrix_loc.Row >= top && item_matrix_loc.Row <= bottom && + item_matrix_loc.Col >= left && item_matrix_loc.Col <= right) + list.Add (GetItemAtDisplayIndex (i)); + } + } + SelectItems (list); + } else if (ctrl_pressed) { + item.Selected = !item.Selected; + selection_start = item; + } else { + if (!reselect) { + // do not unselect, and reselect the item + foreach (int itemIndex in SelectedIndices) { + if (index == itemIndex) + continue; + items [itemIndex].Selected = false; + } + } else { + SelectedItems.Clear (); + item.Selected = true; + } + selection_start = item; + } + } + + internal override bool InternalPreProcessMessage (ref Message msg) + { + if (msg.Msg == (int)Msg.WM_KEYDOWN) { + Keys key_data = (Keys)msg.WParam.ToInt32(); + + HandleNavKeys (key_data); + } + + return base.InternalPreProcessMessage (ref msg); + } + + bool HandleNavKeys (Keys key_data) + { + if (Items.Count == 0 || !item_control.Visible) + return false; + + if (FocusedItem == null) + SetFocusedItem (0); + + switch (key_data) { + case Keys.End: + SelectIndex (Items.Count - 1); + break; + + case Keys.Home: + SelectIndex (0); + break; + + case Keys.Left: + case Keys.Right: + case Keys.Up: + case Keys.Down: + case Keys.PageUp: + case Keys.PageDown: + SelectIndex (GetAdjustedIndex (key_data)); + break; + + case Keys.Space: + SelectIndex (focused_item_index); + ToggleItemsCheckState (); + break; + case Keys.Enter: + if (selected_indices.Count > 0) + OnItemActivate (EventArgs.Empty); + break; + + default: + return false; + } + + return true; + } + + void ToggleItemsCheckState () + { + if (!CheckBoxes) + return; + + // Don't modify check state if StateImageList has less than 2 elements + if (StateImageList != null && StateImageList.Images.Count < 2) + return; + + if (SelectedIndices.Count > 0) { + for (int i = 0; i < SelectedIndices.Count; i++) { + ListViewItem item = Items [SelectedIndices [i]]; + item.Checked = !item.Checked; + } + return; + } + + if (FocusedItem != null) { + FocusedItem.Checked = !FocusedItem.Checked; + SelectIndex (FocusedItem.Index); + } + } + + void SelectIndex (int display_index) + { + if (display_index == -1) + return; + + if (MultiSelect) + UpdateMultiSelection (display_index, true); + else if (!GetItemAtDisplayIndex (display_index).Selected) + GetItemAtDisplayIndex (display_index).Selected = true; + + SetFocusedItem (display_index); + EnsureVisible (GetItemIndex (display_index)); // Index in Items collection, not display index + } + + private void ListView_KeyDown (object sender, KeyEventArgs ke) + { + if (ke.Handled || Items.Count == 0 || !item_control.Visible) + return; + + if (ke.Alt || ke.Widget) + return; + + ke.Handled = KeySearchString (ke); + } + + private MouseEventArgs TranslateMouseEventArgs (MouseEventArgs args) + { + Point loc = PointToClient (Widget.MousePosition); + return new MouseEventArgs (args.Button, args.Clicks, loc.X, loc.Y, args.Delta); + } + + internal class ItemControl : Widget { + + ListView owner; + ListViewItem clicked_item; + ListViewItem last_clicked_item; + bool hover_processed = false; + bool checking = false; + ListViewItem prev_hovered_item; + ListViewItem prev_tooltip_item; + int clicks; + Point drag_begin = new Point (-1, -1); + internal int dragged_item_index = -1; + + ListViewLabelEditTextBox edit_text_box; + internal ListViewItem edit_item; + LabelEditEventArgs edit_args; + + public ItemControl (ListView owner) + { + this.owner = owner; + this.SetStyle (Widgetstyles.DoubleBuffer, true); + DoubleClick += new EventHandler(ItemsDoubleClick); + MouseDown += new MouseEventHandler(ItemsMouseDown); + MouseMove += new MouseEventHandler(ItemsMouseMove); + MouseHover += new EventHandler(ItemsMouseHover); + MouseUp += new MouseEventHandler(ItemsMouseUp); + } + + void ItemsDoubleClick (object sender, EventArgs e) + { + if (owner.activation == ItemActivation.Standard) + owner.OnItemActivate (EventArgs.Empty); + } + + enum BoxSelect { + None, + Normal, + Shift, + Widget + } + + BoxSelect box_select_mode = BoxSelect.None; + IList prev_selection; + Point box_select_start; + + Rectangle box_select_rect; + internal Rectangle BoxSelectRectangle { + get { return box_select_rect; } + set { + if (box_select_rect == value) + return; + + InvalidateBoxSelectRect (); + box_select_rect = value; + InvalidateBoxSelectRect (); + } + } + + void InvalidateBoxSelectRect () + { + if (BoxSelectRectangle.Size.IsEmpty) + return; + + Rectangle edge = BoxSelectRectangle; + edge.X -= 1; + edge.Y -= 1; + edge.Width += 2; + edge.Height = 2; + Invalidate (edge); + edge.Y = BoxSelectRectangle.Bottom - 1; + Invalidate (edge); + edge.Y = BoxSelectRectangle.Y - 1; + edge.Width = 2; + edge.Height = BoxSelectRectangle.Height + 2; + Invalidate (edge); + edge.X = BoxSelectRectangle.Right - 1; + Invalidate (edge); + } + + private Rectangle CalculateBoxSelectRectangle (Point pt) + { + int left = Math.Min (box_select_start.X, pt.X); + int right = Math.Max (box_select_start.X, pt.X); + int top = Math.Min (box_select_start.Y, pt.Y); + int bottom = Math.Max (box_select_start.Y, pt.Y); + return Rectangle.FromLTRB (left, top, right, bottom); + } + + bool BoxIntersectsItem (int index) + { + Rectangle r = new Rectangle (owner.GetItemLocation (index), owner.ItemSize); + if (owner.View != View.Details) { + r.X += r.Width / 4; + r.Y += r.Height / 4; + r.Width /= 2; + r.Height /= 2; + } + return BoxSelectRectangle.IntersectsWith (r); + } + + bool BoxIntersectsText (int index) + { + Rectangle r = owner.GetItemAtDisplayIndex (index).TextBounds; + return BoxSelectRectangle.IntersectsWith (r); + } + + ArrayList BoxSelectedItems { + get { + ArrayList result = new ArrayList (); + for (int i = 0; i < owner.Items.Count; i++) { + bool intersects; + // Can't iterate over specific items properties in virtualmode + if (owner.View == View.Details && !owner.FullRowSelect && !owner.VirtualMode) + intersects = BoxIntersectsText (i); + else + intersects = BoxIntersectsItem (i); + + if (intersects) + result.Add (owner.GetItemAtDisplayIndex (i)); + } + return result; + } + } + + private bool PerformBoxSelection (Point pt) + { + if (box_select_mode == BoxSelect.None) + return false; + + BoxSelectRectangle = CalculateBoxSelectRectangle (pt); + + ArrayList box_items = BoxSelectedItems; + + ArrayList items; + + switch (box_select_mode) { + + case BoxSelect.Normal: + items = box_items; + break; + + case BoxSelect.Widget: + items = new ArrayList (); + foreach (int index in prev_selection) + if (!box_items.Contains (owner.Items [index])) + items.Add (owner.Items [index]); + foreach (ListViewItem item in box_items) + if (!prev_selection.Contains (item.Index)) + items.Add (item); + break; + + case BoxSelect.Shift: + items = box_items; + foreach (ListViewItem item in box_items) + prev_selection.Remove (item.Index); + foreach (int index in prev_selection) + items.Add (owner.Items [index]); + break; + + default: + throw new Exception ("Unexpected Selection mode: " + box_select_mode); + } + + SuspendLayout (); + owner.SelectItems (items); + ResumeLayout (); + + return true; + } + + private void ItemsMouseDown (object sender, MouseEventArgs me) + { + owner.OnMouseDown (owner.TranslateMouseEventArgs (me)); + if (owner.items.Count == 0) + return; + + bool box_selecting = false; + Size item_size = owner.ItemSize; + Point pt = new Point (me.X, me.Y); + for (int i = 0; i < owner.items.Count; i++) { + Rectangle item_rect = new Rectangle (owner.GetItemLocation (i), item_size); + if (!item_rect.Contains (pt)) + continue; + + // Actual item in 'i' position + ListViewItem item = owner.GetItemAtDisplayIndex (i); + + if (item.CheckRectReal.Contains (pt)) { + // Don't modify check state if we have only one image + // and if we are in 1.1 profile only take into account + // double clicks + if (owner.StateImageList != null && owner.StateImageList.Images.Count < 2 + ) + return; + + // Generate an extra ItemCheck event when we got two clicks + // (Match weird .Net behaviour) + if (me.Clicks == 2) + item.Checked = !item.Checked; + + item.Checked = !item.Checked; + checking = true; + return; + } + + if (owner.View == View.Details) { + bool over_text = item.TextBounds.Contains (pt); + if (owner.FullRowSelect) { + clicked_item = item; + bool over_item_column = (me.X > owner.Columns[0].X && me.X < owner.Columns[0].X + owner.Columns[0].Width); + if (!over_text && over_item_column && owner.MultiSelect) + box_selecting = true; + } else if (over_text) + clicked_item = item; + else + owner.SetFocusedItem (i); + } else + clicked_item = item; + + break; + } + + + if (clicked_item != null) { + bool changed = !clicked_item.Selected; + if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed)) + owner.SetFocusedItem (clicked_item.DisplayIndex); + + if (owner.MultiSelect) { + bool reselect = (!owner.LabelEdit || changed); + if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed)) + owner.UpdateMultiSelection (clicked_item.DisplayIndex, reselect); + } else { + clicked_item.Selected = true; + } + + // Side-effects of changing the selection can possibly result in ItemsMouseUp() being called and + // and clicked_item being set to null. (See Xamarin bug 23591.) In such a case, assume + // that there's nothing more we can do here. + if (clicked_item == null) + return; + + if (owner.VirtualMode && changed) { + // Broken event - It's not fired from Item.Selected also + ListViewVirtualItemsSelectionRangeChangedEventArgs args = + new ListViewVirtualItemsSelectionRangeChangedEventArgs (0, owner.items.Count - 1, false); + + owner.OnVirtualItemsSelectionRangeChanged (args); + } + // Report clicks only if the item was clicked. On MS the + // clicks are only raised if you click an item + clicks = me.Clicks; + if (me.Clicks > 1) { + if (owner.CheckBoxes) + clicked_item.Checked = !clicked_item.Checked; + } else if (me.Clicks == 1) { + if (owner.LabelEdit && !changed) + BeginEdit (clicked_item); // this is probably not the correct place to execute BeginEdit + } + + drag_begin = me.Location; + dragged_item_index = clicked_item.Index; + } else { + if (owner.MultiSelect) + box_selecting = true; + else if (owner.SelectedItems.Count > 0) + owner.SelectedItems.Clear (); + } + + if (box_selecting) { + Keys mods = XplatUI.State.ModifierKeys; + if ((mods & Keys.Shift) != 0) + box_select_mode = BoxSelect.Shift; + else if ((mods & Keys.Widget) != 0) + box_select_mode = BoxSelect.Widget; + else + box_select_mode = BoxSelect.Normal; + box_select_start = pt; + prev_selection = owner.SelectedIndices.List.Clone () as IList; + } + } + + private void ItemsMouseMove (object sender, MouseEventArgs me) + { + bool done = PerformBoxSelection (new Point (me.X, me.Y)); + + owner.OnMouseMove (owner.TranslateMouseEventArgs (me)); + + if (done) + return; + if ((me.Button != MouseButtons.Left && me.Button != MouseButtons.Right) && + !hover_processed && owner.Activation != ItemActivation.OneClick + && !owner.ShowItemToolTips + ) + return; + + Point pt = PointToClient (Widget.MousePosition); + ListViewItem item = owner.GetItemAt (pt.X, pt.Y); + + if (hover_processed && item != null && item != prev_hovered_item) { + hover_processed = false; + XplatUI.ResetMouseHover (Handle); + } + + // Need to invalidate the item in HotTracking to show/hide the underline style + if (owner.Activation == ItemActivation.OneClick) { + if (item == null && owner.HotItemIndex != -1) { + if (owner.HotTracking) + Invalidate (owner.Items [owner.HotItemIndex].Bounds); // Previous one + + Cursor = Cursors.Default; + owner.HotItemIndex = -1; + } else if (item != null && owner.HotItemIndex == -1) { + if (owner.HotTracking) + Invalidate (item.Bounds); + + Cursor = Cursors.Hand; + owner.HotItemIndex = item.Index; + } + } + + if (me.Button == MouseButtons.Left || me.Button == MouseButtons.Right) { + if (drag_begin != new Point (-1, -1)) { + Rectangle r = new Rectangle (drag_begin, SystemInformation.DragSize); + if (!r.Contains (me.X, me.Y)) { + ListViewItem dragged_item = owner.items [dragged_item_index]; + owner.OnItemDrag (new ItemDragEventArgs (me.Button, dragged_item)); + + drag_begin = new Point (-1, -1); + dragged_item_index = -1; + } + } + } + + if (owner.ShowItemToolTips) { + if (item == null) { + owner.item_tooltip.Active = false; + prev_tooltip_item = null; + } else if (item != prev_tooltip_item && item.ToolTipText.Length > 0) { + owner.item_tooltip.Active = true; + owner.item_tooltip.SetToolTip (owner, item.ToolTipText); + prev_tooltip_item = item; + } + } + + } + + private void ItemsMouseHover (object sender, EventArgs e) + { + if (owner.hover_pending) { + owner.OnMouseHover (e); + owner.hover_pending = false; + } + + if (Capture) + return; + + hover_processed = true; + Point pt = PointToClient (Widget.MousePosition); + ListViewItem item = owner.GetItemAt (pt.X, pt.Y); + if (item == null) + return; + + prev_hovered_item = item; + + if (owner.HoverSelection) { + if (owner.MultiSelect) + owner.UpdateMultiSelection (item.Index, true); + else + item.Selected = true; + + owner.SetFocusedItem (item.DisplayIndex); + Select (); // Make sure we have the focus, since MouseHover doesn't give it to us + } + + owner.OnItemMouseHover (new ListViewItemMouseHoverEventArgs (item)); + } + + void HandleClicks (MouseEventArgs me) + { + // if the click is not on an item, + // clicks remains as 0 + if (clicks > 1) { + owner.OnDoubleClick (EventArgs.Empty); + owner.OnMouseDoubleClick (me); + } else if (clicks == 1) { + owner.OnClick (EventArgs.Empty); + owner.OnMouseClick (me); + } + + clicks = 0; + } + + private void ItemsMouseUp (object sender, MouseEventArgs me) + { + MouseEventArgs owner_me = owner.TranslateMouseEventArgs (me); + HandleClicks (owner_me); + + Capture = false; + if (owner.Items.Count == 0) { + ResetMouseState (); + owner.OnMouseUp (owner_me); + return; + } + + Point pt = new Point (me.X, me.Y); + + Rectangle rect = Rectangle.Empty; + if (clicked_item != null) { + if (owner.view == View.Details && !owner.full_row_select) + rect = clicked_item.GetBounds (ItemBoundsPortion.Label); + else + rect = clicked_item.Bounds; + + if (rect.Contains (pt)) { + switch (owner.activation) { + case ItemActivation.OneClick: + owner.OnItemActivate (EventArgs.Empty); + break; + + case ItemActivation.TwoClick: + if (last_clicked_item == clicked_item) { + owner.OnItemActivate (EventArgs.Empty); + last_clicked_item = null; + } else + last_clicked_item = clicked_item; + break; + default: + // DoubleClick activation is handled in another handler + break; + } + } + } else if (!checking && owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) { + // Need this to clean up background clicks + owner.SelectedItems.Clear (); + } + + ResetMouseState (); + owner.OnMouseUp (owner_me); + } + + private void ResetMouseState () + { + clicked_item = null; + box_select_start = Point.Empty; + BoxSelectRectangle = Rectangle.Empty; + prev_selection = null; + box_select_mode = BoxSelect.None; + checking = false; + + // Clean these bits in case the mouse buttons were + // released before firing ItemDrag + dragged_item_index = -1; + drag_begin = new Point (-1, -1); + } + + private void LabelEditFinished (object sender, EventArgs e) + { + EndEdit (edit_item); + } + + private void LabelEditCancelled (object sender, EventArgs e) + { + edit_args.SetLabel (null); + EndEdit (edit_item); + } + + private void LabelTextChanged (object sender, EventArgs e) + { + if (edit_args != null) + edit_args.SetLabel (edit_text_box.Text); + } + + internal void BeginEdit (ListViewItem item) + { + if (edit_item != null) + EndEdit (edit_item); + + if (edit_text_box == null) { + edit_text_box = new ListViewLabelEditTextBox (); + edit_text_box.BorderStyle = BorderStyle.FixedSingle; + edit_text_box.EditingCancelled += new EventHandler (LabelEditCancelled); + edit_text_box.EditingFinished += new EventHandler (LabelEditFinished); + edit_text_box.TextChanged += new EventHandler (LabelTextChanged); + edit_text_box.Visible = false; + Widgets.Add (edit_text_box); + } + + item.EnsureVisible(); + + edit_text_box.Reset (); + + switch (owner.view) { + case View.List: + case View.SmallIcon: + case View.Details: + edit_text_box.TextAlign = HorizontalAlignment.Left; + edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label); + SizeF sizef = TextRenderer.MeasureString (item.Text, item.Font); + edit_text_box.Width = (int)sizef.Width + 4; + edit_text_box.MaxWidth = owner.ClientRectangle.Width - edit_text_box.Bounds.X; + edit_text_box.WordWrap = false; + edit_text_box.Multiline = false; + break; + case View.LargeIcon: + edit_text_box.TextAlign = HorizontalAlignment.Center; + edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label); + sizef = TextRenderer.MeasureString (item.Text, item.Font); + edit_text_box.Width = (int)sizef.Width + 4; + edit_text_box.MaxWidth = item.GetBounds(ItemBoundsPortion.Entire).Width; + edit_text_box.MaxHeight = owner.ClientRectangle.Height - edit_text_box.Bounds.Y; + edit_text_box.WordWrap = true; + edit_text_box.Multiline = true; + break; + } + + edit_item = item; + + edit_text_box.Text = item.Text; + edit_text_box.Font = item.Font; + edit_text_box.Visible = true; + edit_text_box.Focus (); + edit_text_box.SelectAll (); + + edit_args = new LabelEditEventArgs (owner.Items.IndexOf (edit_item)); + owner.OnBeforeLabelEdit (edit_args); + + if (edit_args.CancelEdit) + EndEdit (item); + } + + internal void CancelEdit (ListViewItem item) + { + // do nothing if there's no item being edited, or if the + // item being edited is not the one passed in + if (edit_item == null || edit_item != item) + return; + + edit_args.SetLabel (null); + EndEdit (item); + } + + internal void EndEdit (ListViewItem item) + { + // do nothing if there's no item being edited, or if the + // item being edited is not the one passed in + if (edit_item == null || edit_item != item) + return; + + if (edit_text_box != null) { + if (edit_text_box.Visible) + edit_text_box.Visible = false; + // ensure listview gets focus + owner.Focus (); + } + + // Same as TreeView.EndEdit: need to have focus in synch + Application.DoEvents (); + + // + // Create a new instance, since we could get a call to BeginEdit + // from the handler and have fields out of synch + // + LabelEditEventArgs args = new LabelEditEventArgs (item.Index, edit_args.Label); + edit_item = null; + + owner.OnAfterLabelEdit (args); + if (!args.CancelEdit && args.Label != null) + item.Text = args.Label; + } + + internal override void OnPaintInternal (PaintEventArgs pe) + { + ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner); + } + + protected override void WndProc (ref Message m) + { + switch ((Msg)m.Msg) { + case Msg.WM_KILLFOCUS: + owner.Select (false, true); + break; + case Msg.WM_SETFOCUS: + owner.Select (false, true); + break; + case Msg.WM_LBUTTONDOWN: + if (!Focused) + owner.Select (false, true); + break; + case Msg.WM_RBUTTONDOWN: + if (!Focused) + owner.Select (false, true); + break; + default: + break; + } + base.WndProc (ref m); + } + } + + internal class ListViewLabelEditTextBox : TextBox + { + int max_width = -1; + int min_width = -1; + + int max_height = -1; + int min_height = -1; + + int old_number_lines = 1; + + SizeF text_size_one_char; + + public ListViewLabelEditTextBox () + { + min_height = DefaultSize.Height; + text_size_one_char = TextRenderer.MeasureString ("B", Font); + } + + public int MaxWidth { + set { + if (value < min_width) + max_width = min_width; + else + max_width = value; + } + } + + public int MaxHeight { + set { + if (value < min_height) + max_height = min_height; + else + max_height = value; + } + } + + public new int Width { + get { + return base.Width; + } + set { + min_width = value; + base.Width = value; + } + } + + public override Font Font { + get { + return base.Font; + } + set { + base.Font = value; + text_size_one_char = TextRenderer.MeasureString ("B", Font); + } + } + + protected override void OnTextChanged (EventArgs e) + { + SizeF text_size = TextRenderer.MeasureString (Text, Font); + + int new_width = (int)text_size.Width + 8; + + if (!Multiline) + ResizeTextBoxWidth (new_width); + else { + if (Width != max_width) + ResizeTextBoxWidth (new_width); + + int number_lines = Lines.Length; + + if (number_lines != old_number_lines) { + int new_height = number_lines * (int)text_size_one_char.Height + 4; + old_number_lines = number_lines; + + ResizeTextBoxHeight (new_height); + } + } + + base.OnTextChanged (e); + } + + protected override bool IsInputKey (Keys key_data) + { + if ((key_data & Keys.Alt) == 0) { + switch (key_data & Keys.KeyCode) { + case Keys.Enter: + return true; + case Keys.Escape: + return true; + } + } + return base.IsInputKey (key_data); + } + + protected override void OnKeyDown (KeyEventArgs e) + { + if (!Visible) + return; + + switch (e.KeyCode) { + case Keys.Return: + Visible = false; + e.Handled = true; + OnEditingFinished (e); + break; + case Keys.Escape: + Visible = false; + e.Handled = true; + OnEditingCancelled (e); + break; + } + } + + protected override void OnLostFocus (EventArgs e) + { + if (Visible) { + OnEditingFinished (e); + } + } + + protected void OnEditingCancelled (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [EditingCancelledEvent]); + if (eh != null) + eh (this, e); + } + + protected void OnEditingFinished (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [EditingFinishedEvent]); + if (eh != null) + eh (this, e); + } + + private void ResizeTextBoxWidth (int new_width) + { + if (new_width > max_width) + base.Width = max_width; + else + if (new_width >= min_width) + base.Width = new_width; + else + base.Width = min_width; + } + + private void ResizeTextBoxHeight (int new_height) + { + if (new_height > max_height) + base.Height = max_height; + else + if (new_height >= min_height) + base.Height = new_height; + else + base.Height = min_height; + } + + public void Reset () + { + max_width = -1; + min_width = -1; + + max_height = -1; + + old_number_lines = 1; + + Text = String.Empty; + + Size = DefaultSize; + } + + static object EditingCancelledEvent = new object (); + public event EventHandler EditingCancelled { + add { Events.AddHandler (EditingCancelledEvent, value); } + remove { Events.RemoveHandler (EditingCancelledEvent, value); } + } + + static object EditingFinishedEvent = new object (); + public event EventHandler EditingFinished { + add { Events.AddHandler (EditingFinishedEvent, value); } + remove { Events.RemoveHandler (EditingFinishedEvent, value); } + } + } + + internal override void OnPaintInternal (PaintEventArgs pe) + { + if (updating) + return; + + CalculateScrollBars (); + } + + void FocusChanged (object o, EventArgs args) + { + if (Items.Count == 0) + return; + + if (FocusedItem == null) + SetFocusedItem (0); + + ListViewItem focused_item = FocusedItem; + + if (focused_item.ListView != null) { + focused_item.Invalidate (); + focused_item.Layout (); + focused_item.Invalidate (); + } + } + + private void ListView_Invalidated (object sender, InvalidateEventArgs e) + { + // When the ListView is invalidated, we need to invalidate + // the child Widgets. + header_control.Invalidate (); + item_control.Invalidate (); + } + + private void ListView_MouseEnter (object sender, EventArgs args) + { + hover_pending = true; // Need a hover event for every Enter/Leave cycle + } + + private void ListView_MouseWheel (object sender, MouseEventArgs me) + { + if (Items.Count == 0) + return; + + int lines = me.Delta / 120; + + if (lines == 0) + return; + + switch (View) { + case View.Details: + case View.SmallIcon: + Scroll (v_scroll, -ItemSize.Height * SystemInformation.MouseWheelScrollLines * lines); + break; + case View.LargeIcon: + Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines); + break; + case View.List: + Scroll (h_scroll, -ItemSize.Width * lines); + break; + case View.Tile: + if (!Application.VisualStylesEnabled) + goto case View.LargeIcon; + + Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * 2 * lines); + break; + } + } + + private void ListView_SizeChanged (object sender, EventArgs e) + { + Redraw (true); + } + + private void SetFocusedItem (int display_index) + { + if (display_index != -1) + GetItemAtDisplayIndex (display_index).Focused = true; + else if (focused_item_index != -1 && focused_item_index < items.Count) // Previous focused item + GetItemAtDisplayIndex (focused_item_index).Focused = false; + focused_item_index = display_index; + if (display_index == -1) + OnUIAFocusedItemChanged (); + // otherwise the event will have been fired + // when the ListViewItem's Focused was set + } + + private void HorizontalScroller (object sender, EventArgs e) + { + item_control.EndEdit (item_control.edit_item); + + // Avoid unnecessary flickering, when button is + // kept pressed at the end + if (h_marker != h_scroll.Value) { + + int pixels = h_marker - h_scroll.Value; + + h_marker = h_scroll.Value; + if (header_control.Visible) + XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false); + + XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false); + } + } + + private void VerticalScroller (object sender, EventArgs e) + { + item_control.EndEdit (item_control.edit_item); + + // Avoid unnecessary flickering, when button is + // kept pressed at the end + if (v_marker != v_scroll.Value) { + int pixels = v_marker - v_scroll.Value; + Rectangle area = item_control.ClientRectangle; + if (header_control.Visible) { + area.Y += header_control.Height; + area.Height -= header_control.Height; + } + + v_marker = v_scroll.Value; + XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false); + } + } + + internal override bool IsInputCharInternal (char charCode) + { + return true; + } + #endregion // Internal Methods Properties + + #region Protected Methods + protected override void CreateHandle () + { + base.CreateHandle (); + is_selection_available = true; + for (int i = 0; i < SelectedItems.Count; i++) + OnSelectedIndexChanged (EventArgs.Empty); + } + + protected override void Dispose (bool disposing) + { + if (disposing) { + large_image_list = null; + small_image_list = null; + state_image_list = null; + + foreach (ColumnHeader col in columns) + col.SetListView (null); + + if (!virtual_mode) // In virtual mode we don't save the items + foreach (ListViewItem item in items) + item.Owner = null; + } + + base.Dispose (disposing); + } + + protected override bool IsInputKey (Keys keyData) + { + switch (keyData) { + case Keys.Up: + case Keys.Down: + case Keys.PageUp: + case Keys.PageDown: + case Keys.Right: + case Keys.Left: + case Keys.End: + case Keys.Home: + return true; + + default: + break; + } + + return base.IsInputKey (keyData); + } + + protected virtual void OnAfterLabelEdit (LabelEditEventArgs e) + { + LabelEditEventHandler eh = (LabelEditEventHandler)(Events [AfterLabelEditEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnBackgroundImageChanged (EventArgs e) + { + item_control.BackgroundImage = BackgroundImage; + base.OnBackgroundImageChanged (e); + } + + protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e) + { + LabelEditEventHandler eh = (LabelEditEventHandler)(Events [BeforeLabelEditEvent]); + if (eh != null) + eh (this, e); + } + + protected internal virtual void OnColumnClick (ColumnClickEventArgs e) + { + ColumnClickEventHandler eh = (ColumnClickEventHandler)(Events [ColumnClickEvent]); + if (eh != null) + eh (this, e); + } + + protected internal virtual void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e) + { + DrawListViewColumnHeaderEventHandler eh = (DrawListViewColumnHeaderEventHandler)(Events[DrawColumnHeaderEvent]); + if (eh != null) + eh(this, e); + } + + protected internal virtual void OnDrawItem(DrawListViewItemEventArgs e) + { + DrawListViewItemEventHandler eh = (DrawListViewItemEventHandler)(Events[DrawItemEvent]); + if (eh != null) + eh(this, e); + } + + protected internal virtual void OnDrawSubItem(DrawListViewSubItemEventArgs e) + { + DrawListViewSubItemEventHandler eh = (DrawListViewSubItemEventHandler)(Events[DrawSubItemEvent]); + if (eh != null) + eh(this, e); + } + + protected override void OnFontChanged (EventArgs e) + { + base.OnFontChanged (e); + Redraw (true); + } + + protected override void OnHandleCreated (EventArgs e) + { + base.OnHandleCreated (e); + CalculateListView (alignment); + if (!virtual_mode) // Sorting is not allowed in virtual mode + Sort (); + } + + protected override void OnHandleDestroyed (EventArgs e) + { + base.OnHandleDestroyed (e); + } + + protected virtual void OnItemActivate (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [ItemActivateEvent]); + if (eh != null) + eh (this, e); + } + + protected internal virtual void OnItemCheck (ItemCheckEventArgs ice) + { + ItemCheckEventHandler eh = (ItemCheckEventHandler)(Events [ItemCheckEvent]); + if (eh != null) + eh (this, ice); + } + + protected internal virtual void OnItemChecked (ItemCheckedEventArgs e) + { + ItemCheckedEventHandler eh = (ItemCheckedEventHandler)(Events [ItemCheckedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnItemDrag (ItemDragEventArgs e) + { + ItemDragEventHandler eh = (ItemDragEventHandler)(Events [ItemDragEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnItemMouseHover (ListViewItemMouseHoverEventArgs e) + { + ListViewItemMouseHoverEventHandler eh = (ListViewItemMouseHoverEventHandler)(Events [ItemMouseHoverEvent]); + if (eh != null) + eh (this, e); + } + + protected internal virtual void OnItemSelectionChanged (ListViewItemSelectionChangedEventArgs e) + { + ListViewItemSelectionChangedEventHandler eh = + (ListViewItemSelectionChangedEventHandler) Events [ItemSelectionChangedEvent]; + if (eh != null) + eh (this, e); + } + + protected override void OnMouseHover (EventArgs e) + { + base.OnMouseHover (e); + } + + protected override void OnParentChanged (EventArgs e) + { + base.OnParentChanged (e); + } + + protected virtual void OnSelectedIndexChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnSystemColorsChanged (EventArgs e) + { + base.OnSystemColorsChanged (e); + } + + protected internal virtual void OnCacheVirtualItems (CacheVirtualItemsEventArgs e) + { + CacheVirtualItemsEventHandler eh = (CacheVirtualItemsEventHandler)Events [CacheVirtualItemsEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnRetrieveVirtualItem (RetrieveVirtualItemEventArgs e) + { + RetrieveVirtualItemEventHandler eh = (RetrieveVirtualItemEventHandler)Events [RetrieveVirtualItemEvent]; + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnRightToLeftLayoutChanged (EventArgs e) + { + EventHandler eh = (EventHandler)Events[RightToLeftLayoutChangedEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnSearchForVirtualItem (SearchForVirtualItemEventArgs e) + { + SearchForVirtualItemEventHandler eh = (SearchForVirtualItemEventHandler) Events [SearchForVirtualItemEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnVirtualItemsSelectionRangeChanged (ListViewVirtualItemsSelectionRangeChangedEventArgs e) + { + ListViewVirtualItemsSelectionRangeChangedEventHandler eh = + (ListViewVirtualItemsSelectionRangeChangedEventHandler) Events [VirtualItemsSelectionRangeChangedEvent]; + if (eh != null) + eh (this, e); + } + + protected void RealizeProperties () + { + // FIXME: TODO + } + + protected void UpdateExtendedStyles () + { + // FIXME: TODO + } + + bool refocusing = false; + + protected override void WndProc (ref Message m) + { + switch ((Msg)m.Msg) { + case Msg.WM_KILLFOCUS: + Widget receiver = Widget.FromHandle (m.WParam); + if (receiver == item_control) { + has_focus = false; + refocusing = true; + return; + } + break; + case Msg.WM_SETFOCUS: + if (refocusing) { + has_focus = true; + refocusing = false; + return; + } + break; + default: + break; + } + base.WndProc (ref m); + } + #endregion // Protected Methods + + #region Public Instance Methods + public void ArrangeIcons () + { + ArrangeIcons (this.alignment); + } + + public void ArrangeIcons (ListViewAlignment value) + { + // Icons are arranged only if view is set to LargeIcon or SmallIcon + if (view == View.LargeIcon || view == View.SmallIcon) + Redraw (true); + } + + public void AutoResizeColumn (int columnIndex, ColumnHeaderAutoResizeStyle headerAutoResize) + { + if (columnIndex < 0 || columnIndex >= columns.Count) + throw new ArgumentOutOfRangeException ("columnIndex"); + + columns [columnIndex].AutoResize (headerAutoResize); + } + + public void AutoResizeColumns (ColumnHeaderAutoResizeStyle headerAutoResize) + { + BeginUpdate (); + foreach (ColumnHeader col in columns) + col.AutoResize (headerAutoResize); + EndUpdate (); + } + + public void BeginUpdate () + { + // flag to avoid painting + updating = true; + } + + public void Clear () + { + columns.Clear (); + items.Clear (); // Redraw (true) called here + } + + public void EndUpdate () + { + // flag to avoid painting + updating = false; + + // probably, now we need a redraw with recalculations + this.Redraw (true); + } + + public void EnsureVisible (int index) + { + if (index < 0 || index >= items.Count || scrollable == false || updating) + return; + + Rectangle view_rect = item_control.ClientRectangle; + // Avoid direct access to items in virtual mode, and use item bounds otherwise, since we could have reordered items + Rectangle bounds = virtual_mode ? new Rectangle (GetItemLocation (index), ItemSize) : items [index].Bounds; + + if (view == View.Details && header_style != ColumnHeaderStyle.None) { + view_rect.Y += header_control.Height; + view_rect.Height -= header_control.Height; + } + + if (view_rect.Contains (bounds)) + return; + + if (View != View.Details) { + if (bounds.Left < 0) + h_scroll.Value += bounds.Left; + // Don't shift right unless right-to-left layout is active. (Xamarin bug 22483) + else if (this.RightToLeftLayout && bounds.Right > view_rect.Right) + h_scroll.Value += (bounds.Right - view_rect.Right); + } + + if (bounds.Top < view_rect.Y) + v_scroll.Value += bounds.Top - view_rect.Y; + else if (bounds.Bottom > view_rect.Bottom) + v_scroll.Value += (bounds.Bottom - view_rect.Bottom); + } + + public ListViewItem FindItemWithText (string text) + { + if (items.Count == 0) + return null; + + return FindItemWithText (text, true, 0, true); + } + + public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex) + { + return FindItemWithText (text, includeSubItemsInSearch, startIndex, true, false); + } + + public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch) + { + return FindItemWithText (text, includeSubItemsInSearch, startIndex, isPrefixSearch, false); + } + + internal ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch, bool roundtrip) + { + if (startIndex < 0 || startIndex >= items.Count) + throw new ArgumentOutOfRangeException ("startIndex"); + + if (text == null) + throw new ArgumentNullException ("text"); + + if (virtual_mode) { + SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (true, + isPrefixSearch, includeSubItemsInSearch, text, Point.Empty, + SearchDirectionHint.Down, startIndex); + + OnSearchForVirtualItem (args); + int idx = args.Index; + if (idx >= 0 && idx < virtual_list_size) + return items [idx]; + + return null; + } + + int i = startIndex; + while (true) { + ListViewItem lvi = items [i]; + + if (isPrefixSearch) { // prefix search + if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (lvi.Text, text, CompareOptions.IgnoreCase)) + return lvi; + } else if (String.Compare (lvi.Text, text, true) == 0) // match + return lvi; + + if (i + 1 >= items.Count) { + if (!roundtrip) + break; + + i = 0; + } else + i++; + + if (i == startIndex) + break; + } + + // Subitems have a minor priority, so we have to do a second linear search + // Also, we don't need to to a roundtrip search for them by now + if (includeSubItemsInSearch) { + for (i = startIndex; i < items.Count; i++) { + ListViewItem lvi = items [i]; + foreach (ListViewItem.ListViewSubItem sub_item in lvi.SubItems) + if (isPrefixSearch) { + if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (sub_item.Text, + text, CompareOptions.IgnoreCase)) + return lvi; + } else if (String.Compare (sub_item.Text, text, true) == 0) + return lvi; + } + } + + return null; + } + + public ListViewItem FindNearestItem (SearchDirectionHint searchDirection, int x, int y) + { + return FindNearestItem (searchDirection, new Point (x, y)); + } + + public ListViewItem FindNearestItem (SearchDirectionHint dir, Point point) + { + if (dir < SearchDirectionHint.Left || dir > SearchDirectionHint.Down) + throw new ArgumentOutOfRangeException ("searchDirection"); + + if (view != View.LargeIcon && view != View.SmallIcon) + throw new InvalidOperationException (); + + if (virtual_mode) { + SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (false, + false, false, String.Empty, point, + dir, 0); + + OnSearchForVirtualItem (args); + int idx = args.Index; + if (idx >= 0 && idx < virtual_list_size) + return items [idx]; + + return null; + } + + ListViewItem item = null; + int min_dist = Int32.MaxValue; + + // + // It looks like .Net does a previous adjustment + // + switch (dir) { + case SearchDirectionHint.Up: + point.Y -= item_size.Height; + break; + case SearchDirectionHint.Down: + point.Y += item_size.Height; + break; + case SearchDirectionHint.Left: + point.X -= item_size.Width; + break; + case SearchDirectionHint.Right: + point.X += item_size.Width; + break; + } + + for (int i = 0; i < items.Count; i++) { + Point item_loc = GetItemLocation (i); + + if (dir == SearchDirectionHint.Up) { + if (point.Y < item_loc.Y) + continue; + } else if (dir == SearchDirectionHint.Down) { + if (point.Y > item_loc.Y) + continue; + } else if (dir == SearchDirectionHint.Left) { + if (point.X < item_loc.X) + continue; + } else if (dir == SearchDirectionHint.Right) { + if (point.X > item_loc.X) + continue; + } + + int x_dist = point.X - item_loc.X; + int y_dist = point.Y - item_loc.Y; + + int dist = x_dist * x_dist + y_dist * y_dist; + if (dist < min_dist) { + item = items [i]; + min_dist = dist; + } + } + + return item; + } + + public ListViewItem GetItemAt (int x, int y) + { + Size item_size = ItemSize; + for (int i = 0; i < items.Count; i++) { + Rectangle item_rect = items [i].Bounds; + if (item_rect.Contains (x, y)) + return items [i]; + } + + return null; + } + + public Rectangle GetItemRect (int index) + { + return GetItemRect (index, ItemBoundsPortion.Entire); + } + + public Rectangle GetItemRect (int index, ItemBoundsPortion portion) + { + if (index < 0 || index >= items.Count) + throw new IndexOutOfRangeException ("index"); + + return items [index].GetBounds (portion); + } + + public ListViewHitTestInfo HitTest (Point point) + { + return HitTest (point.X, point.Y); + } + + public ListViewHitTestInfo HitTest (int x, int y) + { + if (x < 0) + throw new ArgumentOutOfRangeException ("x"); + if (y < 0) + throw new ArgumentOutOfRangeException ("y"); + + ListViewItem item = GetItemAt (x, y); + if (item == null) + return new ListViewHitTestInfo (null, null, ListViewHitTestLocations.None); + + ListViewHitTestLocations locations = 0; + if (item.GetBounds (ItemBoundsPortion.Label).Contains (x, y)) + locations |= ListViewHitTestLocations.Label; + else if (item.GetBounds (ItemBoundsPortion.Icon).Contains (x, y)) + locations |= ListViewHitTestLocations.Image; + else if (item.CheckRectReal.Contains (x, y)) + locations |= ListViewHitTestLocations.StateImage; + + ListViewItem.ListViewSubItem subitem = null; + if (view == View.Details) + foreach (ListViewItem.ListViewSubItem si in item.SubItems) + if (si.Bounds.Contains (x, y)) { + subitem = si; + break; + } + + return new ListViewHitTestInfo (item, subitem, locations); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + public void RedrawItems (int startIndex, int endIndex, bool invalidateOnly) + { + if (startIndex < 0 || startIndex >= items.Count) + throw new ArgumentOutOfRangeException ("startIndex"); + if (endIndex < 0 || endIndex >= items.Count) + throw new ArgumentOutOfRangeException ("endIndex"); + if (startIndex > endIndex) + throw new ArgumentException ("startIndex"); + + if (updating) + return; + + for (int i = startIndex; i <= endIndex; i++) + items [i].Invalidate (); + + if (!invalidateOnly) + Update (); + } + + public void Sort () + { + if (virtual_mode) + throw new InvalidOperationException (); + + Sort (true); + } + + // we need this overload to reuse the logic for sorting, while allowing + // redrawing to be done by caller or have it done by this method when + // sorting is really performed + // + // ListViewItemCollection's Add and AddRange methods call this overload + // with redraw set to false, as they take care of redrawing themselves + // (they even want to redraw the listview if no sort is performed, as + // an item was added), while ListView.Sort () only wants to redraw if + // sorting was actually performed + private void Sort (bool redraw) + { + if (!IsHandleCreated || item_sorter == null) { + return; + } + + items.Sort (item_sorter); + if (redraw) + this.Redraw (true); + } + + public override string ToString () + { + int count = this.Items.Count; + + if (count == 0) + return string.Format ("ShiftUI.ListView, Items.Count: 0"); + else + return string.Format ("ShiftUI.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ()); + } + #endregion // Public Instance Methods + + + #region Subclasses + + internal class HeaderControl : Widget { + + ListView owner; + bool column_resize_active = false; + ColumnHeader resize_column; + ColumnHeader clicked_column; + ColumnHeader drag_column; + int drag_x; + int drag_to_index = -1; + ColumnHeader entered_column_header; + + public HeaderControl (ListView owner) + { + this.owner = owner; + this.SetStyle (Widgetstyles.DoubleBuffer, true); + MouseDown += new MouseEventHandler (HeaderMouseDown); + MouseMove += new MouseEventHandler (HeaderMouseMove); + MouseUp += new MouseEventHandler (HeaderMouseUp); + MouseLeave += new EventHandler (OnMouseLeave); + } + + internal ColumnHeader EnteredColumnHeader { + get { return entered_column_header; } + private set { + if (entered_column_header == value) + return; + if (ThemeEngine.Current.ListViewHasHotHeaderStyle) { + Region region_to_invalidate = new Region (); + region_to_invalidate.MakeEmpty (); + if (entered_column_header != null) + region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header)); + entered_column_header = value; + if (entered_column_header != null) + region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header)); + Invalidate (region_to_invalidate); + region_to_invalidate.Dispose (); + } else + entered_column_header = value; + } + } + + void OnMouseLeave (object sender, EventArgs e) + { + EnteredColumnHeader = null; + } + + private ColumnHeader ColumnAtX (int x) + { + Point pt = new Point (x, 0); + ColumnHeader result = null; + foreach (ColumnHeader col in owner.Columns) { + if (col.Rect.Contains (pt)) { + result = col; + break; + } + } + return result; + } + + private int GetReorderedIndex (ColumnHeader col) + { + if (owner.reordered_column_indices == null) + return col.Index; + else + for (int i = 0; i < owner.Columns.Count; i++) + if (owner.reordered_column_indices [i] == col.Index) + return i; + throw new Exception ("Column index missing from reordered array"); + } + + private void HeaderMouseDown (object sender, MouseEventArgs me) + { + if (resize_column != null) { + column_resize_active = true; + Capture = true; + return; + } + + clicked_column = ColumnAtX (me.X + owner.h_marker); + + if (clicked_column != null) { + Capture = true; + if (owner.AllowColumnReorder) { + drag_x = me.X; + drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone (); + drag_column.Rect = clicked_column.Rect; + drag_to_index = GetReorderedIndex (clicked_column); + } + clicked_column.Pressed = true; + Invalidate (clicked_column); + return; + } + } + + void Invalidate (ColumnHeader columnHeader) + { + Invalidate (GetColumnHeaderInvalidateArea (columnHeader)); + } + + Rectangle GetColumnHeaderInvalidateArea (ColumnHeader columnHeader) + { + Rectangle bounds = columnHeader.Rect; + bounds.X -= owner.h_marker; + return bounds; + } + + void StopResize () + { + column_resize_active = false; + resize_column = null; + Capture = false; + Cursor = Cursors.Default; + } + + private void HeaderMouseMove (object sender, MouseEventArgs me) + { + Point pt = new Point (me.X + owner.h_marker, me.Y); + + if (column_resize_active) { + int width = pt.X - resize_column.X; + if (width < 0) + width = 0; + + if (!owner.CanProceedWithResize (resize_column, width)){ + StopResize (); + return; + } + resize_column.Width = width; + return; + } + + resize_column = null; + + if (clicked_column != null) { + if (owner.AllowColumnReorder) { + Rectangle r; + + r = drag_column.Rect; + r.X = clicked_column.Rect.X + me.X - drag_x; + drag_column.Rect = r; + + int x = me.X + owner.h_marker; + ColumnHeader over = ColumnAtX (x); + if (over == null) + drag_to_index = owner.Columns.Count; + else if (x < over.X + over.Width / 2) + drag_to_index = GetReorderedIndex (over); + else + drag_to_index = GetReorderedIndex (over) + 1; + Invalidate (); + } else { + ColumnHeader over = ColumnAtX (me.X + owner.h_marker); + bool pressed = clicked_column.Pressed; + clicked_column.Pressed = over == clicked_column; + if (clicked_column.Pressed ^ pressed) + Invalidate (clicked_column); + } + return; + } + + for (int i = 0; i < owner.Columns.Count; i++) { + Rectangle zone = owner.Columns [i].Rect; + if (zone.Contains (pt)) + EnteredColumnHeader = owner.Columns [i]; + zone.X = zone.Right - 5; + zone.Width = 10; + if (zone.Contains (pt)) { + if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0) + i++; + resize_column = owner.Columns [i]; + break; + } + } + + if (resize_column == null) + Cursor = Cursors.Default; + else + Cursor = Cursors.VSplit; + } + + void HeaderMouseUp (object sender, MouseEventArgs me) + { + Capture = false; + + if (column_resize_active) { + int column_idx = resize_column.Index; + StopResize (); + owner.RaiseColumnWidthChanged (column_idx); + return; + } + + if (clicked_column != null && clicked_column.Pressed) { + clicked_column.Pressed = false; + Invalidate (clicked_column); + owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index)); + } + + if (drag_column != null && owner.AllowColumnReorder) { + drag_column = null; + if (drag_to_index > GetReorderedIndex (clicked_column)) + drag_to_index--; + if (owner.GetReorderedColumn (drag_to_index) != clicked_column) + owner.ReorderColumn (clicked_column, drag_to_index, true); + drag_to_index = -1; + Invalidate (); + } + + clicked_column = null; + } + + internal override void OnPaintInternal (PaintEventArgs pe) + { + if (owner.updating) + return; + + Theme theme = ThemeEngine.Current; + theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner); + + if (drag_column == null) + return; + + int target_x; + if (drag_to_index == owner.Columns.Count) + target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker; + else + target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker; + theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x); + } + + protected override void WndProc (ref Message m) + { + switch ((Msg)m.Msg) { + case Msg.WM_SETFOCUS: + owner.Focus (); + break; + default: + base.WndProc (ref m); + break; + } + } + } + + private class ItemComparer : IComparer { + readonly SortOrder sort_order; + + public ItemComparer (SortOrder sortOrder) + { + sort_order = sortOrder; + } + + public int Compare (object x, object y) + { + ListViewItem item_x = x as ListViewItem; + ListViewItem item_y = y as ListViewItem; + if (sort_order == SortOrder.Ascending) + return String.Compare (item_x.Text, item_y.Text); + else + return String.Compare (item_y.Text, item_x.Text); + } + } + + [ListBindable (false)] + public class CheckedIndexCollection : IList, ICollection, IEnumerable + { + private readonly ListView owner; + + #region Public Constructor + public CheckedIndexCollection (ListView owner) + { + this.owner = owner; + } + #endregion // Public Constructor + + #region Public Properties + [Browsable (false)] + public int Count { + get { return owner.CheckedItems.Count; } + } + + public bool IsReadOnly { + get { return true; } + } + + public int this [int index] { + get { + int [] indices = GetIndices (); + if (index < 0 || index >= indices.Length) + throw new ArgumentOutOfRangeException ("index"); + return indices [index]; + } + } + + bool ICollection.IsSynchronized { + get { return false; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + bool IList.IsFixedSize { + get { return true; } + } + + object IList.this [int index] { + get { return this [index]; } + set { throw new NotSupportedException ("SetItem operation is not supported."); } + } + #endregion // Public Properties + + #region Public Methods + public bool Contains (int checkedIndex) + { + int [] indices = GetIndices (); + for (int i = 0; i < indices.Length; i++) { + if (indices [i] == checkedIndex) + return true; + } + return false; + } + + public IEnumerator GetEnumerator () + { + int [] indices = GetIndices (); + return indices.GetEnumerator (); + } + + void ICollection.CopyTo (Array dest, int index) + { + int [] indices = GetIndices (); + Array.Copy (indices, 0, dest, index, indices.Length); + } + + int IList.Add (object value) + { + throw new NotSupportedException ("Add operation is not supported."); + } + + void IList.Clear () + { + throw new NotSupportedException ("Clear operation is not supported."); + } + + bool IList.Contains (object checkedIndex) + { + if (!(checkedIndex is int)) + return false; + return Contains ((int) checkedIndex); + } + + int IList.IndexOf (object checkedIndex) + { + if (!(checkedIndex is int)) + return -1; + return IndexOf ((int) checkedIndex); + } + + void IList.Insert (int index, object value) + { + throw new NotSupportedException ("Insert operation is not supported."); + } + + void IList.Remove (object value) + { + throw new NotSupportedException ("Remove operation is not supported."); + } + + void IList.RemoveAt (int index) + { + throw new NotSupportedException ("RemoveAt operation is not supported."); + } + + public int IndexOf (int checkedIndex) + { + int [] indices = GetIndices (); + for (int i = 0; i < indices.Length; i++) { + if (indices [i] == checkedIndex) + return i; + } + return -1; + } + #endregion // Public Methods + + private int [] GetIndices () + { + ArrayList checked_items = owner.CheckedItems.List; + int [] indices = new int [checked_items.Count]; + for (int i = 0; i < checked_items.Count; i++) { + ListViewItem item = (ListViewItem) checked_items [i]; + indices [i] = item.Index; + } + return indices; + } + } // CheckedIndexCollection + + [ListBindable (false)] + public class CheckedListViewItemCollection : IList, ICollection, IEnumerable + { + private readonly ListView owner; + private ArrayList list; + + #region Public Constructor + public CheckedListViewItemCollection (ListView owner) + { + this.owner = owner; + this.owner.Items.Changed += new CollectionChangedHandler ( + ItemsCollection_Changed); + } + #endregion // Public Constructor + + #region Public Properties + [Browsable (false)] + public int Count { + get { + if (!owner.CheckBoxes) + return 0; + return List.Count; + } + } + + public bool IsReadOnly { + get { return true; } + } + + public ListViewItem this [int index] { + get { + if (owner.VirtualMode) + throw new InvalidOperationException (); + ArrayList checked_items = List; + if (index < 0 || index >= checked_items.Count) + throw new ArgumentOutOfRangeException ("index"); + return (ListViewItem) checked_items [index]; + } + } + + public virtual ListViewItem this [string key] { + get { + int idx = IndexOfKey (key); + return idx == -1 ? null : (ListViewItem) List [idx]; + } + } + + bool ICollection.IsSynchronized { + get { return false; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + bool IList.IsFixedSize { + get { return true; } + } + + object IList.this [int index] { + get { return this [index]; } + set { throw new NotSupportedException ("SetItem operation is not supported."); } + } + #endregion // Public Properties + + #region Public Methods + public bool Contains (ListViewItem item) + { + if (!owner.CheckBoxes) + return false; + return List.Contains (item); + } + + public virtual bool ContainsKey (string key) + { + return IndexOfKey (key) != -1; + } + + public void CopyTo (Array dest, int index) + { + if (owner.VirtualMode) + throw new InvalidOperationException (); + if (!owner.CheckBoxes) + return; + List.CopyTo (dest, index); + } + + public IEnumerator GetEnumerator () + { + if (owner.VirtualMode) + throw new InvalidOperationException (); + if (!owner.CheckBoxes) + return (new ListViewItem [0]).GetEnumerator (); + return List.GetEnumerator (); + } + + int IList.Add (object value) + { + throw new NotSupportedException ("Add operation is not supported."); + } + + void IList.Clear () + { + throw new NotSupportedException ("Clear operation is not supported."); + } + + bool IList.Contains (object item) + { + if (!(item is ListViewItem)) + return false; + return Contains ((ListViewItem) item); + } + + int IList.IndexOf (object item) + { + if (!(item is ListViewItem)) + return -1; + return IndexOf ((ListViewItem) item); + } + + void IList.Insert (int index, object value) + { + throw new NotSupportedException ("Insert operation is not supported."); + } + + void IList.Remove (object value) + { + throw new NotSupportedException ("Remove operation is not supported."); + } + + void IList.RemoveAt (int index) + { + throw new NotSupportedException ("RemoveAt operation is not supported."); + } + + public int IndexOf (ListViewItem item) + { + if (owner.VirtualMode) + throw new InvalidOperationException (); + if (!owner.CheckBoxes) + return -1; + return List.IndexOf (item); + } + + public virtual int IndexOfKey (string key) + { + if (owner.VirtualMode) + throw new InvalidOperationException (); + if (key == null || key.Length == 0) + return -1; + + ArrayList checked_items = List; + for (int i = 0; i < checked_items.Count; i++) { + ListViewItem item = (ListViewItem) checked_items [i]; + if (String.Compare (key, item.Name, true) == 0) + return i; + } + + return -1; + } + #endregion // Public Methods + + internal ArrayList List { + get { + if (list == null) { + list = new ArrayList (); + foreach (ListViewItem item in owner.Items) { + if (item.Checked) + list.Add (item); + } + } + return list; + } + } + + internal void Reset () + { + // force re-population of list + list = null; + } + + private void ItemsCollection_Changed () + { + Reset (); + } + } // CheckedListViewItemCollection + + [ListBindable (false)] + public class ColumnHeaderCollection : IList, ICollection, IEnumerable + { + internal ArrayList list; + private ListView owner; + + #region UIA Framework Events + //NOTE: + // We are using Reflection to add/remove internal events. + // Class ListViewProvider uses the events when View is Details. + // + //Event used to generate UIA StructureChangedEvent + static object UIACollectionChangedEvent = new object (); + + internal event CollectionChangeEventHandler UIACollectionChanged { + add { + if (owner != null) + owner.Events.AddHandler (UIACollectionChangedEvent, value); + } + remove { + if (owner != null) + owner.Events.RemoveHandler (UIACollectionChangedEvent, value); + } + } + + internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args) + { + if (owner == null) + return; + + CollectionChangeEventHandler eh + = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent]; + if (eh != null) + eh (owner, args); + } + + #endregion UIA Framework Events + + #region Public Constructor + public ColumnHeaderCollection (ListView owner) + { + list = new ArrayList (); + this.owner = owner; + } + #endregion // Public Constructor + + #region Public Properties + [Browsable (false)] + public int Count { + get { return list.Count; } + } + + public bool IsReadOnly { + get { return false; } + } + + public virtual ColumnHeader this [int index] { + get { + if (index < 0 || index >= list.Count) + throw new ArgumentOutOfRangeException ("index"); + return (ColumnHeader) list [index]; + } + } + + public virtual ColumnHeader this [string key] { + get { + int idx = IndexOfKey (key); + if (idx == -1) + return null; + + return (ColumnHeader) list [idx]; + } + } + + bool ICollection.IsSynchronized { + get { return true; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + bool IList.IsFixedSize { + get { return list.IsFixedSize; } + } + + object IList.this [int index] { + get { return this [index]; } + set { throw new NotSupportedException ("SetItem operation is not supported."); } + } + #endregion // Public Properties + + #region Public Methods + public virtual int Add (ColumnHeader value) + { + int idx = list.Add (value); + owner.AddColumn (value, idx, true); + + //UIA Framework event: Item Added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value)); + + return idx; + } + + public virtual ColumnHeader Add (string text, int width, HorizontalAlignment textAlign) + { + string str = text; + ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width); + this.Add (colHeader); + return colHeader; + } + + public virtual ColumnHeader Add (string text) + { + return Add (String.Empty, text); + } + + public virtual ColumnHeader Add (string text, int width) + { + return Add (String.Empty, text, width); + } + + public virtual ColumnHeader Add (string key, string text) + { + ColumnHeader colHeader = new ColumnHeader (); + colHeader.Name = key; + colHeader.Text = text; + Add (colHeader); + return colHeader; + } + + public virtual ColumnHeader Add (string key, string text, int width) + { + return Add (key, text, width, HorizontalAlignment.Left, -1); + } + + public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, int imageIndex) + { + ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign); + colHeader.ImageIndex = imageIndex; + Add (colHeader); + return colHeader; + } + + public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, string imageKey) + { + ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign); + colHeader.ImageKey = imageKey; + Add (colHeader); + return colHeader; + } + + public virtual void AddRange (ColumnHeader [] values) + { + foreach (ColumnHeader colHeader in values) { + int idx = list.Add (colHeader); + owner.AddColumn (colHeader, idx, false); + } + + owner.Redraw (true); + } + + public virtual void Clear () + { + foreach (ColumnHeader col in list) + col.SetListView (null); + list.Clear (); + owner.ReorderColumns (new int [0], true); + + //UIA Framework event: Items cleared + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null)); + + } + + public bool Contains (ColumnHeader value) + { + return list.Contains (value); + } + + public virtual bool ContainsKey (string key) + { + return IndexOfKey (key) != -1; + } + + public IEnumerator GetEnumerator () + { + return list.GetEnumerator (); + } + + void ICollection.CopyTo (Array dest, int index) + { + list.CopyTo (dest, index); + } + + int IList.Add (object value) + { + if (! (value is ColumnHeader)) { + throw new ArgumentException ("Not of type ColumnHeader", "value"); + } + + return this.Add ((ColumnHeader) value); + } + + bool IList.Contains (object value) + { + if (! (value is ColumnHeader)) { + throw new ArgumentException ("Not of type ColumnHeader", "value"); + } + + return this.Contains ((ColumnHeader) value); + } + + int IList.IndexOf (object value) + { + if (! (value is ColumnHeader)) { + throw new ArgumentException ("Not of type ColumnHeader", "value"); + } + + return this.IndexOf ((ColumnHeader) value); + } + + void IList.Insert (int index, object value) + { + if (! (value is ColumnHeader)) { + throw new ArgumentException ("Not of type ColumnHeader", "value"); + } + + this.Insert (index, (ColumnHeader) value); + } + + void IList.Remove (object value) + { + if (! (value is ColumnHeader)) { + throw new ArgumentException ("Not of type ColumnHeader", "value"); + } + + this.Remove ((ColumnHeader) value); + } + + public int IndexOf (ColumnHeader value) + { + return list.IndexOf (value); + } + + public virtual int IndexOfKey (string key) + { + if (key == null || key.Length == 0) + return -1; + + for (int i = 0; i < list.Count; i++) { + ColumnHeader col = (ColumnHeader) list [i]; + if (String.Compare (key, col.Name, true) == 0) + return i; + } + + return -1; + } + + public void Insert (int index, ColumnHeader value) + { + // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property + // but it's really only greater. + if (index < 0 || index > list.Count) + throw new ArgumentOutOfRangeException ("index"); + + list.Insert (index, value); + owner.AddColumn (value, index, true); + + //UIA Framework event: Item added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value)); + } + + public void Insert (int index, string text) + { + Insert (index, String.Empty, text); + } + + public void Insert (int index, string text, int width) + { + Insert (index, String.Empty, text, width); + } + + public void Insert (int index, string key, string text) + { + ColumnHeader colHeader = new ColumnHeader (); + colHeader.Name = key; + colHeader.Text = text; + Insert (index, colHeader); + } + + public void Insert (int index, string key, string text, int width) + { + ColumnHeader colHeader = new ColumnHeader (key, text, width, HorizontalAlignment.Left); + Insert (index, colHeader); + } + + public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, int imageIndex) + { + ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign); + colHeader.ImageIndex = imageIndex; + Insert (index, colHeader); + } + + public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, string imageKey) + { + ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign); + colHeader.ImageKey = imageKey; + Insert (index, colHeader); + } + + public void Insert (int index, string text, int width, HorizontalAlignment textAlign) + { + string str = text; + ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width); + this.Insert (index, colHeader); + } + + public virtual void Remove (ColumnHeader column) + { + if (!Contains (column)) + return; + + list.Remove (column); + column.SetListView (null); + + int rem_display_index = column.InternalDisplayIndex; + int [] display_indices = new int [list.Count]; + for (int i = 0; i < display_indices.Length; i++) { + ColumnHeader col = (ColumnHeader) list [i]; + int display_index = col.InternalDisplayIndex; + if (display_index < rem_display_index) { + display_indices [i] = display_index; + } else { + display_indices [i] = (display_index - 1); + } + } + + column.InternalDisplayIndex = -1; + owner.ReorderColumns (display_indices, true); + + //UIA Framework event: Item Removed + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, column)); + } + + public virtual void RemoveByKey (string key) + { + int idx = IndexOfKey (key); + if (idx != -1) + RemoveAt (idx); + } + + public virtual void RemoveAt (int index) + { + if (index < 0 || index >= list.Count) + throw new ArgumentOutOfRangeException ("index"); + + ColumnHeader col = (ColumnHeader) list [index]; + Remove (col); + } + #endregion // Public Methods + + + } // ColumnHeaderCollection + + [ListBindable (false)] + public class ListViewItemCollection : IList, ICollection, IEnumerable + { + private readonly ArrayList list; + private ListView owner; + private ListViewGroup group; + + #region UIA Framework Events + //NOTE: + // We are using Reflection to add/remove internal events. + // Class ListViewProvider uses the events. + // + //Event used to generate UIA StructureChangedEvent + static object UIACollectionChangedEvent = new object (); + + internal event CollectionChangeEventHandler UIACollectionChanged { + add { + if (owner != null) + owner.Events.AddHandler (UIACollectionChangedEvent, value); + } + remove { + if (owner != null) + owner.Events.RemoveHandler (UIACollectionChangedEvent, value); + } + } + + internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args) + { + if (owner == null) + return; + + CollectionChangeEventHandler eh + = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent]; + if (eh != null) + eh (owner, args); + } + + #endregion UIA Framework Events + + // The collection can belong to a ListView (main) or to a ListViewGroup (sub-collection) + // In the later case ListViewItem.ListView never gets modified + private bool is_main_collection = true; + + #region Public Constructor + public ListViewItemCollection (ListView owner) + { + list = new ArrayList (0); + this.owner = owner; + } + #endregion // Public Constructor + + internal ListViewItemCollection (ListView owner, ListViewGroup group) : this (owner) + { + this.group = group; + is_main_collection = false; + } + + #region Public Properties + [Browsable (false)] + public int Count { + get { + if (owner != null && owner.VirtualMode) + return owner.VirtualListSize; + + return list.Count; + } + } + + public bool IsReadOnly { + get { return false; } + } + + public virtual ListViewItem this [int index] { + get { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("index"); + + if (owner != null && owner.VirtualMode) + return RetrieveVirtualItemFromOwner (index); + return (ListViewItem) list [index]; + } + + set { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("index"); + + if (owner != null && owner.VirtualMode) + throw new InvalidOperationException (); + + if (list.Contains (value)) + throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value"); + + if (value.ListView != null && value.ListView != owner) + throw new ArgumentException ("Cannot add or insert the item '" + value.Text + "' in more than one place. You must first remove it from its current location or clone it.", "value"); + + if (is_main_collection) + value.Owner = owner; + else { + if (value.Group != null) + value.Group.Items.Remove (value); + + value.SetGroup (group); + } + + //UIA Framework event: Item Replaced + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, list [index])); + + list [index] = value; + + CollectionChanged (true); + + //UIA Framework event: Item Replaced + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value)); + + } + } + + public virtual ListViewItem this [string key] { + get { + int idx = IndexOfKey (key); + if (idx == -1) + return null; + + return this [idx]; + } + } + + bool ICollection.IsSynchronized { + get { return true; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + bool IList.IsFixedSize { + get { return list.IsFixedSize; } + } + + object IList.this [int index] { + get { return this [index]; } + set { + //UIA Framework event: Item Replaced + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, this [index])); + + if (value is ListViewItem) + this [index] = (ListViewItem) value; + else + this [index] = new ListViewItem (value.ToString ()); + + OnChange (); + //UIA Framework event: Item Replaced + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value)); + } + } + #endregion // Public Properties + + #region Public Methods + public virtual ListViewItem Add (ListViewItem value) + { + if (owner != null && owner.VirtualMode) + throw new InvalidOperationException (); + + AddItem (value); + + // Item is ignored until it has been added to the ListView + if (is_main_collection || value.ListView != null) + CollectionChanged (true); + + //UIA Framework event: Item Added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value)); + + return value; + } + + public virtual ListViewItem Add (string text) + { + ListViewItem item = new ListViewItem (text); + return this.Add (item); + } + + public virtual ListViewItem Add (string text, int imageIndex) + { + ListViewItem item = new ListViewItem (text, imageIndex); + return this.Add (item); + } + + public virtual ListViewItem Add (string text, string imageKey) + { + ListViewItem item = new ListViewItem (text, imageKey); + return this.Add (item); + } + + public virtual ListViewItem Add (string key, string text, int imageIndex) + { + ListViewItem item = new ListViewItem (text, imageIndex); + item.Name = key; + return this.Add (item); + } + + public virtual ListViewItem Add (string key, string text, string imageKey) + { + ListViewItem item = new ListViewItem (text, imageKey); + item.Name = key; + return this.Add (item); + } + + public void AddRange (ListViewItem [] items) + { + if (items == null) + throw new ArgumentNullException ("Argument cannot be null!", "items"); + if (owner != null && owner.VirtualMode) + throw new InvalidOperationException (); + + owner.BeginUpdate (); + + foreach (ListViewItem item in items) { + AddItem (item); + + //UIA Framework event: Item Added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item)); + } + + owner.EndUpdate (); + + CollectionChanged (true); + } + + public void AddRange (ListViewItemCollection items) + { + if (items == null) + throw new ArgumentNullException ("Argument cannot be null!", "items"); + + ListViewItem[] itemArray = new ListViewItem[items.Count]; + items.CopyTo (itemArray,0); + this.AddRange (itemArray); + } + + public virtual void Clear () + { + if (owner != null && owner.VirtualMode) + throw new InvalidOperationException (); + if (is_main_collection && owner != null) { + owner.SetFocusedItem (-1); + owner.h_scroll.Value = owner.v_scroll.Value = 0; + + // first remove any item in the groups that *are* part of this LV too + foreach (ListViewGroup group in owner.groups) + group.Items.ClearItemsWithSameListView (); + + foreach (ListViewItem item in list) { + owner.item_control.CancelEdit (item); + item.Owner = null; + } + } + else + foreach (ListViewItem item in list) + item.SetGroup (null); + + list.Clear (); + CollectionChanged (false); + + //UIA Framework event: Items Removed + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null)); + + } + + // This method is intended to be used from ListViewGroup.Items, not from ListView.Items, + // added for performance reasons (avoid calling manually Remove for every item on ListViewGroup.Items) + void ClearItemsWithSameListView () + { + if (is_main_collection) + return; + + int counter = list.Count - 1; + while (counter >= 0) { + ListViewItem item = list [counter] as ListViewItem; + + // remove only if the items in group have being added to the ListView too + if (item.ListView == group.ListView) { + list.RemoveAt (counter); + item.SetGroup (null); + } + + counter--; + } + } + + public bool Contains (ListViewItem item) + { + return IndexOf (item) != -1; + } + + public virtual bool ContainsKey (string key) + { + return IndexOfKey (key) != -1; + } + + public void CopyTo (Array dest, int index) + { + list.CopyTo (dest, index); + } + + public ListViewItem [] Find (string key, bool searchAllSubItems) + { + if (key == null) + return new ListViewItem [0]; + + List temp_list = new List (); + + for (int i = 0; i < list.Count; i++) { + ListViewItem lvi = (ListViewItem) list [i]; + if (String.Compare (key, lvi.Name, true) == 0) + temp_list.Add (lvi); + } + + ListViewItem [] retval = new ListViewItem [temp_list.Count]; + temp_list.CopyTo (retval); + + return retval; + } + + public IEnumerator GetEnumerator () + { + if (owner != null && owner.VirtualMode) + throw new InvalidOperationException (); + + // This enumerator makes a copy of the collection so + // it can be deleted from in a foreach + return new Widget.WidgetCollection.WidgetCollectionEnumerator (list); + } + + int IList.Add (object item) + { + int result; + ListViewItem li; + + if (owner != null && owner.VirtualMode) + throw new InvalidOperationException (); + + if (item is ListViewItem) { + li = (ListViewItem) item; + if (list.Contains (li)) + throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item"); + + if (li.ListView != null && li.ListView != owner) + throw new ArgumentException ("Cannot add or insert the item '" + li.Text + "' in more than one place. You must first remove it from its current location or clone it.", "item"); + } + else + li = new ListViewItem (item.ToString ()); + + li.Owner = owner; + + + result = list.Add (li); + CollectionChanged (true); + + //UIA Framework event: Item Added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, li)); + + return result; + } + + bool IList.Contains (object item) + { + return Contains ((ListViewItem) item); + } + + int IList.IndexOf (object item) + { + return IndexOf ((ListViewItem) item); + } + + void IList.Insert (int index, object item) + { + if (item is ListViewItem) + this.Insert (index, (ListViewItem) item); + else + this.Insert (index, item.ToString ()); + + //UIA Framework event: Item Added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, this [index])); + } + + void IList.Remove (object item) + { + Remove ((ListViewItem) item); + } + + public int IndexOf (ListViewItem item) + { + if (owner != null && owner.VirtualMode) { + for (int i = 0; i < Count; i++) + if (RetrieveVirtualItemFromOwner (i) == item) + return i; + + return -1; + } + + return list.IndexOf (item); + } + + public virtual int IndexOfKey (string key) + { + if (key == null || key.Length == 0) + return -1; + + for (int i = 0; i < Count; i++) { + ListViewItem lvi = this [i]; + if (String.Compare (key, lvi.Name, true) == 0) + return i; + } + + return -1; + } + + public ListViewItem Insert (int index, ListViewItem item) + { + if (index < 0 || index > list.Count) + throw new ArgumentOutOfRangeException ("index"); + + if (owner != null && owner.VirtualMode) + throw new InvalidOperationException (); + + if (list.Contains (item)) + throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item"); + + if (item.ListView != null && item.ListView != owner) + throw new ArgumentException ("Cannot add or insert the item '" + item.Text + "' in more than one place. You must first remove it from its current location or clone it.", "item"); + + if (is_main_collection) + item.Owner = owner; + else { + if (item.Group != null) + item.Group.Items.Remove (item); + + item.SetGroup (group); + } + + list.Insert (index, item); + + if (is_main_collection || item.ListView != null) + CollectionChanged (true); + + // force an update of the selected info if the new item is selected. + if (item.Selected) + item.SetSelectedCore (true); + //UIA Framework event: Item Added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item)); + + return item; + } + + public ListViewItem Insert (int index, string text) + { + return this.Insert (index, new ListViewItem (text)); + } + + public ListViewItem Insert (int index, string text, int imageIndex) + { + return this.Insert (index, new ListViewItem (text, imageIndex)); + } + + public ListViewItem Insert (int index, string text, string imageKey) + { + ListViewItem lvi = new ListViewItem (text, imageKey); + return Insert (index, lvi); + } + + public virtual ListViewItem Insert (int index, string key, string text, int imageIndex) + { + ListViewItem lvi = new ListViewItem (text, imageIndex); + lvi.Name = key; + return Insert (index, lvi); + } + + public virtual ListViewItem Insert (int index, string key, string text, string imageKey) + { + ListViewItem lvi = new ListViewItem (text, imageKey); + lvi.Name = key; + return Insert (index, lvi); + } + + public virtual void Remove (ListViewItem item) + { + if (owner != null && owner.VirtualMode) + throw new InvalidOperationException (); + + int idx = list.IndexOf (item); + if (idx != -1) + RemoveAt (idx); + } + + public virtual void RemoveAt (int index) + { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("index"); + + if (owner != null && owner.VirtualMode) + throw new InvalidOperationException (); + + ListViewItem item = (ListViewItem) list [index]; + + bool selection_changed = false; + if (is_main_collection && owner != null) { + + int display_index = item.DisplayIndex; + if (item.Focused && display_index + 1 == Count) // Last item + owner.SetFocusedItem (display_index == 0 ? -1 : display_index - 1); + + selection_changed = owner.SelectedIndices.Contains (index); + owner.item_control.CancelEdit (item); + } + + list.RemoveAt (index); + + if (is_main_collection) { + item.Owner = null; + if (item.Group != null) + item.Group.Items.Remove (item); + } else + item.SetGroup (null); + + CollectionChanged (false); + if (selection_changed && owner != null) + owner.OnSelectedIndexChanged (EventArgs.Empty); + + + //UIA Framework event: Item Removed + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, item)); + } + + public virtual void RemoveByKey (string key) + { + int idx = IndexOfKey (key); + if (idx != -1) + RemoveAt (idx); + } + + #endregion // Public Methods + + internal ListView Owner { + get { + return owner; + } + set { + owner = value; + } + } + + internal ListViewGroup Group { + get { + return group; + } + set { + group = value; + } + } + + void AddItem (ListViewItem value) + { + if (list.Contains (value)) + throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value"); + + if (value.ListView != null && value.ListView != owner) + throw new ArgumentException ("Cannot add or insert the item '" + value.Text + "' in more than one place. You must first remove it from its current location or clone it.", "value"); + if (is_main_collection) + value.Owner = owner; + else { + if (value.Group != null) + value.Group.Items.Remove (value); + + value.SetGroup (group); + } + + list.Add (value); + + // force an update of the selected info if the new item is selected. + if (value.Selected) + value.SetSelectedCore (true); + } + + void CollectionChanged (bool sort) + { + if (owner != null) { + if (sort) + owner.Sort (false); + + OnChange (); + owner.Redraw (true); + } + } + + ListViewItem RetrieveVirtualItemFromOwner (int displayIndex) + { + RetrieveVirtualItemEventArgs args = new RetrieveVirtualItemEventArgs (displayIndex); + + owner.OnRetrieveVirtualItem (args); + ListViewItem retval = args.Item; + retval.Owner = owner; + retval.DisplayIndex = displayIndex; + retval.Layout (); + + return retval; + } + + internal event CollectionChangedHandler Changed; + + internal void Sort (IComparer comparer) + { + list.Sort (comparer); + OnChange (); + } + + internal void OnChange () + { + if (Changed != null) + Changed (); + } + } // ListViewItemCollection + + + // In normal mode, the selection information resides in the Items, + // making SelectedIndexCollection.List read-only + // + // In virtual mode, SelectedIndexCollection directly saves the selection + // information, instead of getting it from Items, making List read-and-write + [ListBindable (false)] + public class SelectedIndexCollection : IList, ICollection, IEnumerable + { + private readonly ListView owner; + private ArrayList list; + + #region Public Constructor + public SelectedIndexCollection (ListView owner) + { + this.owner = owner; + owner.Items.Changed += new CollectionChangedHandler (ItemsCollection_Changed); + } + #endregion // Public Constructor + + #region Public Properties + [Browsable (false)] + public int Count { + get { + if (!owner.is_selection_available) + return 0; + + return List.Count; + } + } + + public bool IsReadOnly { + get { + return false; + } + } + + public int this [int index] { + get { + if (!owner.is_selection_available || index < 0 || index >= List.Count) + throw new ArgumentOutOfRangeException ("index"); + + return (int) List [index]; + } + } + + bool ICollection.IsSynchronized { + get { return false; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + bool IList.IsFixedSize { + get { + return false; + } + } + + object IList.this [int index] { + get { return this [index]; } + set { throw new NotSupportedException ("SetItem operation is not supported."); } + } + #endregion // Public Properties + + #region Public Methods + public int Add (int itemIndex) + { + if (itemIndex < 0 || itemIndex >= owner.Items.Count) + throw new ArgumentOutOfRangeException ("index"); + + if (owner.virtual_mode && !owner.is_selection_available) + return -1; + + owner.Items [itemIndex].Selected = true; + + if (!owner.is_selection_available) + return 0; + + return List.Count; + } + + public void Clear () + { + if (!owner.is_selection_available) + return; + + int [] indexes = (int []) List.ToArray (typeof (int)); + foreach (int index in indexes) + owner.Items [index].Selected = false; + } + + public bool Contains (int selectedIndex) + { + return IndexOf (selectedIndex) != -1; + } + + public void CopyTo (Array dest, int index) + { + List.CopyTo (dest, index); + } + + public IEnumerator GetEnumerator () + { + return List.GetEnumerator (); + } + + int IList.Add (object value) + { + throw new NotSupportedException ("Add operation is not supported."); + } + + void IList.Clear () + { + Clear (); + } + + bool IList.Contains (object selectedIndex) + { + if (!(selectedIndex is int)) + return false; + return Contains ((int) selectedIndex); + } + + int IList.IndexOf (object selectedIndex) + { + if (!(selectedIndex is int)) + return -1; + return IndexOf ((int) selectedIndex); + } + + void IList.Insert (int index, object value) + { + throw new NotSupportedException ("Insert operation is not supported."); + } + + void IList.Remove (object value) + { + throw new NotSupportedException ("Remove operation is not supported."); + } + + void IList.RemoveAt (int index) + { + throw new NotSupportedException ("RemoveAt operation is not supported."); + } + + public int IndexOf (int selectedIndex) + { + if (!owner.is_selection_available) + return -1; + + return List.IndexOf (selectedIndex); + } + + public void Remove (int itemIndex) + { + if (itemIndex < 0 || itemIndex >= owner.Items.Count) + throw new ArgumentOutOfRangeException ("itemIndex"); + + owner.Items [itemIndex].Selected = false; + } + #endregion // Public Methods + + internal ArrayList List { + get { + if (list == null) { + list = new ArrayList (); + if (!owner.VirtualMode) + for (int i = 0; i < owner.Items.Count; i++) { + if (owner.Items [i].Selected) + list.Add (i); + } + } + return list; + } + } + + internal void Reset () + { + // force re-population of list + list = null; + } + + private void ItemsCollection_Changed () + { + Reset (); + } + + internal void RemoveIndex (int index) + { + int idx = List.BinarySearch (index); + if (idx != -1) + List.RemoveAt (idx); + } + + // actually store index in the collection + // also, keep the collection sorted, as .Net does + internal void InsertIndex (int index) + { + int iMin = 0; + int iMax = List.Count - 1; + while (iMin <= iMax) { + int iMid = (iMin + iMax) / 2; + int current_index = (int) List [iMid]; + + if (current_index == index) + return; // Already added + if (current_index > index) + iMax = iMid - 1; + else + iMin = iMid + 1; + } + + List.Insert (iMin, index); + } + + } // SelectedIndexCollection + + [ListBindable (false)] + public class SelectedListViewItemCollection : IList, ICollection, IEnumerable + { + private readonly ListView owner; + + #region Public Constructor + public SelectedListViewItemCollection (ListView owner) + { + this.owner = owner; + } + #endregion // Public Constructor + + #region Public Properties + [Browsable (false)] + public int Count { + get { + return owner.SelectedIndices.Count; + } + } + + public bool IsReadOnly { + get { return true; } + } + + public ListViewItem this [int index] { + get { + if (!owner.is_selection_available || index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("index"); + + int item_index = owner.SelectedIndices [index]; + return owner.Items [item_index]; + } + } + + public virtual ListViewItem this [string key] { + get { + int idx = IndexOfKey (key); + if (idx == -1) + return null; + + return this [idx]; + } + } + + bool ICollection.IsSynchronized { + get { return false; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + bool IList.IsFixedSize { + get { return true; } + } + + object IList.this [int index] { + get { return this [index]; } + set { throw new NotSupportedException ("SetItem operation is not supported."); } + } + #endregion // Public Properties + + #region Public Methods + public void Clear () + { + owner.SelectedIndices.Clear (); + } + + public bool Contains (ListViewItem item) + { + return IndexOf (item) != -1; + } + + public virtual bool ContainsKey (string key) + { + return IndexOfKey (key) != -1; + } + + public void CopyTo (Array dest, int index) + { + if (!owner.is_selection_available) + return; + if (index > Count) // Throws ArgumentException instead of IOOR exception + throw new ArgumentException ("index"); + + for (int i = 0; i < Count; i++) + dest.SetValue (this [i], index++); + } + + public IEnumerator GetEnumerator () + { + if (!owner.is_selection_available) + return (new ListViewItem [0]).GetEnumerator (); + + ListViewItem [] items = new ListViewItem [Count]; + for (int i = 0; i < Count; i++) + items [i] = this [i]; + + return items.GetEnumerator (); + } + + int IList.Add (object value) + { + throw new NotSupportedException ("Add operation is not supported."); + } + + bool IList.Contains (object item) + { + if (!(item is ListViewItem)) + return false; + return Contains ((ListViewItem) item); + } + + int IList.IndexOf (object item) + { + if (!(item is ListViewItem)) + return -1; + return IndexOf ((ListViewItem) item); + } + + void IList.Insert (int index, object value) + { + throw new NotSupportedException ("Insert operation is not supported."); + } + + void IList.Remove (object value) + { + throw new NotSupportedException ("Remove operation is not supported."); + } + + void IList.RemoveAt (int index) + { + throw new NotSupportedException ("RemoveAt operation is not supported."); + } + + public int IndexOf (ListViewItem item) + { + if (!owner.is_selection_available) + return -1; + + for (int i = 0; i < Count; i++) + if (this [i] == item) + return i; + + return -1; + } + + public virtual int IndexOfKey (string key) + { + if (!owner.is_selection_available || key == null || key.Length == 0) + return -1; + + for (int i = 0; i < Count; i++) { + ListViewItem item = this [i]; + if (String.Compare (item.Name, key, true) == 0) + return i; + } + + return -1; + } + #endregion // Public Methods + + } // SelectedListViewItemCollection + + internal delegate void CollectionChangedHandler (); + + struct ItemMatrixLocation + { + int row; + int col; + + public ItemMatrixLocation (int row, int col) + { + this.row = row; + this.col = col; + + } + + public int Col { + get { + return col; + } + set { + col = value; + } + } + + public int Row { + get { + return row; + } + set { + row = value; + } + } + + } + + #endregion // Subclasses + protected override void OnResize (EventArgs e) + { + base.OnResize (e); + } + + protected override void OnMouseLeave (EventArgs e) + { + base.OnMouseLeave (e); + } + + // + // ColumnReorder event + // + static object ColumnReorderedEvent = new object (); + public event ColumnReorderedEventHandler ColumnReordered { + add { Events.AddHandler (ColumnReorderedEvent, value); } + remove { Events.RemoveHandler (ColumnReorderedEvent, value); } + } + + protected virtual void OnColumnReordered (ColumnReorderedEventArgs e) + { + ColumnReorderedEventHandler creh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]); + + if (creh != null) + creh (this, e); + } + + // + // ColumnWidthChanged + // + static object ColumnWidthChangedEvent = new object (); + public event ColumnWidthChangedEventHandler ColumnWidthChanged { + add { Events.AddHandler (ColumnWidthChangedEvent, value); } + remove { Events.RemoveHandler (ColumnWidthChangedEvent, value); } + } + + protected virtual void OnColumnWidthChanged (ColumnWidthChangedEventArgs e) + { + ColumnWidthChangedEventHandler eh = (ColumnWidthChangedEventHandler) (Events[ColumnWidthChangedEvent]); + if (eh != null) + eh (this, e); + } + + void RaiseColumnWidthChanged (int resize_column) + { + ColumnWidthChangedEventArgs n = new ColumnWidthChangedEventArgs (resize_column); + + OnColumnWidthChanged (n); + } + + // + // ColumnWidthChanging + // + static object ColumnWidthChangingEvent = new object (); + public event ColumnWidthChangingEventHandler ColumnWidthChanging { + add { Events.AddHandler (ColumnWidthChangingEvent, value); } + remove { Events.RemoveHandler (ColumnWidthChangingEvent, value); } + } + + protected virtual void OnColumnWidthChanging (ColumnWidthChangingEventArgs e) + { + ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]); + if (cwceh != null) + cwceh (this, e); + } + + // + // 2.0 profile based implementation + // + bool CanProceedWithResize (ColumnHeader col, int width) + { + ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]); + if (cwceh == null) + return true; + + ColumnWidthChangingEventArgs changing = new ColumnWidthChangingEventArgs (col.Index, width); + cwceh (this, changing); + return !changing.Cancel; + } + + internal void RaiseColumnWidthChanged (ColumnHeader column) + { + int index = Columns.IndexOf (column); + RaiseColumnWidthChanged (index); + } + + + #region UIA Framework: Methods, Properties and Events + + static object UIALabelEditChangedEvent = new object (); + static object UIAShowGroupsChangedEvent = new object (); + static object UIAMultiSelectChangedEvent = new object (); + static object UIAViewChangedEvent = new object (); + static object UIACheckBoxesChangedEvent = new object (); + static object UIAFocusedItemChangedEvent = new object (); + + internal Rectangle UIAHeaderControl { + get { return header_control.Bounds; } + } + + internal int UIAColumns { + get { return cols; } + } + + internal int UIARows { + get { return rows; } + } + + internal ListViewGroup UIADefaultListViewGroup + { + get { return groups.DefaultGroup; } + } + + internal ScrollBar UIAHScrollBar { + get { return h_scroll; } + } + + internal ScrollBar UIAVScrollBar { + get { return v_scroll; } + } + + internal event EventHandler UIAShowGroupsChanged { + add { Events.AddHandler (UIAShowGroupsChangedEvent, value); } + remove { Events.RemoveHandler (UIAShowGroupsChangedEvent, value); } + } + + internal event EventHandler UIACheckBoxesChanged { + add { Events.AddHandler (UIACheckBoxesChangedEvent, value); } + remove { Events.RemoveHandler (UIACheckBoxesChangedEvent, value); } + } + + internal event EventHandler UIAMultiSelectChanged { + add { Events.AddHandler (UIAMultiSelectChangedEvent, value); } + remove { Events.RemoveHandler (UIAMultiSelectChangedEvent, value); } + } + + internal event EventHandler UIALabelEditChanged { + add { Events.AddHandler (UIALabelEditChangedEvent, value); } + remove { Events.RemoveHandler (UIALabelEditChangedEvent, value); } + } + + internal event EventHandler UIAViewChanged { + add { Events.AddHandler (UIAViewChangedEvent, value); } + remove { Events.RemoveHandler (UIAViewChangedEvent, value); } + } + + internal event EventHandler UIAFocusedItemChanged { + add { Events.AddHandler (UIAFocusedItemChangedEvent, value); } + remove { Events.RemoveHandler (UIAFocusedItemChangedEvent, value); } + } + + internal Rectangle UIAGetHeaderBounds (ListViewGroup group) + { + return group.HeaderBounds; + } + + internal int UIAItemsLocationLength + { + get { return items_location.Length; } + } + + private void OnUIACheckBoxesChanged () + { + EventHandler eh = (EventHandler) Events [UIACheckBoxesChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + + private void OnUIAShowGroupsChanged () + { + EventHandler eh = (EventHandler) Events [UIAShowGroupsChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + + private void OnUIAMultiSelectChanged () + { + EventHandler eh = (EventHandler) Events [UIAMultiSelectChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + + private void OnUIALabelEditChanged () + { + EventHandler eh = (EventHandler) Events [UIALabelEditChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + + private void OnUIAViewChanged () + { + EventHandler eh = (EventHandler) Events [UIAViewChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + + internal void OnUIAFocusedItemChanged () + { + EventHandler eh = (EventHandler) Events [UIAFocusedItemChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + + #endregion // UIA Framework: Methods, Properties and Events + + } +} diff --git a/source/ShiftUI/Widgets/ListViewItem.cs b/source/ShiftUI/Widgets/ListViewItem.cs new file mode 100644 index 0000000..b9473e1 --- /dev/null +++ b/source/ShiftUI/Widgets/ListViewItem.cs @@ -0,0 +1,1638 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Author: +// Ravindra (rkumar@novell.com) +// Mike Kestner +// Daniel Nauck (dna(at)mono-project(dot)de) + +using System.Collections; +using System.ComponentModel; +using System.Drawing; +using System.Runtime.Serialization; +using System; + +namespace ShiftUI +{ + [DefaultProperty ("Text")] + [DesignTimeVisible (false)] + [Serializable] + [ToolboxItem (false)] + [TypeConverter (typeof (ListViewItemConverter))] + public class ListViewItem : ICloneable, ISerializable + { + #region Instance Variables + private int image_index = -1; + private bool is_checked = false; + private int state_image_index = -1; + private ListViewSubItemCollection sub_items; + private object tag; + private bool use_item_style = true; + int display_index = -1; // actual position in ListView + private ListViewGroup group = null; + private string name = String.Empty; + private string image_key = String.Empty; + string tooltip_text = String.Empty; + int indent_count; + Point position = new Point (-1, -1); // cached to mimic .Net behaviour + Rectangle bounds = Rectangle.Empty; + Rectangle checkbox_rect; // calculated by CalcListViewItem method + Rectangle icon_rect; + Rectangle item_rect; + Rectangle label_rect; + ListView owner; + Font font; + Font hot_font; // cached font for hot tracking + bool selected; + + internal int row; + internal int col; + + + #region UIA Framework: Methods, Properties and Events + + internal event EventHandler UIATextChanged; + + internal event LabelEditEventHandler UIASubItemTextChanged; + + internal void OnUIATextChanged () + { + if (UIATextChanged != null) + UIATextChanged (this, EventArgs.Empty); + } + + internal void OnUIASubItemTextChanged (LabelEditEventArgs args) + { + //If our index is 0 we also generate TextChanged for the ListViewItem + //because ListViewItem.Text is the same as ListViewItem.SubItems [0].Text + if (args.Item == 0) + OnUIATextChanged (); + + if (UIASubItemTextChanged != null) + UIASubItemTextChanged (this, args); + } + + #endregion // UIA Framework: Methods, Properties and Events + + + #endregion Instance Variables + + #region Public Constructors + public ListViewItem () : this (string.Empty) + { + } + + public ListViewItem (string text) : this (text, -1) + { + } + + public ListViewItem (string [] items) : this (items, -1) + { + } + + public ListViewItem (ListViewItem.ListViewSubItem [] subItems, int imageIndex) + { + this.sub_items = new ListViewSubItemCollection (this, null); + for (int i = 0; i < subItems.Length; i++) + sub_items.Add (subItems [i]); + this.image_index = imageIndex; + } + + public ListViewItem (string text, int imageIndex) + { + this.image_index = imageIndex; + this.sub_items = new ListViewSubItemCollection (this, text); + } + + public ListViewItem (string [] items, int imageIndex) + { + this.sub_items = new ListViewSubItemCollection (this, null); + if (items != null) { + for (int i = 0; i < items.Length; i++) + sub_items.Add (new ListViewSubItem (this, items [i])); + } + this.image_index = imageIndex; + } + + public ListViewItem (string [] items, int imageIndex, Color foreColor, + Color backColor, Font font) : this (items, imageIndex) + { + ForeColor = foreColor; + BackColor = backColor; + this.font = font; + } + + public ListViewItem(string[] items, string imageKey) : this(items) + { + this.ImageKey = imageKey; + } + + public ListViewItem(string text, string imageKey) : this(text) + { + this.ImageKey = imageKey; + } + + public ListViewItem(ListViewSubItem[] subItems, string imageKey) + { + this.sub_items = new ListViewSubItemCollection (this, null); + for (int i = 0; i < subItems.Length; i++) + this.sub_items.Add (subItems [i]); + this.ImageKey = imageKey; + } + + public ListViewItem(string[] items, string imageKey, Color foreColor, + Color backColor, Font font) : this(items, imageKey) + { + ForeColor = foreColor; + BackColor = backColor; + this.font = font; + } + + public ListViewItem(ListViewGroup group) : this() + { + Group = group; + } + + public ListViewItem(string text, ListViewGroup group) : this(text) + { + Group = group; + } + + public ListViewItem(string[] items, ListViewGroup group) : this(items) + { + Group = group; + } + + public ListViewItem(ListViewSubItem[] subItems, int imageIndex, ListViewGroup group) + : this(subItems, imageIndex) + { + Group = group; + } + + public ListViewItem(ListViewSubItem[] subItems, string imageKey, ListViewGroup group) + : this(subItems, imageKey) + { + Group = group; + } + + public ListViewItem(string text, int imageIndex, ListViewGroup group) + : this(text, imageIndex) + { + Group = group; + } + + public ListViewItem(string text, string imageKey, ListViewGroup group) + : this(text, imageKey) + { + Group = group; + } + + public ListViewItem(string[] items, int imageIndex, ListViewGroup group) + : this(items, imageIndex) + { + Group = group; + } + + public ListViewItem(string[] items, string imageKey, ListViewGroup group) + : this(items, imageKey) + { + Group = group; + } + + public ListViewItem(string[] items, int imageIndex, Color foreColor, Color backColor, + Font font, ListViewGroup group) + : this(items, imageIndex, foreColor, backColor, font) + { + Group = group; + } + + public ListViewItem(string[] items, string imageKey, Color foreColor, Color backColor, + Font font, ListViewGroup group) + : this(items, imageKey, foreColor, backColor, font) + { + Group = group; + } + #endregion // Public Constructors + + protected ListViewItem (SerializationInfo info, StreamingContext context) + { + Deserialize (info, context); + } + + #region Public Instance Properties + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public Color BackColor { + get { + if (sub_items.Count > 0) + return sub_items[0].BackColor; + + if (owner != null) + return owner.BackColor; + + return ThemeEngine.Current.ColorWindow; + } + set { SubItems [0].BackColor = value; } + } + + [Browsable (false)] + public Rectangle Bounds { + get { + return GetBounds (ItemBoundsPortion.Entire); + } + } + + [DefaultValue (false)] + [RefreshProperties (RefreshProperties.Repaint)] + public bool Checked { + get { return is_checked; } + set { + if (is_checked == value) + return; + + if (owner != null) { + CheckState current_value = is_checked ? CheckState.Checked : CheckState.Unchecked; + CheckState new_value = value ? CheckState.Checked : CheckState.Unchecked; + + ItemCheckEventArgs icea = new ItemCheckEventArgs (Index, + new_value, current_value); + owner.OnItemCheck (icea); + + if (new_value != current_value) { + // force re-population of list + owner.CheckedItems.Reset (); + is_checked = new_value == CheckState.Checked; + Invalidate (); + + ItemCheckedEventArgs args = new ItemCheckedEventArgs (this); + owner.OnItemChecked (args); + } + } else + is_checked = value; + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public bool Focused { + get { + if (owner == null) + return false; + + // In virtual mode the checks are always done using indexes + if (owner.VirtualMode) + return Index == owner.focused_item_index; + + // Light check + return owner.FocusedItem == this; + + } + set { + if (owner == null) + return; + + if (Focused == value) + return; + + ListViewItem prev_focused_item = owner.FocusedItem; + if (prev_focused_item != null) + prev_focused_item.UpdateFocusedState (); + + owner.focused_item_index = value ? Index : -1; + if (value) + owner.OnUIAFocusedItemChanged (); + + UpdateFocusedState (); + } + } + + [Localizable (true)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public Font Font { + get { + if (font != null) + return font; + else if (owner != null) + return owner.Font; + + return ThemeEngine.Current.DefaultFont; + } + set { + if (font == value) + return; + + font = value; + hot_font = null; + + if (owner != null) + Layout (); + Invalidate (); + } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public Color ForeColor { + get { + if (sub_items.Count > 0) + return sub_items[0].ForeColor; + + if (owner != null) + return owner.ForeColor; + + return ThemeEngine.Current.ColorWindowText; + } + set { SubItems [0].ForeColor = value; } + } + + [DefaultValue (-1)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, + //typeof (System.Drawing.Design.UITypeEditor))] + [Localizable (true)] + [RefreshProperties (RefreshProperties.Repaint)] + [TypeConverter (typeof (NoneExcludedImageIndexConverter))] + public int ImageIndex { + get { return image_index; } + set { + if (value < -1) + throw new ArgumentException ("Invalid ImageIndex. It must be greater than or equal to -1."); + + image_index = value; + image_key = String.Empty; + + if (owner != null) + Layout (); + Invalidate (); + } + } + + [DefaultValue ("")] + [LocalizableAttribute (true)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, + //typeof (System.Drawing.Design.UITypeEditor))] + [RefreshProperties (RefreshProperties.Repaint)] + [TypeConverter (typeof (ImageKeyConverter))] + public string ImageKey { + get { + return image_key; + } + set { + image_key = value == null ? String.Empty : value; + image_index = -1; + + if (owner != null) + Layout (); + Invalidate (); + } + } + + [Browsable (false)] + public ImageList ImageList { + get { + if (owner == null) + return null; + else if (owner.View == View.LargeIcon) + return owner.large_image_list; + else + return owner.small_image_list; + } + } + + [DefaultValue (0)] + public int IndentCount { + get { + return indent_count; + } + set { + if (value < 0) + throw new ArgumentOutOfRangeException ("value"); + + if (value == indent_count) + return; + + indent_count = value; + Invalidate (); + } + } + + [Browsable (false)] + public int Index { + get { + if (owner == null) + return -1; + if (owner.VirtualMode) + return display_index; + + if (display_index == -1) + return owner.Items.IndexOf (this); + + return owner.GetItemIndex (display_index); + } + } + + [Browsable (false)] + public ListView ListView { + get { return owner; } + } + + [Browsable (false)] + [Localizable (true)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public string Name { + get { + return name; + } + set { + name = value == null ? String.Empty : value; + } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + [Browsable (false)] + public Point Position { + get { + if (owner != null && owner.VirtualMode) + return owner.GetItemLocation (display_index); + + if (owner != null && !owner.IsHandleCreated) + return new Point (-1, -1); + + return position; + } + set { + if (owner == null || owner.View == View.Details || owner.View == View.List) + return; + + if (owner.VirtualMode) + throw new InvalidOperationException (); + + owner.ChangeItemLocation (display_index, value); + } + } + + // When ListView uses VirtualMode, selection state info + // lives in the ListView, not in the item + // Also, in VirtualMode we can't Reset() the selection + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public bool Selected { + get { + if (owner != null && owner.VirtualMode) + return owner.SelectedIndices.Contains (Index); + + return selected; + } + set { + if (selected == value && owner != null && !owner.VirtualMode) + return; + + SetSelectedCore (value); + } + } + + // Expose this method as internal so we can force an update in the selection. + internal void SetSelectedCore (bool value) + { + if (owner != null) { + if (value && !owner.MultiSelect) + owner.SelectedIndices.Clear (); + if (owner.VirtualMode) { + if (value) + owner.SelectedIndices.InsertIndex (Index); + else + owner.SelectedIndices.RemoveIndex (Index); + } else { + selected = value; + owner.SelectedIndices.Reset (); // force re-population of list + } + + owner.OnItemSelectionChanged (new ListViewItemSelectionChangedEventArgs (this, Index, value)); + owner.OnSelectedIndexChanged (); + Invalidate (); + } else + selected = value; + } + + [DefaultValue (-1)] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, + //typeof (System.Drawing.Design.UITypeEditor))] + [Localizable (true)] + [RefreshProperties (RefreshProperties.Repaint)] + [RelatedImageListAttribute ("ListView.StateImageList")] + [TypeConverter (typeof (NoneExcludedImageIndexConverter))] + public int StateImageIndex { + get { return state_image_index; } + set { + if (value < -1 || value > 14) + throw new ArgumentOutOfRangeException ("Invalid StateImageIndex. It must be in the range of [-1, 14]."); + + state_image_index = value; + } + } + + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[Editor ("ShiftUI.Design.ListViewSubItemCollectionEditor, " + Consts.AssemblySystem_Design, + //typeof (System.Drawing.Design.UITypeEditor))] + public ListViewSubItemCollection SubItems { + get { + if (sub_items.Count == 0) + this.sub_items.Add (string.Empty); + return sub_items; + } + } + + [Bindable (true)] + [DefaultValue (null)] + [Localizable (false)] + [TypeConverter (typeof (StringConverter))] + public object Tag { + get { return tag; } + set { tag = value; } + } + + [Localizable (true)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public string Text { + get { + if (this.sub_items.Count > 0) + return this.sub_items [0].Text; + else + return string.Empty; + } + set { + if (SubItems [0].Text == value) + return; + + sub_items [0].Text = value; + + if (owner != null) + Layout (); + Invalidate (); + + //UIA Framework: Generates Text changed + OnUIATextChanged (); + + } + } + + [DefaultValue (true)] + public bool UseItemStyleForSubItems { + get { return use_item_style; } + set { use_item_style = value; } + } + + [LocalizableAttribute(true)] + [DefaultValue (null)] + public ListViewGroup Group { + get { return this.group; } + set { + if (group != value) { + if (value == null) + group.Items.Remove (this); + else + value.Items.Add (this); + + group = value; + } + } + } + + [DefaultValue ("")] + public string ToolTipText { + get { + return tooltip_text; + } + set { + if (value == null) + value = String.Empty; + + tooltip_text = value; + } + } + + #endregion // Public Instance Properties + + #region Public Instance Methods + public void BeginEdit () + { + if (owner != null && owner.LabelEdit) { + owner.item_control.BeginEdit (this); + } + // FIXME: TODO + // if (owner != null && owner.LabelEdit + // && owner.Activation == ItemActivation.Standard) + // allow editing + // else + // throw new InvalidOperationException (); + } + + public virtual object Clone () + { + ListViewItem clone = new ListViewItem (); + clone.image_index = this.image_index; + clone.is_checked = this.is_checked; + clone.selected = this.selected; + clone.font = this.font; + clone.state_image_index = this.state_image_index; + clone.sub_items = new ListViewSubItemCollection (this, null); + + foreach (ListViewSubItem subItem in this.sub_items) + clone.sub_items.Add (subItem.Text, subItem.ForeColor, + subItem.BackColor, subItem.Font); + clone.tag = this.tag; + clone.use_item_style = this.use_item_style; + clone.owner = null; + clone.name = name; + clone.tooltip_text = tooltip_text; + + return clone; + } + + public virtual void EnsureVisible () + { + if (this.owner != null) { + owner.EnsureVisible (owner.Items.IndexOf (this)); + } + } + + public ListViewItem FindNearestItem (SearchDirectionHint searchDirection) + { + if (owner == null) + return null; + + Point loc = owner.GetItemLocation (display_index); + return owner.FindNearestItem (searchDirection, loc); + } + + public Rectangle GetBounds (ItemBoundsPortion portion) + { + if (owner == null) + return Rectangle.Empty; + + Rectangle rect; + + switch (portion) { + case ItemBoundsPortion.Icon: + rect = icon_rect; + break; + + case ItemBoundsPortion.Label: + rect = label_rect; + break; + + case ItemBoundsPortion.ItemOnly: + rect = item_rect; + break; + + case ItemBoundsPortion.Entire: + rect = bounds; + break; + + default: + throw new ArgumentException ("Invalid value for portion."); + } + + Point item_loc = owner.GetItemLocation (DisplayIndex); + rect.X += item_loc.X; + rect.Y += item_loc.Y; + return rect; + } + + void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) + { + Serialize (info, context); + } + + public ListViewSubItem GetSubItemAt (int x, int y) + { + if (owner != null && owner.View != View.Details) + return null; + + foreach (ListViewSubItem sub_item in sub_items) + if (sub_item.Bounds.Contains (x, y)) + return sub_item; + + return null; + } + + public virtual void Remove () + { + if (owner == null) + return; + + owner.item_control.CancelEdit (this); + owner.Items.Remove (this); + owner = null; + } + + public override string ToString () + { + return string.Format ("ListViewItem: {0}", this.Text); + } + #endregion // Public Instance Methods + + #region Protected Methods + protected virtual void Deserialize (SerializationInfo info, StreamingContext context) + { + sub_items = new ListViewSubItemCollection (this, null); + int sub_items_count = 0; + + foreach (SerializationEntry entry in info) { + switch (entry.Name) { + case "Text": + sub_items.Add ((string)entry.Value); + break; + case "Font": + font = (Font)entry.Value; + break; + case "Checked": + is_checked = (bool)entry.Value; + break; + case "ImageIndex": + image_index = (int)entry.Value; + break; + case "StateImageIndex": + state_image_index = (int)entry.Value; + break; + case "UseItemStyleForSubItems": + use_item_style = (bool)entry.Value; + break; + case "SubItemCount": + sub_items_count = (int)entry.Value; + break; + case "Group": + group = (ListViewGroup)entry.Value; + break; + case "ImageKey": + if (image_index == -1) + image_key = (string)entry.Value; + break; + } + } + + Type subitem_type = typeof (ListViewSubItem); + if (sub_items_count > 0) { + sub_items.Clear (); // .net fixup + Text = info.GetString ("Text"); + for (int i = 0; i < sub_items_count - 1; i++) + sub_items.Add ((ListViewSubItem)info.GetValue ("SubItem" + (i + 1), subitem_type)); + } + + // After any sub item has been added. + ForeColor = (Color)info.GetValue ("ForeColor", typeof (Color)); + BackColor = (Color)info.GetValue ("BackColor", typeof (Color)); + } + + protected virtual void Serialize (SerializationInfo info, StreamingContext context) + { + info.AddValue ("Text", Text); + info.AddValue ("Font", Font); + info.AddValue ("ImageIndex", image_index); + info.AddValue ("Checked", is_checked); + info.AddValue ("StateImageIndex", state_image_index); + info.AddValue ("UseItemStyleForSubItems", use_item_style); + info.AddValue ("BackColor", BackColor); + info.AddValue ("ForeColor", ForeColor); + info.AddValue ("ImageKey", image_key); + if (group != null) + info.AddValue ("Group", group); + if (sub_items.Count > 1) { + info.AddValue ("SubItemCount", sub_items.Count); + for (int i = 1; i < sub_items.Count; i++) { + info.AddValue ("SubItem" + i, sub_items [i]); + } + } + } + #endregion // Protected Methods + + #region Private Internal Methods + internal Rectangle CheckRectReal { + get { + Rectangle rect = checkbox_rect; + Point item_loc = owner.GetItemLocation (DisplayIndex); + rect.X += item_loc.X; + rect.Y += item_loc.Y; + return rect; + } + } + + Rectangle text_bounds; + internal Rectangle TextBounds { + get { + // Call Layout() if it hasn't been called before. + if (owner.VirtualMode && bounds == new Rectangle (-1, -1, -1, -1)) + Layout (); + Rectangle result = text_bounds; + Point loc = owner.GetItemLocation (DisplayIndex); + result.X += loc.X; + result.Y += loc.Y; + return result; + } + } + + internal int DisplayIndex { + get { + // Special case for Details view + // and no columns (which means no Layout at all) + if (display_index == -1) + return owner.Items.IndexOf (this); + + return display_index; + } + set { + display_index = value; + } + } + + internal bool Hot { + get { + return Index == owner.HotItemIndex; + } + } + + internal Font HotFont { + get { + if (hot_font == null) + hot_font = new Font (Font, Font.Style | FontStyle.Underline); + + return hot_font; + } + } + + internal ListView Owner { + set { + if (owner == value) + return; + + owner = value; + } + } + + internal void SetGroup (ListViewGroup group) + { + this.group = group; + } + + internal void SetPosition (Point position) + { + this.position = position; + } + + // When focus changed, we need to invalidate area + // with previous layout and with the new one + void UpdateFocusedState () + { + if (owner != null) { + Invalidate (); + Layout (); + Invalidate (); + } + } + + internal void Invalidate () + { + if (owner == null || owner.item_control == null || owner.updating) + return; + + // Add some padding to bounds (focused extra space, selection) + Rectangle rect = Bounds; + rect.Inflate (1, 1); + owner.item_control.Invalidate (rect); + } + + internal void Layout () + { + if (owner == null) + return; + int item_ht; + Rectangle total; + Size text_size = owner.text_size; + + checkbox_rect = Rectangle.Empty; + if (owner.CheckBoxes) + checkbox_rect.Size = owner.CheckBoxSize; + switch (owner.View) { + case View.Details: + // LAMESPEC: MSDN says, "In all views except the details + // view of the ListView, this value specifies the same + // bounding rectangle as the Entire value." Actually, it + // returns same bounding rectangles for Item and Entire + // values in the case of Details view. + + int x_offset = 0; + if (owner.SmallImageList != null) + x_offset = indent_count * owner.SmallImageList.ImageSize.Width; + + // Handle reordered column + if (owner.Columns.Count > 0) + checkbox_rect.X = owner.Columns[0].Rect.X + x_offset; + + icon_rect = label_rect = Rectangle.Empty; + icon_rect.X = checkbox_rect.Right + 2; + item_ht = owner.ItemSize.Height; + + if (owner.SmallImageList != null) + icon_rect.Width = owner.SmallImageList.ImageSize.Width; + + label_rect.Height = icon_rect.Height = item_ht; + checkbox_rect.Y = item_ht - checkbox_rect.Height; + + label_rect.X = icon_rect.Width > 0 ? icon_rect.Right + 1 : icon_rect.Right; + + if (owner.Columns.Count > 0) + label_rect.Width = owner.Columns[0].Wd - label_rect.X + checkbox_rect.X; + else + label_rect.Width = text_size.Width; + + SizeF text_sz = TextRenderer.MeasureString (Text, Font); + text_bounds = label_rect; + text_bounds.Width = (int) text_sz.Width; + + item_rect = total = Rectangle.Union + (Rectangle.Union (checkbox_rect, icon_rect), label_rect); + bounds.Size = total.Size; + + item_rect.Width = 0; + bounds.Width = 0; + for (int i = 0; i < owner.Columns.Count; i++) { + item_rect.Width += owner.Columns [i].Wd; + bounds.Width += owner.Columns [i].Wd; + } + + // Bounds for sub items + int n = Math.Min (owner.Columns.Count, sub_items.Count); + for (int i = 0; i < n; i++) { + Rectangle col_rect = owner.Columns [i].Rect; + sub_items [i].SetBounds (col_rect.X, 0, col_rect.Width, item_ht); + } + break; + + case View.LargeIcon: + label_rect = icon_rect = Rectangle.Empty; + + SizeF sz = TextRenderer.MeasureString (Text, Font); + if ((int) sz.Width > text_size.Width) { + if (Focused && owner.InternalContainsFocus) { + int text_width = text_size.Width; + StringFormat format = new StringFormat (); + format.Alignment = StringAlignment.Center; + sz = TextRenderer.MeasureString (Text, Font, text_width, format); + text_size.Height = (int) sz.Height; + } else + text_size.Height = 2 * (int) sz.Height; + } + + if (owner.LargeImageList != null) { + icon_rect.Width = owner.LargeImageList.ImageSize.Width; + icon_rect.Height = owner.LargeImageList.ImageSize.Height; + } + + if (checkbox_rect.Height > icon_rect.Height) + icon_rect.Y = checkbox_rect.Height - icon_rect.Height; + else + checkbox_rect.Y = icon_rect.Height - checkbox_rect.Height; + + if (text_size.Width <= icon_rect.Width) { + icon_rect.X = checkbox_rect.Width + 1; + label_rect.X = icon_rect.X + (icon_rect.Width - text_size.Width) / 2; + label_rect.Y = icon_rect.Bottom + 2; + label_rect.Size = text_size; + } else { + int centerX = text_size.Width / 2; + icon_rect.X = checkbox_rect.Width + 1 + centerX - icon_rect.Width / 2; + label_rect.X = checkbox_rect.Width + 1; + label_rect.Y = icon_rect.Bottom + 2; + label_rect.Size = text_size; + } + + item_rect = Rectangle.Union (icon_rect, label_rect); + total = Rectangle.Union (item_rect, checkbox_rect); + bounds.Size = total.Size; + break; + + case View.List: + case View.SmallIcon: + label_rect = icon_rect = Rectangle.Empty; + icon_rect.X = checkbox_rect.Width + 1; + item_ht = Math.Max (owner.CheckBoxSize.Height, text_size.Height); + + if (owner.SmallImageList != null) { + item_ht = Math.Max (item_ht, owner.SmallImageList.ImageSize.Height); + icon_rect.Width = owner.SmallImageList.ImageSize.Width; + icon_rect.Height = owner.SmallImageList.ImageSize.Height; + } + + checkbox_rect.Y = item_ht - checkbox_rect.Height; + label_rect.X = icon_rect.Right + 1; + label_rect.Width = text_size.Width; + label_rect.Height = icon_rect.Height = item_ht; + + item_rect = Rectangle.Union (icon_rect, label_rect); + total = Rectangle.Union (item_rect, checkbox_rect); + bounds.Size = total.Size; + break; + case View.Tile: + if (!Application.VisualStylesEnabled) + goto case View.LargeIcon; + + label_rect = icon_rect = Rectangle.Empty; + + if (owner.LargeImageList != null) { + icon_rect.Width = owner.LargeImageList.ImageSize.Width; + icon_rect.Height = owner.LargeImageList.ImageSize.Height; + } + + int separation = 2; + SizeF tsize = TextRenderer.MeasureString (Text, Font); + int main_item_height = (int) Math.Ceiling (tsize.Height); + int main_item_width = (int) Math.Ceiling (tsize.Width); + sub_items [0].bounds.Height = main_item_height; + + // Set initial values for subitem's layout + int total_height = main_item_height; + int max_subitem_width = main_item_width; + + int count = Math.Min (owner.Columns.Count, sub_items.Count); + for (int i = 1; i < count; i++) { // Ignore first column and first subitem + ListViewSubItem sub_item = sub_items [i]; + if (sub_item.Text == null || sub_item.Text.Length == 0) + continue; + + tsize = TextRenderer.MeasureString (sub_item.Text, sub_item.Font); + + int width = (int)Math.Ceiling (tsize.Width); + if (width > max_subitem_width) + max_subitem_width = width; + + int height = (int)Math.Ceiling (tsize.Height); + total_height += height + separation; + + sub_item.bounds.Height = height; + } + + max_subitem_width = Math.Min (max_subitem_width, owner.TileSize.Width - (icon_rect.Width + 4)); + label_rect.X = icon_rect.Right + 4; + label_rect.Y = owner.TileSize.Height / 2 - total_height / 2; + label_rect.Width = max_subitem_width; + label_rect.Height = total_height; + + // Main item - always set bounds for it + sub_items [0].SetBounds (label_rect.X, label_rect.Y, max_subitem_width, sub_items [0].bounds.Height); + + // Second pass to assign bounds for every sub item + int current_y = sub_items [0].bounds.Bottom + separation; + for (int j = 1; j < count; j++) { + ListViewSubItem sub_item = sub_items [j]; + if (sub_item.Text == null || sub_item.Text.Length == 0) + continue; + + sub_item.SetBounds (label_rect.X, current_y, max_subitem_width, sub_item.bounds.Height); + current_y += sub_item.Bounds.Height + separation; + } + + item_rect = Rectangle.Union (icon_rect, label_rect); + bounds.Size = item_rect.Size; + break; + } + + } + #endregion // Private Internal Methods + + #region Subclasses + + [DefaultProperty ("Text")] + [DesignTimeVisible (false)] + [Serializable] + [ToolboxItem (false)] + [TypeConverter (typeof(ListViewSubItemConverter))] + public class ListViewSubItem + { + [NonSerialized] + internal ListViewItem owner; + private string text = string.Empty; + private string name; + private object userData; + private SubItemStyle style; + [NonSerialized] + internal Rectangle bounds; + + + #region UIA Framework: Methods, Properties and Events + + [field:NonSerialized] + internal event EventHandler UIATextChanged; + + private void OnUIATextChanged () + { + if (UIATextChanged != null) + UIATextChanged (this, EventArgs.Empty); + } + + #endregion // UIA Framework: Methods, Properties and Events + + + #region Public Constructors + public ListViewSubItem () + : this (null, string.Empty, Color.Empty, + Color.Empty, null) + { + } + + public ListViewSubItem (ListViewItem owner, string text) + : this (owner, text, Color.Empty, + Color.Empty, null) + { + } + + public ListViewSubItem (ListViewItem owner, string text, Color foreColor, + Color backColor, Font font) + { + this.owner = owner; + Text = text; + this.style = new SubItemStyle (foreColor, + backColor, font); + } + #endregion // Public Constructors + + #region Public Instance Properties + public Color BackColor { + get { + if (style.backColor != Color.Empty) + return style.backColor; + if (this.owner != null && this.owner.ListView != null) + return this.owner.ListView.BackColor; + return ThemeEngine.Current.ColorWindow; + } + set { + style.backColor = value; + Invalidate (); + } + } + + [Browsable (false)] + public Rectangle Bounds { + get { + Rectangle retval = bounds; + if (owner != null) { + retval.X += owner.Bounds.X; + retval.Y += owner.Bounds.Y; + } + + return retval; + } + } + + [Localizable (true)] + public Font Font { + get { + if (style.font != null) + return style.font; + else if (owner != null) + return owner.Font; + return ThemeEngine.Current.DefaultFont; + } + set { + if (style.font == value) + return; + style.font = value; + Invalidate (); + } + } + + public Color ForeColor { + get { + if (style.foreColor != Color.Empty) + return style.foreColor; + if (this.owner != null && this.owner.ListView != null) + return this.owner.ListView.ForeColor; + return ThemeEngine.Current.ColorWindowText; + } + set { + style.foreColor = value; + Invalidate (); + } + } + + [Localizable (true)] + public string Name { + get { + if (name == null) + return string.Empty; + return name; + } + set { + name = value; + } + } + + [TypeConverter (typeof (StringConverter))] + [BindableAttribute (true)] + [DefaultValue (null)] + [Localizable (false)] + public object Tag { + get { + return userData; + } + set { + userData = value; + } + } + + [Localizable (true)] + public string Text { + get { return text; } + set { + if(text == value) + return; + + if(value == null) + text = string.Empty; + else + text = value; + + Invalidate (); + + // UIA Framework: Generates SubItem TextChanged + OnUIATextChanged (); + } + } + #endregion // Public Instance Properties + + #region Public Methods + public void ResetStyle () + { + style.Reset (); + Invalidate (); + } + + public override string ToString () + { + return string.Format ("ListViewSubItem {{0}}", text); + } + #endregion // Public Methods + + #region Private Methods + private void Invalidate () + { + if (owner == null || owner.owner == null) + return; + + owner.Invalidate (); + } + + [OnDeserialized] + void OnDeserialized (StreamingContext context) + { + name = null; + userData = null; + } + + internal int Height { + get { + return bounds.Height; + } + } + + internal void SetBounds (int x, int y, int width, int height) + { + bounds = new Rectangle (x, y, width, height); + } + + #endregion // Private Methods + + [Serializable] + class SubItemStyle + { + public SubItemStyle () + { + } + + public SubItemStyle (Color foreColor, Color backColor, Font font) + { + this.foreColor = foreColor; + this.backColor = backColor; + this.font = font; + } + + public void Reset () + { + foreColor = Color.Empty; + backColor = Color.Empty; + font = null; + } + + public Color backColor; + public Color foreColor; + public Font font; + } + } + + public class ListViewSubItemCollection : IList, ICollection, IEnumerable + { + private ArrayList list; + internal ListViewItem owner; + + #region Public Constructors + public ListViewSubItemCollection (ListViewItem owner) : this (owner, owner.Text) + { + } + #endregion // Public Constructors + + internal ListViewSubItemCollection (ListViewItem owner, string text) + { + this.owner = owner; + this.list = new ArrayList (); + if (text != null) + Add (text); + } + #region Public Properties + [Browsable (false)] + public int Count { + get { return list.Count; } + } + + public bool IsReadOnly { + get { return false; } + } + + public ListViewSubItem this [int index] { + get { return (ListViewSubItem) list [index]; } + set { + value.owner = owner; + list [index] = value; + owner.Layout (); + owner.Invalidate (); + } + } + + public virtual ListViewSubItem this [string key] { + get { + int idx = IndexOfKey (key); + if (idx == -1) + return null; + + return (ListViewSubItem) list [idx]; + } + } + + bool ICollection.IsSynchronized { + get { return list.IsSynchronized; } + } + + object ICollection.SyncRoot { + get { return list.SyncRoot; } + } + + bool IList.IsFixedSize { + get { return list.IsFixedSize; } + } + + object IList.this [int index] { + get { return this [index]; } + set { + if (! (value is ListViewSubItem)) + throw new ArgumentException ("Not of type ListViewSubItem", "value"); + this [index] = (ListViewSubItem) value; + } + } + #endregion // Public Properties + + #region Public Methods + public ListViewSubItem Add (ListViewSubItem item) + { + AddSubItem (item); + owner.Layout (); + owner.Invalidate (); + return item; + } + + public ListViewSubItem Add (string text) + { + ListViewSubItem item = new ListViewSubItem (owner, text); + return Add (item); + } + + public ListViewSubItem Add (string text, Color foreColor, + Color backColor, Font font) + { + ListViewSubItem item = new ListViewSubItem (owner, text, + foreColor, backColor, font); + return Add (item); + } + + public void AddRange (ListViewSubItem [] items) + { + if (items == null) + throw new ArgumentNullException ("items"); + + foreach (ListViewSubItem item in items) { + if (item == null) + continue; + AddSubItem (item); + } + owner.Layout (); + owner.Invalidate (); + } + + public void AddRange (string [] items) + { + if (items == null) + throw new ArgumentNullException ("items"); + + foreach (string item in items) { + if (item == null) + continue; + AddSubItem (new ListViewSubItem (owner, item)); + } + owner.Layout (); + owner.Invalidate (); + } + + public void AddRange (string [] items, Color foreColor, + Color backColor, Font font) + { + if (items == null) + throw new ArgumentNullException ("items"); + + foreach (string item in items) { + if (item == null) + continue; + + AddSubItem (new ListViewSubItem (owner, item, foreColor, backColor, font)); + } + owner.Layout (); + owner.Invalidate (); + } + + void AddSubItem (ListViewSubItem subItem) + { + subItem.owner = owner; + list.Add (subItem); + + //UIA Framework + subItem.UIATextChanged += OnUIASubItemTextChanged; + } + + public void Clear () + { + list.Clear (); + } + + public bool Contains (ListViewSubItem subItem) + { + return list.Contains (subItem); + } + + public virtual bool ContainsKey (string key) + { + return IndexOfKey (key) != -1; + } + + public IEnumerator GetEnumerator () + { + return list.GetEnumerator (); + } + + void ICollection.CopyTo (Array dest, int index) + { + list.CopyTo (dest, index); + } + + int IList.Add (object item) + { + if (! (item is ListViewSubItem)) { + throw new ArgumentException ("Not of type ListViewSubItem", "item"); + } + + ListViewSubItem sub_item = (ListViewSubItem) item; + sub_item.owner = this.owner; + //UIA Framework + sub_item.UIATextChanged += OnUIASubItemTextChanged; + return list.Add (sub_item); + } + + bool IList.Contains (object subItem) + { + if (! (subItem is ListViewSubItem)) { + throw new ArgumentException ("Not of type ListViewSubItem", "subItem"); + } + + return this.Contains ((ListViewSubItem) subItem); + } + + int IList.IndexOf (object subItem) + { + if (! (subItem is ListViewSubItem)) { + throw new ArgumentException ("Not of type ListViewSubItem", "subItem"); + } + + return this.IndexOf ((ListViewSubItem) subItem); + } + + void IList.Insert (int index, object item) + { + if (! (item is ListViewSubItem)) { + throw new ArgumentException ("Not of type ListViewSubItem", "item"); + } + + this.Insert (index, (ListViewSubItem) item); + } + + void IList.Remove (object item) + { + if (! (item is ListViewSubItem)) { + throw new ArgumentException ("Not of type ListViewSubItem", "item"); + } + + this.Remove ((ListViewSubItem) item); + } + + public int IndexOf (ListViewSubItem subItem) + { + return list.IndexOf (subItem); + } + + public virtual int IndexOfKey (string key) + { + if (key == null || key.Length == 0) + return -1; + + for (int i = 0; i < list.Count; i++) { + ListViewSubItem l = (ListViewSubItem) list [i]; + if (String.Compare (l.Name, key, true) == 0) + return i; + } + + return -1; + } + + public void Insert (int index, ListViewSubItem item) + { + item.owner = this.owner; + list.Insert (index, item); + owner.Layout (); + owner.Invalidate (); + + //UIA Framework + item.UIATextChanged += OnUIASubItemTextChanged; + } + + public void Remove (ListViewSubItem item) + { + list.Remove (item); + owner.Layout (); + owner.Invalidate (); + + //UIA Framework + item.UIATextChanged -= OnUIASubItemTextChanged; + } + + public virtual void RemoveByKey (string key) + { + int idx = IndexOfKey (key); + if (idx != -1) + RemoveAt (idx); + } + + public void RemoveAt (int index) + { + //UIA Framework + if (index >= 0 && index < list.Count) + ((ListViewSubItem) list [index]).UIATextChanged -= OnUIASubItemTextChanged; + + list.RemoveAt (index); + + } + #endregion // Public Methods + #region UIA Event Handler + + private void OnUIASubItemTextChanged (object sender, EventArgs args) + { + owner.OnUIASubItemTextChanged (new LabelEditEventArgs (list.IndexOf (sender))); + } + + #endregion + + + } + #endregion // Subclasses + } +} diff --git a/source/ShiftUI/Widgets/MonthCalendar.cs b/source/ShiftUI/Widgets/MonthCalendar.cs new file mode 100644 index 0000000..24d7c8f --- /dev/null +++ b/source/ShiftUI/Widgets/MonthCalendar.cs @@ -0,0 +1,2430 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// John BouAntoun jba-mono@optusnet.com.au +// +// REMAINING TODO: +// - get the date_cell_size and title_size to be pixel perfect match of SWF + +using System; +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Threading; + +namespace ShiftUI { + [DefaultBindingProperty("SelectionRange")] + [ClassInterface(ClassInterfaceType.AutoDispatch)] + [ComVisible(true)] + [DefaultProperty("SelectionRange")] + [DefaultEvent("DateChanged")] + //[Designer ("ShiftUI.Design.MonthCalendarDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + public class MonthCalendar : Widget { + #region Local variables + ArrayList annually_bolded_dates; + ArrayList monthly_bolded_dates; + ArrayList bolded_dates; + Size calendar_dimensions; + Day first_day_of_week; + DateTime max_date; + int max_selection_count; + DateTime min_date; + int scroll_change; + SelectionRange selection_range; + bool show_today; + bool show_today_circle; + bool show_week_numbers; + Color title_back_color; + Color title_fore_color; + DateTime today_date; + bool today_date_set; + Color trailing_fore_color; + Timer timer; + Timer updown_timer; + const int initial_delay = 500; + const int subsequent_delay = 100; + private bool is_year_going_up; + private bool is_year_going_down; + private bool is_mouse_moving_year; + private int year_moving_count; + private bool date_selected_event_pending; + bool right_to_left_layout; + + // internal variables used + internal bool show_year_updown; + internal DateTime current_month; // the month that is being displayed in top left corner of the grid + internal DateTimePicker owner; // used if this control is popped up + internal int button_x_offset; + internal Size button_size; + internal Size title_size; + internal Size date_cell_size; + internal Size calendar_spacing; + internal int divider_line_offset; + internal DateTime clicked_date; + internal Rectangle clicked_rect; + internal bool is_date_clicked; + internal bool is_previous_clicked; + internal bool is_next_clicked; + internal bool is_shift_pressed; + internal DateTime first_select_start_date; + internal int last_clicked_calendar_index; + internal Rectangle last_clicked_calendar_rect; + internal Font bold_font; // Cache the font in FontStyle.Bold + internal StringFormat centered_format; // Cache centered string format + private Point month_title_click_location; + // this is used to see which item was actually clicked on in the beginning + // so that we know which item to fire on timer + // 0: date clicked + // 1: previous clicked + // 2: next clicked + private bool[] click_state; + + + + #endregion // Local variables + + #region Public Constructors + + public MonthCalendar () { + // set up the control painting + SetStyle (Widgetstyles.UserPaint | Widgetstyles.StandardClick, false); + + // mouse down timer + timer = new Timer (); + timer.Interval = 500; + timer.Enabled = false; + + // initialise default values + DateTime now = DateTime.Now.Date; + selection_range = new SelectionRange (now, now); + today_date = now; + current_month = new DateTime (now.Year , now.Month, 1); + + // iniatialise local members + annually_bolded_dates = null; + bolded_dates = null; + calendar_dimensions = new Size (1,1); + first_day_of_week = Day.Default; + max_date = new DateTime (9998, 12, 31); + max_selection_count = 7; + min_date = new DateTime (1753, 1, 1); + monthly_bolded_dates = null; + scroll_change = 0; + show_today = true; + show_today_circle = true; + show_week_numbers = false; + title_back_color = ThemeEngine.Current.ColorActiveCaption; + title_fore_color = ThemeEngine.Current.ColorActiveCaptionText; + today_date_set = false; + trailing_fore_color = SystemColors.GrayText; + bold_font = new Font (Font, Font.Style | FontStyle.Bold); + centered_format = new StringFormat (StringFormat.GenericTypographic); + centered_format.FormatFlags = centered_format.FormatFlags | StringFormatFlags.MeasureTrailingSpaces | StringFormatFlags.NoWrap | StringFormatFlags.FitBlackBox; + centered_format.FormatFlags &= ~StringFormatFlags.NoClip; + centered_format.LineAlignment = StringAlignment.Center; + centered_format.Alignment = StringAlignment.Center; + + // Set default values + ForeColor = SystemColors.WindowText; + BackColor = ThemeEngine.Current.ColorWindow; + + // intiailise internal variables used + button_x_offset = 5; + button_size = new Size (22, 17); + // default settings based on 8.25 pt San Serif Font + // Not sure of algorithm used to establish this + date_cell_size = new Size (24, 16); // default size at san-serif 8.25 + divider_line_offset = 4; + calendar_spacing = new Size (4, 5); // horiz and vert spacing between months in a calendar grid + + // set some state info + clicked_date = now; + is_date_clicked = false; + is_previous_clicked = false; + is_next_clicked = false; + is_shift_pressed = false; + click_state = new bool [] {false, false, false}; + first_select_start_date = now; + month_title_click_location = Point.Empty; + + // set up context menus + SetUpTodayMenu (); + SetUpMonthMenu (); + + // event handlers + timer.Tick += new EventHandler (TimerHandler); + MouseMove += new MouseEventHandler (MouseMoveHandler); + MouseDown += new MouseEventHandler (MouseDownHandler); + KeyDown += new KeyEventHandler (KeyDownHandler); + MouseUp += new MouseEventHandler (MouseUpHandler); + KeyUp += new KeyEventHandler (KeyUpHandler); + + // this replaces paint so call the control version + base.Paint += new PaintEventHandler (PaintHandler); + + Size = DefaultSize; + } + + // called when this control is added to date time picker + internal MonthCalendar (DateTimePicker owner) : this () { + this.owner = owner; + this.is_visible = false; + this.Size = this.DefaultSize; + } + + #endregion // Public Constructors + + #region Public Instance Properties + + // dates to make bold on calendar annually (recurring) + [Localizable (true)] + public DateTime [] AnnuallyBoldedDates { + set { + if (annually_bolded_dates == null) + annually_bolded_dates = new ArrayList (value); + else { + annually_bolded_dates.Clear (); + annually_bolded_dates.AddRange (value); + } + + UpdateBoldedDates (); + } + get { + if (annually_bolded_dates == null || annually_bolded_dates.Count == 0) { + return new DateTime [0]; + } + DateTime [] result = new DateTime [annually_bolded_dates.Count]; + annually_bolded_dates.CopyTo (result); + return result; + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override Image BackgroundImage { + get { + return base.BackgroundImage; + } + set { + base.BackgroundImage = value; + } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public override ImageLayout BackgroundImageLayout { + get { + return base.BackgroundImageLayout; + } + set { + base.BackgroundImageLayout = value; + } + } + + // the back color for the main part of the calendar + public override Color BackColor { + set { + base.BackColor = value; + } + get { + return base.BackColor; + } + } + + // specific dates to make bold on calendar (non-recurring) + [Localizable (true)] + public DateTime[] BoldedDates { + set { + if (bolded_dates == null) { + bolded_dates = new ArrayList (value); + } else { + bolded_dates.Clear (); + bolded_dates.AddRange (value); + } + + UpdateBoldedDates (); + } + get { + if (bolded_dates == null || bolded_dates.Count == 0) + return new DateTime [0]; + + DateTime [] result = new DateTime [bolded_dates.Count]; + bolded_dates.CopyTo (result); + return result; + } + } + + // the configuration of the monthly grid display - only allowed to display at most, + // 1 calendar year at a time, will be trimmed to fit it properly + [Localizable (true)] + public Size CalendarDimensions { + set { + if (value.Width < 0 || value.Height < 0) { + throw new ArgumentException (); + } + if (calendar_dimensions != value) { + // squeeze the grid into 1 calendar year + if (value.Width * value.Height > 12) { + // iteratively reduce the largest dimension till our + // product is less than 12 + if (value.Width > 12 && value.Height > 12) { + calendar_dimensions = new Size (4, 3); + } else if (value.Width > 12) { + for (int i = 12; i > 0; i--) { + if (i * value.Height <= 12) { + calendar_dimensions = new Size (i, value.Height); + break; + } + } + } else if (value.Height > 12) { + for (int i = 12; i > 0; i--) { + if (i * value.Width <= 12) { + calendar_dimensions = new Size (value.Width, i); + break; + } + } + } + } else { + calendar_dimensions = value; + } + this.Invalidate (); + } + } + get { + return calendar_dimensions; + } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + protected override bool DoubleBuffered { + get { + return base.DoubleBuffered; + } + set { + base.DoubleBuffered = value; + } + } + + // the first day of the week to display + [Localizable (true)] + [DefaultValue (Day.Default)] + public Day FirstDayOfWeek { + set { + if (first_day_of_week != value) { + first_day_of_week = value; + this.Invalidate (); + } + } + get { + return first_day_of_week; + } + } + + // the fore color for the main part of the calendar + public override Color ForeColor { + set { + base.ForeColor = value; + } + get { + return base.ForeColor; + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new ImeMode ImeMode { + get { return base.ImeMode; } + set { base.ImeMode = value; } + } + + // the maximum date allowed to be selected on this month calendar + public DateTime MaxDate { + set { + if (value < MinDate) { + string msg = string.Format (CultureInfo.CurrentCulture, + "Value of '{0}' is not valid for 'MaxDate'. 'MaxDate' " + + "must be greater than or equal to MinDate.", + value.ToString ("d", CultureInfo.CurrentCulture)); + throw new ArgumentOutOfRangeException ("MaxDate", + msg); + } + + if (max_date == value) + return; + + max_date = value; + + if (max_date < selection_range.Start || max_date < selection_range.End) { + DateTime start = max_date < selection_range.Start ? max_date : selection_range.Start; + DateTime end = max_date < selection_range.End ? max_date : selection_range.End; + SelectionRange = new SelectionRange (start, end); + } + } + get { + return max_date; + } + } + + // the maximum number of selectable days + [DefaultValue (7)] + public int MaxSelectionCount { + set { + if (value < 1) { + string msg = string.Format (CultureInfo.CurrentCulture, + "Value of '{0}' is not valid for 'MaxSelectionCount'. " + + "'MaxSelectionCount' must be greater than or equal to {1}.", + value, 1); + throw new ArgumentOutOfRangeException ("MaxSelectionCount", + msg); + } + + // can't set selectioncount less than already selected dates + if ((SelectionEnd - SelectionStart).Days > value) { + throw new ArgumentException(); + } + + if (max_selection_count != value) { + max_selection_count = value; + this.OnUIAMaxSelectionCountChanged (); + } + } + get { + return max_selection_count; + } + } + + // the minimum date allowed to be selected on this month calendar + public DateTime MinDate { + set { + DateTime absoluteMinDate = new DateTime (1753, 1, 1); + + if (value < absoluteMinDate) { + string msg = string.Format (CultureInfo.CurrentCulture, + "Value of '{0}' is not valid for 'MinDate'. 'MinDate' " + + "must be greater than or equal to {1}.", + value.ToString ("d", CultureInfo.CurrentCulture), + absoluteMinDate.ToString ("d", CultureInfo.CurrentCulture)); + throw new ArgumentOutOfRangeException ("MinDate", + msg); + } + + if (value > MaxDate) { + string msg = string.Format (CultureInfo.CurrentCulture, + "Value of '{0}' is not valid for 'MinDate'. 'MinDate' " + + "must be less than MaxDate.", + value.ToString ("d", CultureInfo.CurrentCulture)); + throw new ArgumentOutOfRangeException ("MinDate", + msg); + } + + if (min_date == value) + return; + + min_date = value; + + if (min_date > selection_range.Start || min_date > selection_range.End) { + DateTime start = min_date > selection_range.Start ? min_date : selection_range.Start; + DateTime end = min_date > selection_range.End ? min_date : selection_range.End; + SelectionRange = new SelectionRange (start, end); + } + } + get { + return min_date; + } + } + + // dates to make bold on calendar monthly (recurring) + [Localizable (true)] + public DateTime[] MonthlyBoldedDates { + set { + if (monthly_bolded_dates == null) { + monthly_bolded_dates = new ArrayList (value); + } else { + monthly_bolded_dates.Clear (); + monthly_bolded_dates.AddRange (value); + } + + UpdateBoldedDates (); + } + get { + if (monthly_bolded_dates == null || monthly_bolded_dates.Count == 0) + return new DateTime [0]; + + DateTime [] result = new DateTime [monthly_bolded_dates.Count]; + monthly_bolded_dates.CopyTo (result); + return result; + } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + [Browsable (false)] + // Padding should not have any effect on the appearance of MonthCalendar. + public new Padding Padding { + get { + return base.Padding; + } + set { + base.Padding = value; + } + } + + [DefaultValue (false)] + [Localizable (true)] + public virtual bool RightToLeftLayout { + get { + return right_to_left_layout; + } + set { + right_to_left_layout = value; + } + } + + // the ammount by which to scroll this calendar by + [DefaultValue (0)] + public int ScrollChange { + set { + if (value < 0 || value > 20000) { + throw new ArgumentException(); + } + + if (scroll_change != value) { + scroll_change = value; + } + } + get { + return scroll_change; + } + } + + + // the last selected date + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public DateTime SelectionEnd { + set { + if (value < MinDate || value > MaxDate) { + throw new ArgumentException(); + } + + if (SelectionRange.End != value) { + DateTime old_end = SelectionRange.End; + // make sure the end obeys the max selection range count + if (value < SelectionRange.Start) { + SelectionRange.Start = value; + } + if (value.AddDays((MaxSelectionCount-1)*-1) > SelectionRange.Start) { + SelectionRange.Start = value.AddDays((MaxSelectionCount-1)*-1); + } + SelectionRange.End = value; + this.InvalidateDateRange (new SelectionRange (old_end, SelectionRange.End)); + this.OnDateChanged (new DateRangeEventArgs (SelectionStart, SelectionEnd)); + this.OnUIASelectionChanged (); + } + } + get { + return SelectionRange.End; + } + } + + [Bindable(true)] + // the range of selected dates + public SelectionRange SelectionRange { + set { + if (selection_range != value) { + if (value.Start < MinDate) + throw new ArgumentException ("SelectionStart cannot be less than MinDate"); + else if (value.End > MaxDate) + throw new ArgumentException ("SelectionEnd cannot be greated than MaxDate"); + + SelectionRange old_range = selection_range; + + // make sure the end obeys the max selection range count + if (value.End.AddDays((MaxSelectionCount-1)*-1) > value.Start) { + selection_range = new SelectionRange (value.End.AddDays((MaxSelectionCount-1)*-1), value.End); + } else { + selection_range = value; + } + SelectionRange visible_range = this.GetDisplayRange(true); + if(visible_range.Start > selection_range.End) { + this.current_month = new DateTime (selection_range.Start.Year, selection_range.Start.Month, 1); + this.Invalidate (); + } else if (visible_range.End < selection_range.Start) { + int year_diff = selection_range.End.Year - visible_range.End.Year; + int month_diff = selection_range.End.Month - visible_range.End.Month; + this.current_month = current_month.AddMonths(year_diff * 12 + month_diff); + this.Invalidate (); + } + // invalidate the selected range changes + DateTime diff_start = old_range.Start; + DateTime diff_end = old_range.End; + // now decide which region is greated + if (old_range.Start > SelectionRange.Start) { + diff_start = SelectionRange.Start; + } else if (old_range.Start == SelectionRange.Start) { + if (old_range.End < SelectionRange.End) { + diff_start = old_range.End; + } else { + diff_start = SelectionRange.End; + } + } + if (old_range.End < SelectionRange.End) { + diff_end = SelectionRange.End; + } else if (old_range.End == SelectionRange.End) { + if (old_range.Start < SelectionRange.Start) { + diff_end = SelectionRange.Start; + } else { + diff_end = old_range.Start; + } + } + + + // invalidate the region required + SelectionRange new_range = new SelectionRange (diff_start, diff_end); + if (new_range.End != old_range.End || new_range.Start != old_range.Start) + this.InvalidateDateRange (new_range); + // raise date changed event + this.OnDateChanged (new DateRangeEventArgs (SelectionStart, SelectionEnd)); + this.OnUIASelectionChanged (); + } + } + get { + return selection_range; + } + } + + // the first selected date + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public DateTime SelectionStart { + set { + if (value < MinDate || value > MaxDate) { + throw new ArgumentException(); + } + + if (SelectionRange.Start != value) { + // make sure the end obeys the max selection range count + if (value > SelectionRange.End) { + SelectionRange.End = value; + } else if (value.AddDays(MaxSelectionCount-1) < SelectionRange.End) { + SelectionRange.End = value.AddDays(MaxSelectionCount-1); + } + SelectionRange.Start = value; + DateTime new_month = new DateTime(value.Year, value.Month, 1); + if (current_month != new_month) + current_month = new_month; + + this.Invalidate (); + this.OnDateChanged (new DateRangeEventArgs (SelectionStart, SelectionEnd)); + this.OnUIASelectionChanged (); + } + } + get { + return selection_range.Start; + } + } + + // whether or not to show todays date + [DefaultValue (true)] + public bool ShowToday { + set { + if (show_today != value) { + show_today = value; + this.Invalidate (); + } + } + get { + return show_today; + } + } + + // whether or not to show a circle around todays date + [DefaultValue (true)] + public bool ShowTodayCircle { + set { + if (show_today_circle != value) { + show_today_circle = value; + this.Invalidate (); + } + } + get { + return show_today_circle; + } + } + + // whether or not to show numbers beside each row of weeks + [Localizable (true)] + [DefaultValue (false)] + public bool ShowWeekNumbers { + set { + if (show_week_numbers != value) { + show_week_numbers = value; + // The values here don't matter, SetBoundsCore will calculate its own + SetBoundsCore (Left, Top, Width, Height, BoundsSpecified.Width); + this.Invalidate (); + } + } + get { + return show_week_numbers; + } + } + + // the rectangle size required to render one month based on current font + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public Size SingleMonthSize { + get { + if (this.Font == null) { + throw new InvalidOperationException(); + } + + // multiplier is sucked out from the font size + int multiplier = this.Font.Height; + + // establis how many columns and rows we have + int column_count = (ShowWeekNumbers) ? 8 : 7; + int row_count = 7; // not including the today date + + // set the date_cell_size and the title_size + date_cell_size = new Size ((int) Math.Ceiling (1.8 * multiplier), multiplier); + title_size = new Size ((date_cell_size.Width * column_count), 2 * multiplier); + + return new Size (column_count * date_cell_size.Width, row_count * date_cell_size.Height + title_size.Height); + } + } + + [Localizable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public new Size Size { + get { + return base.Size; + } + set { + base.Size = value; + } + } + + [Bindable(false)] + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override string Text { + get { + return base.Text; + } + set { + base.Text = value; + } + } + + // the back color for the title of the calendar and the + // forecolor for the day of the week text + public Color TitleBackColor { + set { + if (title_back_color != value) { + title_back_color = value; + this.Invalidate (); + } + } + get { + return title_back_color; + } + } + + // the fore color for the title of the calendar + public Color TitleForeColor { + set { + if (title_fore_color != value) { + title_fore_color = value; + this.Invalidate (); + } + } + get { + return title_fore_color; + } + } + + // the date this calendar is using to refer to today's date + public DateTime TodayDate { + set { + today_date_set = true; + if (today_date != value) { + today_date = value; + this.Invalidate (); + } + } + get { + return today_date; + } + } + + // tells if user specifically set today_date for this control + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public bool TodayDateSet { + get { + return today_date_set; + } + } + + // the color used for trailing dates in the calendar + public Color TrailingForeColor { + set { + if (trailing_fore_color != value) { + trailing_fore_color = value; + SelectionRange bounds = this.GetDisplayRange (false); + SelectionRange visible_bounds = this.GetDisplayRange (true); + this.InvalidateDateRange (new SelectionRange (bounds.Start, visible_bounds.Start)); + this.InvalidateDateRange (new SelectionRange (bounds.End, visible_bounds.End)); + } + } + get { + return trailing_fore_color; + } + } + + #endregion // Public Instance Properties + + #region Protected Instance Properties + + // overloaded to allow controll to be windowed for drop down + protected override CreateParams CreateParams { + get { + if (this.owner == null) { + return base.CreateParams; + } else { + CreateParams cp = base.CreateParams; + cp.Style ^= (int) WindowStyles.WS_CHILD; + cp.Style |= (int) WindowStyles.WS_POPUP; + cp.ExStyle |= (int)(WindowExStyles.WS_EX_TOOLWINDOW | WindowExStyles.WS_EX_TOPMOST); + + return cp; + } + } + } + + // not sure what to put in here - just doing a base() call - jba + protected override ImeMode DefaultImeMode { + get { + return base.DefaultImeMode; + } + } + + protected override Padding DefaultMargin { + get { + return new Padding (9); + } + } + + protected override Size DefaultSize { + get { + Size single_month = SingleMonthSize; + // get the width + int width = calendar_dimensions.Width * single_month.Width; + if (calendar_dimensions.Width > 1) { + width += (calendar_dimensions.Width - 1) * calendar_spacing.Width; + } + + // get the height + int height = calendar_dimensions.Height * single_month.Height; + if (this.ShowToday) { + height += date_cell_size.Height + 2; // add the height of the "Today: " ... + } + if (calendar_dimensions.Height > 1) { + height += (calendar_dimensions.Height - 1) * calendar_spacing.Height; + } + + // add the 1 pixel boundary + if (width > 0) { + width += 2; + } + if (height > 0) { + height +=2; + } + + return new Size (width, height); + } + } + + #endregion // Protected Instance Properties + + #region Public Instance Methods + + // add a date to the anually bolded date arraylist + public void AddAnnuallyBoldedDate (DateTime date) { + if (annually_bolded_dates == null) + annually_bolded_dates = new ArrayList (); + if (!annually_bolded_dates.Contains (date)) + annually_bolded_dates.Add (date); + } + + // add a date to the normal bolded date arraylist + public void AddBoldedDate (DateTime date) { + if (bolded_dates == null) + bolded_dates = new ArrayList (); + if (!bolded_dates.Contains (date)) + bolded_dates.Add (date); + } + + // add a date to the anually monthly date arraylist + public void AddMonthlyBoldedDate (DateTime date) { + if (monthly_bolded_dates == null) + monthly_bolded_dates = new ArrayList (); + if (!monthly_bolded_dates.Contains (date)) + monthly_bolded_dates.Add (date); + } + + // if visible = true, return only the dates of full months, else return all dates visible + public SelectionRange GetDisplayRange (bool visible) { + DateTime start; + DateTime end; + start = new DateTime (current_month.Year, current_month.Month, 1); + end = start.AddMonths (calendar_dimensions.Width * calendar_dimensions.Height); + end = end.AddDays(-1); + + // process all visible dates if needed (including the grayed out dates + if (!visible) { + start = GetFirstDateInMonthGrid (start); + end = GetLastDateInMonthGrid (end); + } + + return new SelectionRange (start, end); + } + + // HitTest overload that recieve's x and y co-ordinates as separate ints + public HitTestInfo HitTest (int x, int y) { + return HitTest (new Point (x, y)); + } + + // returns a HitTestInfo for MonthCalendar element's under the specified point + public HitTestInfo HitTest (Point point) { + return HitTest (point, out last_clicked_calendar_index, out last_clicked_calendar_rect); + } + + // clears all the annually bolded dates + public void RemoveAllAnnuallyBoldedDates () { + if (annually_bolded_dates != null) + annually_bolded_dates.Clear (); + } + + // clears all the normal bolded dates + public void RemoveAllBoldedDates () { + if (bolded_dates != null) + bolded_dates.Clear (); + } + + // clears all the monthly bolded dates + public void RemoveAllMonthlyBoldedDates () { + if (monthly_bolded_dates != null) + monthly_bolded_dates.Clear (); + } + + // clears the specified annually bolded date (only compares day and month) + // only removes the first instance of the match + public void RemoveAnnuallyBoldedDate (DateTime date) { + if (annually_bolded_dates == null) + return; + + for (int i = 0; i < annually_bolded_dates.Count; i++) { + DateTime dt = (DateTime) annually_bolded_dates [i]; + if (dt.Day == date.Day && dt.Month == date.Month) { + annually_bolded_dates.RemoveAt (i); + return; + } + } + } + + // clears all the normal bolded date + // only removes the first instance of the match + public void RemoveBoldedDate (DateTime date) { + if (bolded_dates == null) + return; + + for (int i = 0; i < bolded_dates.Count; i++) { + DateTime dt = (DateTime) bolded_dates [i]; + if (dt.Year == date.Year && dt.Month == date.Month && dt.Day == date.Day) { + bolded_dates.RemoveAt (i); + return; + } + } + } + + // clears the specified monthly bolded date (only compares day and month) + // only removes the first instance of the match + public void RemoveMonthlyBoldedDate (DateTime date) { + if (monthly_bolded_dates == null) + return; + + for (int i = 0; i < monthly_bolded_dates.Count; i++) { + DateTime dt = (DateTime) monthly_bolded_dates [i]; + if (dt.Day == date.Day && dt.Month == date.Month) { + monthly_bolded_dates.RemoveAt (i); + return; + } + } + } + + // sets the calendar_dimensions. If product is > 12, the larger dimension is reduced to make product < 12 + public void SetCalendarDimensions(int x, int y) { + this.CalendarDimensions = new Size(x, y); + } + + // sets the currently selected date as date + public void SetDate (DateTime date) { + this.SetSelectionRange (date.Date, date.Date); + } + + // utility method set the SelectionRange property using individual dates + public void SetSelectionRange (DateTime date1, DateTime date2) { + this.SelectionRange = new SelectionRange(date1, date2); + } + + public override string ToString () { + return this.GetType().Name + ", " + this.SelectionRange.ToString (); + } + + // usually called after an AddBoldedDate method is called + // formats monthly and daily bolded dates according to the current calendar year + public void UpdateBoldedDates () { + Invalidate (); + } + + #endregion // Public Instance Methods + + #region Protected Instance Methods + + // not sure why this needs to be overriden + protected override void CreateHandle () { + base.CreateHandle (); + } + + // not sure why this needs to be overriden + protected override void Dispose (bool disposing) { + base.Dispose (disposing); + } + + // Handle arrow keys + protected override bool IsInputKey (Keys keyData) { + switch (keyData) { + case Keys.Up: + case Keys.Down: + case Keys.Right: + case Keys.Left: + return true; + default: + break; + } + + return base.IsInputKey (keyData); + } + + // not sure why this needs to be overriden + protected override void OnBackColorChanged (EventArgs e) { + base.OnBackColorChanged (e); + this.Invalidate (); + } + + // raises the date changed event + protected virtual void OnDateChanged (DateRangeEventArgs drevent) { + DateRangeEventHandler eh = (DateRangeEventHandler) (Events [DateChangedEvent]); + if (eh != null) + eh (this, drevent); + } + + // raises the DateSelected event + protected virtual void OnDateSelected (DateRangeEventArgs drevent) { + DateRangeEventHandler eh = (DateRangeEventHandler) (Events [DateSelectedEvent]); + if (eh != null) + eh (this, drevent); + } + + protected override void OnFontChanged (EventArgs e) { + // Update size based on new font's space requirements + Size = new Size (CalendarDimensions.Width * SingleMonthSize.Width, + CalendarDimensions.Height * SingleMonthSize.Height); + bold_font = new Font (Font, Font.Style | FontStyle.Bold); + base.OnFontChanged (e); + } + + protected override void OnForeColorChanged (EventArgs e) { + base.OnForeColorChanged (e); + } + + protected override void OnHandleCreated (EventArgs e) { + base.OnHandleCreated (e); + } + + protected override void OnHandleDestroyed (EventArgs e) + { + base.OnHandleDestroyed (e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnRightToLeftLayoutChanged (EventArgs e) { + EventHandler eh = (EventHandler) (Events [RightToLeftLayoutChangedEvent]); + if (eh != null) + eh (this, e); + } + + // i think this is overriden to not allow the control to be changed to an arbitrary size + protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified) + { + // only allow sizes = default size to be set + Size default_size = DefaultSize; + Size min_size = default_size; + Size max_size = new Size (default_size.Width + SingleMonthSize.Width + calendar_spacing.Width, + default_size.Height + SingleMonthSize.Height + calendar_spacing.Height); + int x_mid_point = (max_size.Width + min_size.Width)/2; + int y_mid_point = (max_size.Height + min_size.Height)/2; + + if (width < x_mid_point) { + width = min_size.Width; + } else { + width = max_size.Width; + } + if (height < y_mid_point) { + height = min_size.Height; + } else { + height = max_size.Height; + } + base.SetBoundsCore (x, y, width, height, specified); + } + + protected override void WndProc (ref Message m) { + base.WndProc (ref m); + } + + #endregion // Protected Instance Methods + + #region public events + static object DateChangedEvent = new object (); + static object DateSelectedEvent = new object (); + static object RightToLeftLayoutChangedEvent = new object (); + + // fired when the date is changed (either explicitely or implicitely) + // when navigating the month selector + public event DateRangeEventHandler DateChanged { + add { Events.AddHandler (DateChangedEvent, value); } + remove { Events.RemoveHandler (DateChangedEvent, value); } + } + + // fired when the user explicitely clicks on date to select it + public event DateRangeEventHandler DateSelected { + add { Events.AddHandler (DateSelectedEvent, value); } + remove { Events.RemoveHandler (DateSelectedEvent, value); } + } + + [Browsable(false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageChanged { + add { base.BackgroundImageChanged += value; } + remove { base.BackgroundImageChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageLayoutChanged + { + add { base.BackgroundImageLayoutChanged += value;} + remove { base.BackgroundImageLayoutChanged += value;} + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler Click { + add {base.Click += value; } + remove {base.Click -= value;} + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler DoubleClick { + add {base.DoubleClick += value; } + remove {base.DoubleClick -= value; } + } + + [Browsable(false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler ImeModeChanged { + add { base.ImeModeChanged += value; } + remove { base.ImeModeChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event MouseEventHandler MouseClick { + add { base.MouseClick += value;} + remove { base.MouseClick -= value;} + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event MouseEventHandler MouseDoubleClick { + add { base.MouseDoubleClick += value; } + remove { base.MouseDoubleClick -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler PaddingChanged { + add {base.PaddingChanged += value;} + remove {base.PaddingChanged -= value;} + } + + // XXX check this out + [Browsable(false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event PaintEventHandler Paint; + + public event EventHandler RightToLeftLayoutChanged { + add {Events.AddHandler (RightToLeftLayoutChangedEvent, value);} + remove {Events.RemoveHandler (RightToLeftLayoutChangedEvent, value);} + } + + [Browsable(false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + #endregion // public events + + #region internal properties + + private void AddYears (int years, bool fast) + { + DateTime newDate; + if (fast) { + if (!(CurrentMonth.Year + years * 5 > MaxDate.Year)) { + newDate = CurrentMonth.AddYears (years * 5); + if (MaxDate >= newDate && MinDate <= newDate) { + CurrentMonth = newDate; + return; + } + } + } + if (!(CurrentMonth.Year + years > MaxDate.Year)) { + newDate = CurrentMonth.AddYears (years); + if (MaxDate >= newDate && MinDate <= newDate) { + CurrentMonth = newDate; + } + } + } + + internal bool IsYearGoingUp { + get { + return is_year_going_up; + } + set { + if (value) { + is_year_going_down = false; + year_moving_count = (is_year_going_up ? year_moving_count + 1 : 1); + if (is_year_going_up) + year_moving_count++; + else { + year_moving_count = 1; + } + AddYears (1, year_moving_count > 10); + if (is_mouse_moving_year) + StartHideTimer (); + } else { + year_moving_count = 0; + } + is_year_going_up = value; + Invalidate (); + } + } + + internal bool IsYearGoingDown { + get { + return is_year_going_down; + } + set + { + if (value) { + is_year_going_up = false; + year_moving_count = (is_year_going_down ? year_moving_count + 1 : 1); + if (is_year_going_down) + year_moving_count++; + else { + year_moving_count = 1; + } + AddYears (-1, year_moving_count > 10); + if (is_mouse_moving_year) + StartHideTimer (); + } else { + year_moving_count = 0; + } + is_year_going_down = value; + Invalidate (); + } + } + + internal bool ShowYearUpDown { + get { + return show_year_updown; + } + set { + if (show_year_updown != value) { + show_year_updown = value; + Invalidate (); + } + } + } + + internal DateTime CurrentMonth { + set { + // only interested in if the month (not actual date) has change + if (value < MinDate || value > MaxDate) { + return; + } + + if (value.Month != current_month.Month || + value.Year != current_month.Year) { + this.SelectionRange = new SelectionRange( + this.SelectionStart.Add(value.Subtract(current_month)), + this.SelectionEnd.Add(value.Subtract(current_month))); + current_month = value; + UpdateBoldedDates(); + this.Invalidate(); + } + } + get { + return current_month; + } + } + + #endregion // internal properties + + #region internal/private methods + internal HitTestInfo HitTest ( + Point point, + out int calendar_index, + out Rectangle calendar_rect) { + // start by initialising the ref parameters + calendar_index = -1; + calendar_rect = Rectangle.Empty; + + // before doing all the hard work, see if the today's date wasn't clicked + Rectangle today_rect = new Rectangle ( + ClientRectangle.X, + ClientRectangle.Bottom - date_cell_size.Height, + 7 * date_cell_size.Width, + date_cell_size.Height); + if (today_rect.Contains (point) && this.ShowToday) { + return new HitTestInfo(HitArea.TodayLink, point, DateTime.Now); + } + + Size month_size = SingleMonthSize; + // define calendar rect's that this thing can land in + Rectangle[] calendars = new Rectangle [CalendarDimensions.Width * CalendarDimensions.Height]; + for (int i=0; i < CalendarDimensions.Width * CalendarDimensions.Height; i ++) { + if (i == 0) { + calendars[i] = new Rectangle ( + new Point (ClientRectangle.X + 1, ClientRectangle.Y + 1), + month_size); + } else { + // calendar on the next row + if (i % CalendarDimensions.Width == 0) { + calendars[i] = new Rectangle ( + new Point (calendars[i-CalendarDimensions.Width].X, calendars[i-CalendarDimensions.Width].Bottom + calendar_spacing.Height), + month_size); + } else { + // calendar on the next column + calendars[i] = new Rectangle ( + new Point (calendars[i-1].Right + calendar_spacing.Width, calendars[i-1].Y), + month_size); + } + } + } + + // through each trying to find a match + for (int i = 0; i < calendars.Length ; i++) { + if (calendars[i].Contains (point)) { + // check the title section + Rectangle title_rect = new Rectangle ( + calendars[i].Location, + title_size); + if (title_rect.Contains (point) ) { + // make sure it's not a previous button + if (i == 0) { + Rectangle button_rect = new Rectangle( + new Point (calendars[i].X + button_x_offset, (title_size.Height - button_size.Height)/2), + button_size); + if (button_rect.Contains (point)) { + return new HitTestInfo (HitArea.PrevMonthButton, point, new DateTime (1, 1, 1)); + } + } + // make sure it's not the next button + if (i % CalendarDimensions.Height == 0 && i % CalendarDimensions.Width == calendar_dimensions.Width - 1) { + Rectangle button_rect = new Rectangle( + new Point (calendars[i].Right - button_x_offset - button_size.Width, (title_size.Height - button_size.Height)/2), + button_size); + if (button_rect.Contains (point)) { + return new HitTestInfo (HitArea.NextMonthButton, point, new DateTime (1, 1, 1)); + } + } + + // indicate which calendar and month it was + calendar_index = i; + calendar_rect = calendars[i]; + + // make sure it's not the month or the year of the calendar + if (GetMonthNameRectangle (title_rect, i).Contains (point)) { + return new HitTestInfo (HitArea.TitleMonth, point, new DateTime (1, 1, 1)); + } + Rectangle year, up, down; + GetYearNameRectangles (title_rect, i, out year, out up, out down); + if (year.Contains (point)) { + return new HitTestInfo (HitArea.TitleYear, point, new DateTime (1, 1, 1), HitAreaExtra.YearRectangle); + } else if (up.Contains (point)) { + return new HitTestInfo (HitArea.TitleYear, point, new DateTime (1, 1, 1), HitAreaExtra.UpButton); + } else if (down.Contains (point)) { + return new HitTestInfo (HitArea.TitleYear, point, new DateTime (1, 1, 1), HitAreaExtra.DownButton); + } + + // return the hit test in the title background + return new HitTestInfo (HitArea.TitleBackground, point, new DateTime (1, 1, 1)); + } + + Point date_grid_location = new Point (calendars[i].X, title_rect.Bottom); + + // see if it's in the Week numbers + if (ShowWeekNumbers) { + Rectangle weeks_rect = new Rectangle ( + date_grid_location, + new Size (date_cell_size.Width,Math.Max (calendars[i].Height - title_rect.Height, 0))); + if (weeks_rect.Contains (point)) { + return new HitTestInfo(HitArea.WeekNumbers, point, DateTime.Now); + } + + // move the location of the grid over + date_grid_location.X += date_cell_size.Width; + } + + // see if it's in the week names + Rectangle day_rect = new Rectangle ( + date_grid_location, + new Size (Math.Max (calendars[i].Right - date_grid_location.X, 0), date_cell_size.Height)); + if (day_rect.Contains (point)) { + return new HitTestInfo (HitArea.DayOfWeek, point, new DateTime (1, 1, 1)); + } + + // finally see if it was a date that was clicked + Rectangle date_grid = new Rectangle ( + new Point (day_rect.X, day_rect.Bottom), + new Size (day_rect.Width, Math.Max(calendars[i].Bottom - day_rect.Bottom, 0))); + if (date_grid.Contains (point)) { + clicked_rect = date_grid; + // okay so it's inside the grid, get the offset + Point offset = new Point (point.X - date_grid.X, point.Y - date_grid.Y); + int row = offset.Y / date_cell_size.Height; + int col = offset.X / date_cell_size.Width; + // establish our first day of the month + DateTime calendar_month = this.CurrentMonth.AddMonths(i); + DateTime first_day = GetFirstDateInMonthGrid (calendar_month); + DateTime time = first_day.AddDays ((row * 7) + col); + // establish which date was clicked + if (time.Year != calendar_month.Year || time.Month != calendar_month.Month) { + if (time < calendar_month && i == 0) { + return new HitTestInfo (HitArea.PrevMonthDate, point, new DateTime (1, 1, 1), time); + } else if (time > calendar_month && i == CalendarDimensions.Width*CalendarDimensions.Height - 1) { + return new HitTestInfo (HitArea.NextMonthDate, point, new DateTime (1, 1, 1), time); + } + return new HitTestInfo (HitArea.Nowhere, point, new DateTime (1, 1, 1)); + } + return new HitTestInfo(HitArea.Date, point, time); + } + } + } + + return new HitTestInfo (); + } + + // returns the date of the first cell of the specified month grid + internal DateTime GetFirstDateInMonthGrid (DateTime month) { + // convert the first_day_of_week into a DayOfWeekEnum + DayOfWeek first_day = GetDayOfWeek (first_day_of_week); + // find the first day of the month + DateTime first_date_of_month = new DateTime (month.Year, month.Month, 1); + DayOfWeek first_day_of_month = first_date_of_month.DayOfWeek; + // adjust for the starting day of the week + int offset = first_day_of_month - first_day; + if (offset < 0) { + offset += 7; + } + return first_date_of_month.AddDays (-1*offset); + } + + // returns the date of the last cell of the specified month grid + internal DateTime GetLastDateInMonthGrid (DateTime month) + { + DateTime start = GetFirstDateInMonthGrid(month); + return start.AddDays ((7 * 6)-1); + } + + internal bool IsBoldedDate (DateTime date) { + // check bolded dates + if (bolded_dates != null && bolded_dates.Count > 0) { + foreach (DateTime bolded_date in bolded_dates) { + if (bolded_date.Date == date.Date) { + return true; + } + } + } + // check monthly dates + if (monthly_bolded_dates != null && monthly_bolded_dates.Count > 0) { + foreach (DateTime bolded_date in monthly_bolded_dates) { + if (bolded_date.Day == date.Day) { + return true; + } + } + } + // check yearly dates + if (annually_bolded_dates != null && annually_bolded_dates.Count > 0) { + foreach (DateTime bolded_date in annually_bolded_dates) { + if (bolded_date.Month == date.Month && bolded_date.Day == date.Day) { + return true; + } + } + } + + return false; // no match + } + + // initialise the 'go to today' context menu + private void SetUpTodayMenu () { + } + + // initialise the month context menu + private void SetUpMonthMenu () { + + } + + // returns the first date of the month + private DateTime GetFirstDateInMonth (DateTime date) { + return new DateTime (date.Year, date.Month, 1); + } + + // returns the last date of the month + private DateTime GetLastDateInMonth (DateTime date) { + return new DateTime (date.Year, date.Month, 1).AddMonths(1).AddDays(-1); + } + + // called in response to users seletion with shift key + private void AddTimeToSelection (int delta, bool isDays) + { + DateTime cursor_point; + DateTime end_point; + // okay we add the period to the date that is not the same as the + // start date when shift was first clicked. + if (SelectionStart != first_select_start_date) { + cursor_point = SelectionStart; + } else { + cursor_point = SelectionEnd; + } + // add the days + if (isDays) { + end_point = cursor_point.AddDays (delta); + } else { + // delta must be months + end_point = cursor_point.AddMonths (delta); + } + // set the new selection range + SelectionRange range = new SelectionRange (first_select_start_date, end_point); + if (range.Start.AddDays (MaxSelectionCount-1) < range.End) { + // okay the date is beyond what is allowed, lets set the maximum we can + if (range.Start != first_select_start_date) { + range.Start = range.End.AddDays ((MaxSelectionCount-1)*-1); + } else { + range.End = range.Start.AddDays (MaxSelectionCount-1); + } + } + + // Avoid re-setting SelectionRange to the same value and fire an extra DateChanged event + if (range.Start != selection_range.Start || range.End != selection_range.End) + SelectionRange = range; + } + + // attempts to add the date to the selection without throwing exception + private void SelectDate (DateTime date) { + // try and add the new date to the selction range + SelectionRange range = null; + if (is_shift_pressed || (click_state [0])) { + range = new SelectionRange (first_select_start_date, date); + if (range.Start.AddDays (MaxSelectionCount-1) < range.End) { + // okay the date is beyond what is allowed, lets set the maximum we can + if (range.Start != first_select_start_date) { + range.Start = range.End.AddDays ((MaxSelectionCount-1)*-1); + } else { + range.End = range.Start.AddDays (MaxSelectionCount-1); + } + } + } else { + if (date >= MinDate && date <= MaxDate) { + range = new SelectionRange (date, date); + first_select_start_date = date; + } + } + + // Only set if we re actually getting a different range (avoid an extra DateChanged event) + if (range != null && range.Start != selection_range.Start || range.End != selection_range.End) + SelectionRange = range; + } + + // gets the week of the year + internal int GetWeekOfYear (DateTime date) { + // convert the first_day_of_week into a DayOfWeekEnum + DayOfWeek first_day = GetDayOfWeek (first_day_of_week); + // find the first day of the year + DayOfWeek first_day_of_year = new DateTime (date.Year, 1, 1).DayOfWeek; + // adjust for the starting day of the week + int offset = first_day_of_year - first_day; + int week = ((date.DayOfYear + offset) / 7) + 1; + return week; + } + + // convert a Day enum into a DayOfWeek enum + internal DayOfWeek GetDayOfWeek (Day day) { + if (day == Day.Default) { + return Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek; + } else { + return (DayOfWeek) DayOfWeek.Parse (typeof (DayOfWeek), day.ToString ()); + } + } + + // returns the rectangle for themonth name + internal Rectangle GetMonthNameRectangle (Rectangle title_rect, int calendar_index) { + DateTime this_month = this.current_month.AddMonths (calendar_index); + Size title_text_size = TextRenderer.MeasureString (this_month.ToString ("MMMM yyyy"), this.Font).ToSize (); + Size month_size = TextRenderer.MeasureString (this_month.ToString ("MMMM"), this.Font).ToSize (); + // return only the month name part of that + return new Rectangle ( + new Point ( + title_rect.X + ((title_rect.Width - title_text_size.Width)/2), + title_rect.Y + ((title_rect.Height - title_text_size.Height)/2)), + month_size); + } + + internal void GetYearNameRectangles (Rectangle title_rect, int calendar_index, out Rectangle year_rect, out Rectangle up_rect, out Rectangle down_rect) + { + DateTime this_month = this.current_month.AddMonths (calendar_index); + SizeF title_text_size = TextRenderer.MeasureString (this_month.ToString ("MMMM yyyy"), this.bold_font, int.MaxValue, centered_format); + SizeF year_size = TextRenderer.MeasureString (this_month.ToString ("yyyy"), this.bold_font, int.MaxValue, centered_format); + // find out how much space the title took + RectangleF text_rect = new RectangleF ( + new PointF ( + title_rect.X + ((title_rect.Width - title_text_size.Width) / 2), + title_rect.Y + ((title_rect.Height - title_text_size.Height) / 2)), + title_text_size); + // return only the rect of the year + year_rect = new Rectangle ( + new Point ( + ((int)(text_rect.Right - year_size.Width + 1)), + (int)text_rect.Y), + new Size ((int)(year_size.Width + 1), (int)(year_size.Height + 1))); + + year_rect.Inflate (0, 1); + up_rect = new Rectangle (); + up_rect.Location = new Point (year_rect.X + year_rect.Width + 2, year_rect.Y); + up_rect.Size = new Size (16, year_rect.Height / 2); + down_rect = new Rectangle (); + down_rect.Location = new Point (up_rect.X, up_rect.Y + up_rect.Height + 1); + down_rect.Size = up_rect.Size; + } + + // returns the rectangle for the year in the title + internal Rectangle GetYearNameRectangle (Rectangle title_rect, int calendar_index) { + Rectangle result, discard; + GetYearNameRectangles (title_rect, calendar_index, out result, out discard, out discard); + return result; + } + + // determine if date is allowed to be drawn in month + internal bool IsValidWeekToDraw (DateTime month, DateTime date, int row, int col) { + DateTime tocheck = month.AddMonths (-1); + if ((month.Year == date.Year && month.Month == date.Month) || + (tocheck.Year == date.Year && tocheck.Month == date.Month)) { + return true; + } + + // check the railing dates (days in the month after the last month in grid) + if (row == CalendarDimensions.Height - 1 && col == CalendarDimensions.Width - 1) { + tocheck = month.AddMonths (1); + return (tocheck.Year == date.Year && tocheck.Month == date.Month) ; + } + + return false; + } + + // set one item clicked and all others off + private void SetItemClick(HitTestInfo hti) + { + switch(hti.HitArea) { + case HitArea.NextMonthButton: + this.is_previous_clicked = false; + this.is_next_clicked = true; + this.is_date_clicked = false; + break; + case HitArea.PrevMonthButton: + this.is_previous_clicked = true; + this.is_next_clicked = false; + this.is_date_clicked = false; + break; + case HitArea.PrevMonthDate: + case HitArea.NextMonthDate: + case HitArea.Date: + this.clicked_date = hti.hit_time; + this.is_previous_clicked = false; + this.is_next_clicked = false; + this.is_date_clicked = true; + break; + default : + this.is_previous_clicked = false; + this.is_next_clicked = false; + this.is_date_clicked = false; + break; + } + } + + // called when today context menu is clicked + private void TodayMenuItemClickHandler (object sender, EventArgs e) + { + this.SetSelectionRange (DateTime.Now.Date, DateTime.Now.Date); + this.OnDateSelected (new DateRangeEventArgs (SelectionStart, SelectionEnd)); + } + + // called when month context menu is clicked + private void MonthMenuItemClickHandler (object sender, EventArgs e) { + MenuItem item = sender as MenuItem; + if (item != null && month_title_click_location != Point.Empty) { + // establish which month we want to move to + if (item.Parent == null) { + return; + } + int new_month = item.Parent.MenuItems.IndexOf (item) + 1; + if (new_month == 0) { + return; + } + // okay let's establish which calendar was hit + Size month_size = this.SingleMonthSize; + for (int i=0; i < CalendarDimensions.Height; i++) { + for (int j=0; j < CalendarDimensions.Width; j++) { + int month_index = (i * CalendarDimensions.Width) + j; + Rectangle month_rect = new Rectangle ( new Point (0, 0), month_size); + if (j == 0) { + month_rect.X = this.ClientRectangle.X + 1; + } else { + month_rect.X = this.ClientRectangle.X + 1 + ((j)*(month_size.Width+calendar_spacing.Width)); + } + if (i == 0) { + month_rect.Y = this.ClientRectangle.Y + 1; + } else { + month_rect.Y = this.ClientRectangle.Y + 1 + ((i)*(month_size.Height+calendar_spacing.Height)); + } + // see if the point is inside + if (month_rect.Contains (month_title_click_location)) { + DateTime clicked_month = CurrentMonth.AddMonths (month_index); + // get the month that we want to move to + int month_offset = new_month - clicked_month.Month; + + // move forward however more months we need to + this.CurrentMonth = this.CurrentMonth.AddMonths (month_offset); + break; + } + } + } + + // clear the point + month_title_click_location = Point.Empty; + } + } + + // raised on the timer, for mouse hold clicks + private void TimerHandler (object sender, EventArgs e) { + // now find out which area was click + if (this.Capture) { + HitTestInfo hti = this.HitTest (this.PointToClient (MousePosition)); + // see if it was clicked on the prev or next mouse + if (click_state [1] || click_state [2]) { + // invalidate the area where the mouse was last held + DoMouseUp (); + // register the click + if (hti.HitArea == HitArea.PrevMonthButton || + hti.HitArea == HitArea.NextMonthButton) { + DoButtonMouseDown (hti); + click_state [1] = (hti.HitArea == HitArea.PrevMonthButton); + click_state [2] = !click_state [1]; + } + if (timer.Interval != 300) { + timer.Interval = 300; + } + } + } else { + timer.Enabled = false; + } + } + + // selects one of the buttons + private void DoButtonMouseDown (HitTestInfo hti) { + // show the click then move on + SetItemClick(hti); + if (hti.HitArea == HitArea.PrevMonthButton) { + // invalidate the prev monthbutton + this.Invalidate( + new Rectangle ( + this.ClientRectangle.X + 1 + button_x_offset, + this.ClientRectangle.Y + 1 + (title_size.Height - button_size.Height)/2, + button_size.Width, + button_size.Height)); + int scroll = (scroll_change == 0 ? CalendarDimensions.Width * CalendarDimensions.Height : scroll_change); + this.CurrentMonth = this.CurrentMonth.AddMonths (-scroll); + } else { + // invalidate the next monthbutton + this.Invalidate( + new Rectangle ( + this.ClientRectangle.Right - 1 - button_x_offset - button_size.Width, + this.ClientRectangle.Y + 1 + (title_size.Height - button_size.Height)/2, + button_size.Width, + button_size.Height)); + int scroll = (scroll_change == 0 ? CalendarDimensions.Width * CalendarDimensions.Height : scroll_change); + this.CurrentMonth = this.CurrentMonth.AddMonths (scroll); + } + } + + // selects the clicked date + private void DoDateMouseDown (HitTestInfo hti) { + SetItemClick(hti); + } + + // event run on the mouse up event + private void DoMouseUp () { + + IsYearGoingDown = false; + IsYearGoingUp = false; + is_mouse_moving_year = false; + + // invalidate the next monthbutton + if (this.is_next_clicked) { + this.Invalidate( + new Rectangle ( + this.ClientRectangle.Right - 1 - button_x_offset - button_size.Width, + this.ClientRectangle.Y + 1 + (title_size.Height - button_size.Height)/2, + button_size.Width, + button_size.Height)); + } + // invalidate the prev monthbutton + if (this.is_previous_clicked) { + this.Invalidate( + new Rectangle ( + this.ClientRectangle.X + 1 + button_x_offset, + this.ClientRectangle.Y + 1 + (title_size.Height - button_size.Height)/2, + button_size.Width, + button_size.Height)); + } + if (this.is_date_clicked) { + // invalidate the area under the cursor, to remove focus rect + this.InvalidateDateRange (new SelectionRange (clicked_date, clicked_date)); + } + this.is_previous_clicked = false; + this.is_next_clicked = false; + this.is_date_clicked = false; + } + + // needed when in windowed mode to close the calendar if no + // part of it has focus. + private void UpDownTimerTick(object sender, EventArgs e) + { + if (IsYearGoingUp) { + IsYearGoingUp = true; + } + if (IsYearGoingDown) { + IsYearGoingDown = true; + } + + if (!IsYearGoingDown && !IsYearGoingUp) { + updown_timer.Enabled = false; + } else if (IsYearGoingDown || IsYearGoingUp) { + updown_timer.Interval = subsequent_delay; + } + } + + // Needed when in windowed mode. + private void StartHideTimer () + { + if (updown_timer == null) { + updown_timer = new Timer (); + updown_timer.Tick += new EventHandler (UpDownTimerTick); + } + updown_timer.Interval = initial_delay; + updown_timer.Enabled = true; + } + + // occurs when mouse moves around control, used for selection + private void MouseMoveHandler (object sender, MouseEventArgs e) { + HitTestInfo hti = this.HitTest (e.X, e.Y); + // clear the last clicked item + if (click_state [0]) { + // register the click + if (hti.HitArea == HitArea.PrevMonthDate || + hti.HitArea == HitArea.NextMonthDate || + hti.HitArea == HitArea.Date) + { + Rectangle prev_rect = clicked_rect; + DateTime prev_clicked = clicked_date; + DoDateMouseDown (hti); + if (owner == null) { + click_state [0] = true; + } else { + click_state [0] = false; + click_state [1] = false; + click_state [2] = false; + } + + if (prev_clicked != clicked_date) { + // select date after updating click_state and clicked_date + SelectDate (clicked_date); + date_selected_event_pending = true; + + Rectangle invalid = Rectangle.Union (prev_rect, clicked_rect); + Invalidate (invalid); + } + } + + } + } + + // to check if the mouse has come down on this control + private void MouseDownHandler (object sender, MouseEventArgs e) + { + if ((e.Button & MouseButtons.Left) == 0) + return; + + // clear the click_state variables + click_state [0] = false; + click_state [1] = false; + click_state [2] = false; + + // disable the timer if it was enabled + if (timer.Enabled) { + timer.Stop (); + timer.Enabled = false; + } + + Point point = new Point (e.X, e.Y); + // figure out if we are in drop down mode and a click happened outside us + if (this.owner != null) { + if (!this.ClientRectangle.Contains (point)) { + this.owner.HideMonthCalendar (); + return; + } + } + + //establish where was hit + HitTestInfo hti = this.HitTest(point); + // hide the year numeric up down if it was clicked + if (ShowYearUpDown && hti.HitArea != HitArea.TitleYear) { + ShowYearUpDown = false; + } + switch (hti.HitArea) { + case HitArea.PrevMonthButton: + case HitArea.NextMonthButton: + DoButtonMouseDown (hti); + click_state [1] = (hti.HitArea == HitArea.PrevMonthDate); + click_state [2] = !click_state [1]; + timer.Interval = 750; + timer.Start (); + break; + case HitArea.Date: + case HitArea.PrevMonthDate: + case HitArea.NextMonthDate: + DoDateMouseDown (hti); + + // select date before updating click_state + SelectDate (clicked_date); + date_selected_event_pending = true; + + // leave clicked state blank if drop down window + if (owner == null) { + click_state [0] = true; + } else { + click_state [0] = false; + click_state [1] = false; + click_state [2] = false; + } + + break; + case HitArea.TitleMonth: + month_title_click_location = hti.Point; + if (this.Capture && owner != null) { + Capture = false; + Capture = true; + } + break; + case HitArea.TitleYear: + // place the numeric up down + if (ShowYearUpDown) { + if (hti.hit_area_extra == HitAreaExtra.UpButton) { + is_mouse_moving_year = true; + IsYearGoingUp = true; + } else if (hti.hit_area_extra == HitAreaExtra.DownButton) { + is_mouse_moving_year = true; + IsYearGoingDown = true; + } + return; + } else { + ShowYearUpDown = true; + } + break; + case HitArea.TodayLink: + this.SetSelectionRange (DateTime.Now.Date, DateTime.Now.Date); + this.OnDateSelected (new DateRangeEventArgs (SelectionStart, SelectionEnd)); + break; + default: + this.is_previous_clicked = false; + this.is_next_clicked = false; + this.is_date_clicked = false; + break; + } + } + + // raised by any key down events + private void KeyDownHandler (object sender, KeyEventArgs e) { + // send keys to the year_updown control, let it handle it + if(ShowYearUpDown) { + switch (e.KeyCode) { + case Keys.Enter: + ShowYearUpDown = false; + IsYearGoingDown = false; + IsYearGoingUp = false; + break; + case Keys.Up: { + IsYearGoingUp = true; + break; + } + case Keys.Down: { + IsYearGoingDown = true; + break; + } + } + } else { + if (!is_shift_pressed && e.Shift) { + first_select_start_date = SelectionStart; + is_shift_pressed = e.Shift; + e.Handled = true; + } + switch (e.KeyCode) { + case Keys.Home: + // set the date to the start of the month + if (is_shift_pressed) { + DateTime date = GetFirstDateInMonth (first_select_start_date); + if (date < first_select_start_date.AddDays ((MaxSelectionCount-1)*-1)) { + date = first_select_start_date.AddDays ((MaxSelectionCount-1)*-1); + } + this.SetSelectionRange (date, first_select_start_date); + } else { + DateTime date = GetFirstDateInMonth (this.SelectionStart); + this.SetSelectionRange (date, date); + } + e.Handled = true; + break; + case Keys.End: + // set the date to the last of the month + if (is_shift_pressed) { + DateTime date = GetLastDateInMonth (first_select_start_date); + if (date > first_select_start_date.AddDays (MaxSelectionCount-1)) { + date = first_select_start_date.AddDays (MaxSelectionCount-1); + } + this.SetSelectionRange (date, first_select_start_date); + } else { + DateTime date = GetLastDateInMonth (this.SelectionStart); + this.SetSelectionRange (date, date); + } + e.Handled = true; + break; + case Keys.PageUp: + // set the date to the last of the month + if (is_shift_pressed) { + this.AddTimeToSelection (-1, false); + } else { + DateTime date = this.SelectionStart.AddMonths (-1); + this.SetSelectionRange (date, date); + } + e.Handled = true; + break; + case Keys.PageDown: + // set the date to the last of the month + if (is_shift_pressed) { + this.AddTimeToSelection (1, false); + } else { + DateTime date = this.SelectionStart.AddMonths (1); + this.SetSelectionRange (date, date); + } + e.Handled = true; + break; + case Keys.Up: + // set the back 1 week + if (is_shift_pressed) { + this.AddTimeToSelection (-7, true); + } else { + DateTime date = this.SelectionStart.AddDays (-7); + this.SetSelectionRange (date, date); + } + e.Handled = true; + break; + case Keys.Down: + // set the date forward 1 week + if (is_shift_pressed) { + this.AddTimeToSelection (7, true); + } else { + DateTime date = this.SelectionStart.AddDays (7); + this.SetSelectionRange (date, date); + } + e.Handled = true; + break; + case Keys.Left: + // move one left + if (is_shift_pressed) { + this.AddTimeToSelection (-1, true); + } else { + DateTime date = this.SelectionStart.AddDays (-1); + this.SetSelectionRange (date, date); + } + e.Handled = true; + break; + case Keys.Right: + // move one left + if (is_shift_pressed) { + this.AddTimeToSelection (1, true); + } else { + DateTime date = this.SelectionStart.AddDays (1); + this.SetSelectionRange (date, date); + } + e.Handled = true; + break; + case Keys.F4: + // Close ourselves on Alt-F4 if we are a popup + if (e.Alt && owner != null) { + this.Hide (); + e.Handled = true; + } + break; + default: + break; + } + } + } + + // to check if the mouse has come up on this control + private void MouseUpHandler (object sender, MouseEventArgs e) + { + if ((e.Button & MouseButtons.Left) == 0) { + return; + } + + if (timer.Enabled) { + timer.Stop (); + } + // clear the click state array + click_state [0] = false; + click_state [1] = false; + click_state [2] = false; + // do the regulare mouseup stuff + this.DoMouseUp (); + + if (date_selected_event_pending) { + OnDateSelected (new DateRangeEventArgs (SelectionStart, SelectionEnd)); + date_selected_event_pending = false; + } + } + + // raised by any key up events + private void KeyUpHandler (object sender, KeyEventArgs e) { + is_shift_pressed = e.Shift ; + e.Handled = true; + IsYearGoingUp = false; + IsYearGoingDown = false; + } + + // paint this control now + private void PaintHandler (object sender, PaintEventArgs pe) { + if (Width <= 0 || Height <= 0 || Visible == false) + return; + + Draw (pe.ClipRectangle, pe.Graphics); + + // fire the new paint handler + if (this.Paint != null) + { + this.Paint (sender, pe); + } + } + + // returns the region of the control that needs to be redrawn + private void InvalidateDateRange (SelectionRange range) { + SelectionRange bounds = this.GetDisplayRange (false); + + if (range.End < bounds.Start || range.Start > bounds.End) { + // don't invalidate anything, as the modified date range + // is outside the visible bounds of this control + return; + } + // adjust the start and end to be inside the visible range + if (range.Start < bounds.Start) { + range = new SelectionRange (bounds.Start, range.End); + } + if (range.End > bounds.End) { + range = new SelectionRange (range.Start, bounds.End); + } + // now invalidate the date rectangles as series of rows + DateTime last_month = this.current_month.AddMonths ((CalendarDimensions.Width * CalendarDimensions.Height)).AddDays (-1); + DateTime current = range.Start; + while (current <= range.End) { + DateTime month_end = new DateTime (current.Year, current.Month, 1).AddMonths (1).AddDays (-1);; + Rectangle start_rect; + Rectangle end_rect; + // see if entire selection is in this current month + if (range.End <= month_end && current < last_month) { + // the end is the last date + if (current < this.current_month) { + start_rect = GetDateRowRect (current_month, current_month); + } else { + start_rect = GetDateRowRect (current, current); + } + end_rect = GetDateRowRect (current, range.End); + } else if (current < last_month) { + // otherwise it simply means we have a selection spaning + // multiple months simply set rectangle inside the current month + start_rect = GetDateRowRect (current, current); + end_rect = GetDateRowRect (month_end, month_end); + } else { + // it's outside the visible range + start_rect = GetDateRowRect (last_month, last_month.AddDays (1)); + end_rect = GetDateRowRect (last_month, range.End); + } + // push to the next month + current = month_end.AddDays (1); + // invalidate from the start row to the end row for this month + this.Invalidate ( + new Rectangle ( + start_rect.X, + start_rect.Y, + start_rect.Width, + Math.Max (end_rect.Bottom - start_rect.Y, 0))); + } + } + + // gets the rect of the row where the specified date appears on the specified month + private Rectangle GetDateRowRect (DateTime month, DateTime date) { + // first get the general rect of the supplied month + Size month_size = SingleMonthSize; + Rectangle month_rect = Rectangle.Empty; + for (int i=0; i < CalendarDimensions.Width*CalendarDimensions.Height; i++) { + DateTime this_month = this.current_month.AddMonths (i); + if (month.Year == this_month.Year && month.Month == this_month.Month) { + month_rect = new Rectangle ( + this.ClientRectangle.X + 1 + (month_size.Width * (i%CalendarDimensions.Width)) + (this.calendar_spacing.Width * (i%CalendarDimensions.Width)), + this.ClientRectangle.Y + 1 + (month_size.Height * (i/CalendarDimensions.Width)) + (this.calendar_spacing.Height * (i/CalendarDimensions.Width)), + month_size.Width, + month_size.Height); + break; + } + } + // now find out where in the month the supplied date is + if (month_rect == Rectangle.Empty) { + return Rectangle.Empty; + } + // find out which row this date is in + int row = -1; + DateTime first_date = GetFirstDateInMonthGrid (month); + DateTime end_date = first_date.AddDays (7); + for (int i=0; i < 6; i++) { + if (date >= first_date && date < end_date) { + row = i; + break; + } + first_date = end_date; + end_date = end_date.AddDays (7); + } + // ensure it's a valid row + if (row < 0) { + return Rectangle.Empty; + } + int x_offset = (this.ShowWeekNumbers) ? date_cell_size.Width : 0; + int y_offset = title_size.Height + (date_cell_size.Height * (row + 1)); + return new Rectangle ( + month_rect.X + x_offset, + month_rect.Y + y_offset, + date_cell_size.Width * 7, + date_cell_size.Height); + } + + internal void Draw (Rectangle clip_rect, Graphics dc) + { + ThemeEngine.Current.DrawMonthCalendar (dc, clip_rect, this); + } + + internal override bool InternalCapture { + get { + return base.InternalCapture; + } + set { + // Don't allow internal capture when DateTimePicker is using us + // Widget sets this on MouseDown + if (owner == null) + base.InternalCapture = value; + } + } + + #endregion //internal methods + + #region internal drawing methods + + + #endregion // internal drawing methods + + #region inner classes and enumerations + + // enumeration about what type of area on the calendar was hit + public enum HitArea { + Nowhere, + TitleBackground, + TitleMonth, + TitleYear, + NextMonthButton, + PrevMonthButton, + CalendarBackground, + Date, + NextMonthDate, + PrevMonthDate, + DayOfWeek, + WeekNumbers, + TodayLink + } + + internal enum HitAreaExtra { + YearRectangle, + UpButton, + DownButton + } + + // info regarding to a hit test on this calendar + public sealed class HitTestInfo { + + private HitArea hit_area; + private Point point; + private DateTime time; + + internal HitAreaExtra hit_area_extra; + internal DateTime hit_time; + + // default constructor + internal HitTestInfo () { + hit_area = HitArea.Nowhere; + point = new Point (0, 0); + time = DateTime.Now; + } + + // overload receives all properties + internal HitTestInfo (HitArea hit_area, Point point, DateTime time) { + this.hit_area = hit_area; + this.point = point; + this.time = time; + this.hit_time = time; + } + + // overload receives all properties + internal HitTestInfo (HitArea hit_area, Point point, DateTime time, DateTime hit_time) + { + this.hit_area = hit_area; + this.point = point; + this.time = time; + this.hit_time = hit_time; + } + + internal HitTestInfo (HitArea hit_area, Point point, DateTime time, HitAreaExtra hit_area_extra) + { + this.hit_area = hit_area; + this.hit_area_extra = hit_area_extra; + this.point = point; + this.time = time; + } + + // the type of area that was hit + public HitArea HitArea { + get { + return hit_area; + } + } + + // the point that is being test + public Point Point { + get { + return point; + } + } + + // the date under the hit test point, only valid if HitArea is Date + public DateTime Time { + get { + return time; + } + } + } + + #endregion // inner classes + + #region UIA Framework: Methods, Properties and Events + + static object UIAMaxSelectionCountChangedEvent = new object (); + static object UIASelectionChangedEvent = new object (); + + internal event EventHandler UIAMaxSelectionCountChanged { + add { Events.AddHandler (UIAMaxSelectionCountChangedEvent, value); } + remove { Events.RemoveHandler (UIAMaxSelectionCountChangedEvent, value); } + } + + internal event EventHandler UIASelectionChanged { + add { Events.AddHandler (UIASelectionChangedEvent, value); } + remove { Events.RemoveHandler (UIASelectionChangedEvent, value); } + } + + private void OnUIAMaxSelectionCountChanged () + { + EventHandler eh = (EventHandler) Events [UIAMaxSelectionCountChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + + private void OnUIASelectionChanged () + { + EventHandler eh = (EventHandler) Events [UIASelectionChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + + #endregion + } +} diff --git a/source/ShiftUI/Widgets/NotifyIcon.cs b/source/ShiftUI/Widgets/NotifyIcon.cs new file mode 100644 index 0000000..c30006a --- /dev/null +++ b/source/ShiftUI/Widgets/NotifyIcon.cs @@ -0,0 +1,753 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Drawing.Text; + +namespace ShiftUI { + [DefaultProperty("Text")] + [DefaultEvent("MouseDoubleClick")] + //[Designer ("ShiftUI.Design.NotifyIconDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [ToolboxItemFilter("ShiftUI", ToolboxItemFilterType.Allow)] + public sealed class NotifyIcon : Component { + #region Local Variables + private Icon icon; + private Bitmap icon_bitmap; + private string text; + private bool visible; + private NotifyIconWindow window; + private bool systray_active; + private ToolTip tooltip; + private bool double_click; + private string balloon_text; + private string balloon_title; + private ToolTipIcon balloon_icon; + private ContextMenuStrip context_menu_strip; + private object tag; + #endregion // Local Variables + + #region NotifyIconWindow Class + internal class NotifyIconWindow : Form { + NotifyIcon owner; + Rectangle rect; + + public NotifyIconWindow(NotifyIcon owner) { + this.owner = owner; + is_visible = false; + rect = new Rectangle(0, 0, 1, 1); + + FormBorderStyle = FormBorderStyle.None; + + //CreateControl(); + + SizeChanged += new EventHandler(HandleSizeChanged); + + // Events that need to be sent to our parent + DoubleClick += new EventHandler(HandleDoubleClick); + MouseDown +=new MouseEventHandler(HandleMouseDown); + MouseUp +=new MouseEventHandler(HandleMouseUp); + MouseMove +=new MouseEventHandler(HandleMouseMove); + ContextMenuStrip = owner.context_menu_strip; + } + + protected override CreateParams CreateParams { + get { + CreateParams cp; + + cp = base.CreateParams; + + cp.Parent = IntPtr.Zero; + cp.Style = (int)WindowStyles.WS_POPUP; + cp.Style |= (int)WindowStyles.WS_CLIPSIBLINGS; + + cp.ExStyle = (int)(WindowExStyles.WS_EX_TOOLWINDOW); + + return cp; + } + } + + protected override void WndProc(ref Message m) { + switch((Msg)m.Msg) { + // + // NotifyIcon does CONTEXTMENU on mouse up, not down + // so we swallow the message here, and handle it on our own + // + case Msg.WM_CONTEXTMENU: + return; + + case Msg.WM_USER: { + switch ((Msg)m.LParam.ToInt32()) { + case Msg.WM_LBUTTONDOWN: { + owner.OnMouseDown (new MouseEventArgs(MouseButtons.Left, 1, Widget.MousePosition.X, Widget.MousePosition.Y, 0)); + return; + } + + case Msg.WM_LBUTTONUP: { + owner.OnMouseUp (new MouseEventArgs(MouseButtons.Left, 1, Widget.MousePosition.X, Widget.MousePosition.Y, 0)); + return; + } + + case Msg.WM_LBUTTONDBLCLK: { + owner.OnDoubleClick (EventArgs.Empty); + owner.OnMouseDoubleClick (new MouseEventArgs (MouseButtons.Left, 2, Widget.MousePosition.X, Widget.MousePosition.Y, 0)); + return; + } + + case Msg.WM_MOUSEMOVE: { + owner.OnMouseMove (new MouseEventArgs(MouseButtons.None, 1, Widget.MousePosition.X, Widget.MousePosition.Y, 0)); + return; + } + + case Msg.WM_RBUTTONDOWN: { + owner.OnMouseDown (new MouseEventArgs(MouseButtons.Right, 1, Widget.MousePosition.X, Widget.MousePosition.Y, 0)); + return; + } + + case Msg.WM_RBUTTONUP: { + owner.OnMouseUp (new MouseEventArgs(MouseButtons.Right, 1, Widget.MousePosition.X, Widget.MousePosition.Y, 0)); + return; + } + + case Msg.WM_RBUTTONDBLCLK: { + owner.OnDoubleClick (EventArgs.Empty); + owner.OnMouseDoubleClick (new MouseEventArgs (MouseButtons.Left, 2, Widget.MousePosition.X, Widget.MousePosition.Y, 0)); + return; + } + + case Msg.NIN_BALLOONUSERCLICK: { + owner.OnBalloonTipClicked (EventArgs.Empty); + return; + } + + case Msg.NIN_BALLOONSHOW: { + owner.OnBalloonTipShown (EventArgs.Empty); + return; + } + + case Msg.NIN_BALLOONHIDE: + case Msg.NIN_BALLOONTIMEOUT: { + owner.OnBalloonTipClosed (EventArgs.Empty); + return; + } + } + return; + } + } + base.WndProc (ref m); + } + + internal void CalculateIconRect() { + int x; + int y; + int size; + + // Icons are always square. Try to center them in the window + if (ClientRectangle.Width < ClientRectangle.Height) { + size = ClientRectangle.Width; + } else { + size = ClientRectangle.Height; + } + x = this.ClientRectangle.Width / 2 - size / 2; + y = this.ClientRectangle.Height / 2 - size / 2; + rect = new Rectangle(x, y, size, size); + + Bounds = new Rectangle (0, 0, size, size); + } + + internal override void OnPaintInternal (PaintEventArgs e) { + if (owner.icon != null) { + // At least in Gnome, the background of the panel is the same as the Menu, so we go for it + // instead of (most of the time) plain white. + e.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(SystemColors.Menu), rect); + e.Graphics.DrawImage(owner.icon_bitmap, + rect, + new Rectangle (0, 0, owner.icon_bitmap.Width, owner.icon_bitmap.Height), + GraphicsUnit.Pixel); + + } + } + + internal void InternalRecreateHandle () { + base.RecreateHandle (); + } + + private void HandleSizeChanged(object sender, EventArgs e) { + owner.Recalculate (); + } + + private void HandleDoubleClick (object sender, EventArgs e) + { + owner.OnDoubleClick (e); + owner.OnMouseDoubleClick (new MouseEventArgs (MouseButtons.Left, 2, Widget.MousePosition.X, Widget.MousePosition.Y, 0)); + } + + private void HandleMouseDown (object sender, MouseEventArgs e) + { + owner.OnMouseDown (e); + } + + private void HandleMouseUp (object sender, MouseEventArgs e) + { + owner.OnMouseUp (e); + } + + private void HandleMouseMove (object sender, MouseEventArgs e) + { + owner.OnMouseMove (e); + } + } + #endregion // NotifyIconWindow Class + + #region NotifyIconBalloonWindow Class + internal class BalloonWindow : Form + { + private IntPtr owner; + private Timer timer; + + private string title; + private string text; + private ToolTipIcon icon; + + public BalloonWindow (IntPtr owner) + { + this.owner = owner; + + StartPosition = FormStartPosition.Manual; + FormBorderStyle = FormBorderStyle.None; + + MouseDown += new MouseEventHandler (HandleMouseDown); + + timer = new Timer (); + timer.Enabled = false; + timer.Tick += new EventHandler (HandleTimer); + } + + public IntPtr OwnerHandle { + get { + return owner; + } + } + + protected override void Dispose (bool disposing) + { + if (disposing) { + timer.Stop(); + timer.Dispose(); + } + base.Dispose (disposing); + } + + protected override CreateParams CreateParams { + get { + CreateParams cp; + + cp = base.CreateParams; + + cp.Style = (int)WindowStyles.WS_POPUP; + cp.Style |= (int)WindowStyles.WS_CLIPSIBLINGS; + + cp.ExStyle = (int)(WindowExStyles.WS_EX_TOOLWINDOW | WindowExStyles.WS_EX_TOPMOST); + + return cp; + } + } + + public new void Close () { + base.Close (); + XplatUI.SendMessage (owner, Msg.WM_USER, IntPtr.Zero, (IntPtr) Msg.NIN_BALLOONHIDE); + } + + protected override void OnShown (EventArgs e) + { + base.OnShown (e); + timer.Start (); + } + + protected override void OnPaint (PaintEventArgs e) + { + ThemeEngine.Current.DrawBalloonWindow (e.Graphics, ClientRectangle, this); + base.OnPaint (e); + } + + private void Recalculate () + { + Rectangle rect = ThemeEngine.Current.BalloonWindowRect (this); + + Left = rect.Left; + Top = rect.Top; + Width = rect.Width; + Height = rect.Height; + } + + // To be used when we have a "close button" inside balloon. + //private void HandleClick (object sender, EventArgs e) + //{ + // Close (); + //} + + private void HandleMouseDown (object sender, MouseEventArgs e) + { + XplatUI.SendMessage (owner, Msg.WM_USER, IntPtr.Zero, (IntPtr) Msg.NIN_BALLOONUSERCLICK); + base.Close (); + } + + private void HandleTimer (object sender, EventArgs e) + { + timer.Stop (); + XplatUI.SendMessage (owner, Msg.WM_USER, IntPtr.Zero, (IntPtr) Msg.NIN_BALLOONTIMEOUT); + base.Close (); + } + + internal StringFormat Format { + get { + StringFormat format = new StringFormat (); + format.Alignment = StringAlignment.Near; + format.HotkeyPrefix = HotkeyPrefix.Hide; + + return format; + } + } + + public new ToolTipIcon Icon { + get { return this.icon; } + set { + if (value == this.icon) + return; + + this.icon = value; + Recalculate (); + } + } + + public string Title { + get { return this.title; } + set { + if (value == this.title) + return; + + this.title = value; + Recalculate (); + } + } + + public override string Text { + get { return this.text; } + set { + if (value == this.text) + return; + + this.text = value; + Recalculate (); + } + } + + public int Timeout { + get { return timer.Interval; } + set { + // Some systems theres a limitiation in timeout, WinXP is between 10k and 30k. + if (value < 10000) + timer.Interval = 10000; + else if (value > 30000) + timer.Interval = 30000; + else + timer.Interval = value; + } + } + } + #endregion // NotifyIconBalloonWindow Class + + #region Public Constructors + public NotifyIcon() { + window = new NotifyIconWindow(this); + systray_active = false; + + balloon_title = ""; + balloon_text = ""; + } + + public NotifyIcon(System.ComponentModel.IContainer container) : this() { + } + #endregion // Public Constructors + + #region Public Methods + public void ShowBalloonTip (int timeout) + { + ShowBalloonTip(timeout, balloon_title, balloon_text, balloon_icon); + } + + public void ShowBalloonTip(int timeout, string tipTitle, string tipText, ToolTipIcon tipIcon) + { + XplatUI.SystrayBalloon(window.Handle, timeout, tipTitle, tipText, tipIcon); + } + #endregion Public Methods + + #region Private Methods + private void OnBalloonTipClicked (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [BalloonTipClickedEvent]); + if (eh != null) + eh (this, e); + } + + private void OnBalloonTipClosed (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [BalloonTipClosedEvent]); + if (eh != null) + eh (this, e); + } + + private void OnBalloonTipShown (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [BalloonTipShownEvent]); + if (eh != null) + eh (this, e); + } + + private void OnClick (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [ClickEvent]); + if (eh != null) + eh (this, e); + } + + private void OnDoubleClick (EventArgs e) + { + double_click = true; + EventHandler eh = (EventHandler)(Events [DoubleClickEvent]); + if (eh != null) + eh (this, e); + } + + private void OnMouseClick (MouseEventArgs e) + { + MouseEventHandler eh = (MouseEventHandler)(Events[MouseClickEvent]); + if (eh != null) + eh (this, e); + } + + private void OnMouseDoubleClick (MouseEventArgs e) + { + MouseEventHandler eh = (MouseEventHandler)(Events[MouseDoubleClickEvent]); + if (eh != null) + eh (this, e); + } + + private void OnMouseDown (MouseEventArgs e) + { + MouseEventHandler eh = (MouseEventHandler)(Events [MouseDownEvent]); + if (eh != null) + eh (this, e); + } + + private void OnMouseUp (MouseEventArgs e) + { + if ((e.Button & MouseButtons.Right) == MouseButtons.Right) { + if (context_menu_strip != null) { + XplatUI.SetForegroundWindow (window.Handle); + context_menu_strip.Show (window, new Point (e.X, e.Y), ToolStripDropDownDirection.AboveLeft); + } + } + + MouseEventHandler eh = (MouseEventHandler)(Events [MouseUpEvent]); + if (eh != null) + eh (this, e); + + if (!double_click) { + OnClick (EventArgs.Empty); + OnMouseClick (e); + double_click = false; + } + } + + private void OnMouseMove (MouseEventArgs e) + { + MouseEventHandler eh = (MouseEventHandler)(Events [MouseMoveEvent]); + if (eh != null) + eh (this, e); + } + + private void Recalculate () + { + window.CalculateIconRect (); + + if (!Visible || (text == string.Empty && icon == null)) { + HideSystray (); + } else { + + if (systray_active) + UpdateSystray (); + else + ShowSystray (); + } + } + + private void ShowSystray() + { + if (icon == null) + return; + + icon_bitmap = icon.ToBitmap(); + + systray_active = true; + XplatUI.SystrayAdd(window.Handle, text, icon, out tooltip); + } + + private void HideSystray() + { + if (!systray_active) { + return; + } + + systray_active = false; + XplatUI.SystrayRemove(window.Handle, ref tooltip); + } + + private void UpdateSystray() + { + if (icon_bitmap != null) { + icon_bitmap.Dispose(); + } + + if (icon != null) { + icon_bitmap = icon.ToBitmap(); + } + + window.Invalidate(); + XplatUI.SystrayChange(window.Handle, text, icon, ref tooltip); + } + #endregion // Private Methods + + #region Public Instance Properties + [DefaultValue ("None")] + public ToolTipIcon BalloonTipIcon { + get { return this.balloon_icon; } + set { + if (value == this.balloon_icon) + return; + + this.balloon_icon = value; + } + } + + [Localizable(true)] + [DefaultValue ("")] + //[Editor ("System.ComponentModel.Design.MultilineStringEditor, " + Consts.AssemblySystem_Design, + //"System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)] + public string BalloonTipText { + get { return this.balloon_text; } + set { + if (value == this.balloon_text) + return; + + this.balloon_text = value; + } + } + + [Localizable(true)] + [DefaultValue ("")] + public string BalloonTipTitle { + get { return this.balloon_title; } + set { + if (value == this.balloon_title) + return; + + this.balloon_title = value; + } + } + + + + [DefaultValue (null)] + public ContextMenuStrip ContextMenuStrip { + get { return this.context_menu_strip; } + set { + if (this.context_menu_strip != value) { + this.context_menu_strip = value; + window.ContextMenuStrip = value; + } + } + } + + [Localizable(true)] + [DefaultValue(null)] + public Icon Icon { + get { + return icon; + } + + set { + if (icon != value) { + icon = value; + Recalculate (); + } + } + } + + [Localizable (false)] + [Bindable (true)] + [TypeConverter (typeof (StringConverter))] + [DefaultValue (null)] + public object Tag { + get { return this.tag; } + set { this.tag = value; } + } + + [DefaultValue ("")] + //[Editor ("System.ComponentModel.Design.MultilineStringEditor, " + Consts.AssemblySystem_Design, + // typeof (System.Drawing.Design.UITypeEditor))] + [Localizable (true)] + public string Text { + get { + return text; + } + + set { + if (text != value) { + if (value.Length >= 64) { + throw new ArgumentException("ToolTip length must be less than 64 characters long", "Text"); + } + text = value; + Recalculate (); + } + } + } + + [Localizable(true)] + [DefaultValue(false)] + public bool Visible { + get { + return visible; + } + + set { + if (visible != value) { + visible = value; + + // Let our control know, too + window.is_visible = value; + + if (visible) { + ShowSystray (); + } else { + HideSystray(); + } + } + } + } + #endregion // Public Instance Properties + + #region Protected Instance Methods + protected override void Dispose(bool disposing) { + if (visible) + HideSystray(); + + if (icon_bitmap != null) { + icon_bitmap.Dispose(); + } + + if (disposing) + icon = null; + + base.Dispose (disposing); + } + + #endregion // Protected Instance Methods + + #region Events + static object ClickEvent = new object (); + static object DoubleClickEvent = new object (); + static object MouseDownEvent = new object (); + static object MouseMoveEvent = new object (); + static object MouseUpEvent = new object (); + static object BalloonTipClickedEvent = new object (); + static object BalloonTipClosedEvent = new object (); + static object BalloonTipShownEvent = new object (); + static object MouseClickEvent = new object (); + static object MouseDoubleClickEvent = new object (); + + [MWFCategory("Action")] + public event EventHandler BalloonTipClicked { + add { Events.AddHandler (BalloonTipClickedEvent, value); } + remove { Events.RemoveHandler (BalloonTipClickedEvent, value); } + } + + [MWFCategory("Action")] + public event EventHandler BalloonTipClosed { + add { Events.AddHandler (BalloonTipClosedEvent, value); } + remove { Events.RemoveHandler (BalloonTipClosedEvent, value); } + } + + [MWFCategory("Action")] + public event EventHandler BalloonTipShown { + add { Events.AddHandler (BalloonTipShownEvent, value); } + remove { Events.RemoveHandler (BalloonTipShownEvent, value); } + } + + [MWFCategory("Action")] + public event MouseEventHandler MouseClick { + add { Events.AddHandler (MouseClickEvent, value); } + remove { Events.RemoveHandler (MouseClickEvent, value); } + } + + [MWFCategory ("Action")] + public event MouseEventHandler MouseDoubleClick { + add { Events.AddHandler (MouseDoubleClickEvent, value); } + remove { Events.RemoveHandler (MouseDoubleClickEvent, value); } + } + + [MWFCategory("Action")] + public event EventHandler Click { + add { Events.AddHandler (ClickEvent, value); } + remove { Events.RemoveHandler (ClickEvent, value); } + } + + [MWFCategory("Action")] + public event EventHandler DoubleClick { + add { Events.AddHandler (DoubleClickEvent, value); } + remove { Events.RemoveHandler (DoubleClickEvent, value); } + } + + public event MouseEventHandler MouseDown { + add { Events.AddHandler (MouseDownEvent, value); } + remove { Events.RemoveHandler (MouseDownEvent, value); } + } + + public event MouseEventHandler MouseMove { + add { Events.AddHandler (MouseMoveEvent, value); } + remove { Events.RemoveHandler (MouseMoveEvent, value); } + } + + public event MouseEventHandler MouseUp { + add { Events.AddHandler (MouseUpEvent, value); } + remove { Events.RemoveHandler (MouseUpEvent, value); } + } + + #endregion // Events + } +} diff --git a/source/ShiftUI/Widgets/Panel.cs b/source/ShiftUI/Widgets/Panel.cs new file mode 100644 index 0000000..3f0be8a --- /dev/null +++ b/source/ShiftUI/Widgets/Panel.cs @@ -0,0 +1,187 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// + +// COMPLETE + +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace ShiftUI { + [DefaultProperty("BorderStyle")] + [DefaultEvent("Paint")] + //[Designer ("ShiftUI.Design.PanelDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [Docking (DockingBehavior.Ask)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + [ToolboxWidget] + public class Panel : ScrollableWidget { + #region Constructors & Destructors + public Panel () { + base.TabStop = false; + SetStyle(Widgetstyles.Selectable, false); + SetStyle (Widgetstyles.SupportsTransparentBackColor, true); + } + #endregion // Constructors & Destructors + + #region Public Instance Properties + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)] + public override bool AutoSize { + get { return base.AutoSize; } + set { base.AutoSize = value; } + } + + [Browsable (true)] + [DefaultValue (AutoSizeMode.GrowOnly)] + [Localizable (true)] + public virtual AutoSizeMode AutoSizeMode { + get { return base.GetAutoSizeMode (); } + set { base.SetAutoSizeMode (value); } + } + + [DefaultValue(BorderStyle.None)] + [DispId(-504)] + public BorderStyle BorderStyle { + get { return InternalBorderStyle; } + set { InternalBorderStyle = value; } + } + + [DefaultValue(false)] + public new bool TabStop { + get { return base.TabStop; } + set { + if (value == TabStop) + return; + base.TabStop = value; + } + } + + [Bindable(false)] + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override string Text { + get { return base.Text; } + set { + if (value == Text) + return; + base.Text = value; + Refresh (); + } + } + #endregion // Public Instance Properties + + #region Protected Instance Properties + protected override CreateParams CreateParams { + get { + return base.CreateParams; + } + } + + protected override Size DefaultSize { + get { return ThemeEngine.Current.PanelDefaultSize; } + } + #endregion // Proteced Instance Properties + + #region Public Instance Methods + public override string ToString () + { + return base.ToString () + ", BorderStyle: " + BorderStyle; + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + protected override void OnResize(EventArgs eventargs) { + base.OnResize (eventargs); + Invalidate(true); + } + + #endregion // Protected Instance Methods + + #region Events + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler AutoSizeChanged { + add { base.AutoSizeChanged += value; } + remove { base.AutoSizeChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event KeyEventHandler KeyDown { + add { base.KeyDown += value; } + remove { base.KeyDown -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event KeyPressEventHandler KeyPress { + add { base.KeyPress += value; } + remove { base.KeyPress -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event KeyEventHandler KeyUp { + add { base.KeyUp += value; } + remove { base.KeyUp -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + #endregion + + #region Internal Methods + internal override Size GetPreferredSizeCore (Size proposedSize) + { + Size retsize = Size.Empty; + + foreach (Widget child in Widgets) { + if (child.Dock == DockStyle.Fill) { + if (child.Bounds.Right > retsize.Width) + retsize.Width = child.Bounds.Right; + } else if (child.Dock != DockStyle.Top && child.Dock != DockStyle.Bottom && (child.Anchor & AnchorStyles.Right) == 0 && (child.Bounds.Right + child.Margin.Right) > retsize.Width) + retsize.Width = child.Bounds.Right + child.Margin.Right; + + if (child.Dock == DockStyle.Fill) { + if (child.Bounds.Bottom > retsize.Height) + retsize.Height = child.Bounds.Bottom; + } else if (child.Dock != DockStyle.Left && child.Dock != DockStyle.Right && (child.Anchor & AnchorStyles.Bottom) == 0 && (child.Bounds.Bottom + child.Margin.Bottom) > retsize.Height) + retsize.Height = child.Bounds.Bottom + child.Margin.Bottom; + } + + return retsize; + } + #endregion + } +} + diff --git a/source/ShiftUI/Widgets/PictureBox.cs b/source/ShiftUI/Widgets/PictureBox.cs new file mode 100644 index 0000000..1574907 --- /dev/null +++ b/source/ShiftUI/Widgets/PictureBox.cs @@ -0,0 +1,618 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// + +// COMPLETE + +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; +using System.IO; +using System.Net; + +namespace ShiftUI { + [DefaultProperty("Image")] + //[Designer("ShiftUI.Design.PictureBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [Docking (DockingBehavior.Ask)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + [DefaultBindingProperty ("Image")] + [ToolboxWidget] + public class PictureBox : Widget, ISupportInitialize + { + #region Fields + private Image image; + private PictureBoxSizeMode size_mode; + private Image error_image; + private string image_location; + private Image initial_image; + private bool wait_on_load; + private WebClient image_download; + private bool image_from_url; + private int no_update; + #endregion // Fields + + private EventHandler frame_handler; + + #region Public Constructor + public PictureBox () + { + //recalc = true; + no_update = 0; + + SetStyle (Widgetstyles.OptimizedDoubleBuffer, true); + SetStyle (Widgetstyles.Opaque, false); + SetStyle (Widgetstyles.Selectable, false); + SetStyle (Widgetstyles.SupportsTransparentBackColor, true); + HandleCreated += new EventHandler(PictureBox_HandleCreated); + initial_image = null; + error_image = null; + } + #endregion // Public Constructor + + #region Public Properties + [DefaultValue(PictureBoxSizeMode.Normal)] + [Localizable(true)] + [RefreshProperties(RefreshProperties.Repaint)] + public PictureBoxSizeMode SizeMode { + get { return size_mode; } + set { + if (size_mode == value) + return; + size_mode = value; + + if (size_mode == PictureBoxSizeMode.AutoSize) { + AutoSize = true; + SetAutoSizeMode (AutoSizeMode.GrowAndShrink); + } else { + AutoSize = false; + SetAutoSizeMode (AutoSizeMode.GrowOnly); + } + + UpdateSize (); + if (no_update == 0) { + Invalidate (); + } + + OnSizeModeChanged (EventArgs.Empty); + } + } + + [Bindable (true)] + [Localizable(true)] + public Image Image { + get { return image; } + set { ChangeImage (value, false); } + } + + [DefaultValue(BorderStyle.None)] + [DispId(-504)] + public BorderStyle BorderStyle { + get { return InternalBorderStyle; } + set { InternalBorderStyle = value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new bool CausesValidation { + get { return base.CausesValidation; } + set { base.CausesValidation = value; } + } + + [Localizable (true)] + [RefreshProperties (RefreshProperties.All)] + public Image ErrorImage { + get { return error_image; } + set { error_image = value; } + } + + [RefreshProperties (RefreshProperties.All)] + [Localizable(true)] + public Image InitialImage { + get { return initial_image; } + set { initial_image = value; } + } + + [Localizable (true)] + [DefaultValue (null)] + [RefreshProperties (RefreshProperties.All)] + public string ImageLocation { + get { return image_location; } + set { + image_location = value; + + if (!string.IsNullOrEmpty (value)) { + if (WaitOnLoad) + Load (value); + else + LoadAsync (value); + } else if (image_from_url) + ChangeImage (null, true); + } + } + + [Localizable (true)] + [DefaultValue (false)] + public bool WaitOnLoad { + get { return wait_on_load; } + set { wait_on_load = value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new ImeMode ImeMode { + get { return base.ImeMode; } + set { base.ImeMode = value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override RightToLeft RightToLeft { + get { return base.RightToLeft; } + set { base.RightToLeft = value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new int TabIndex { + get { return base.TabIndex; } + set { base.TabIndex = value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new bool TabStop { + get { return base.TabStop; } + set { base.TabStop = value; } + } + + [Bindable(false)] + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override string Text { + get { return base.Text; } + set { base.Text = value; } + } + + protected override CreateParams CreateParams { + get { + return base.CreateParams; + } + } + + protected override ImeMode DefaultImeMode { + get { return base.DefaultImeMode; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override Font Font { + get { return base.Font; } + set { base.Font = value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override Color ForeColor { + get { return base.ForeColor; } + set { base.ForeColor = value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override bool AllowDrop { + get { return base.AllowDrop; } + set { base.AllowDrop = value; } + } + #endregion // Public Properties + + #region Protected Instance Methods + protected override Size DefaultSize { + get { return ThemeEngine.Current.PictureBoxDefaultSize; } + } + + protected override void Dispose (bool disposing) + { + if (image != null) { + StopAnimation (); + image = null; + } + initial_image = null; + + base.Dispose (disposing); + } + + protected override void OnPaint (PaintEventArgs pe) + { + ThemeEngine.Current.DrawPictureBox (pe.Graphics, pe.ClipRectangle, this); + base.OnPaint (pe); + } + + protected override void OnVisibleChanged (EventArgs e) + { + base.OnVisibleChanged (e); + } + + protected virtual void OnSizeModeChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [SizeModeChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnEnabledChanged (EventArgs e) + { + base.OnEnabledChanged (e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void OnHandleCreated (EventArgs e) + { + base.OnHandleCreated (e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void OnHandleDestroyed (EventArgs e) + { + base.OnHandleDestroyed (e); + } + + protected virtual void OnLoadCompleted (AsyncCompletedEventArgs e) + { + AsyncCompletedEventHandler eh = (AsyncCompletedEventHandler)(Events[LoadCompletedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnLoadProgressChanged (ProgressChangedEventArgs e) + { + ProgressChangedEventHandler eh = (ProgressChangedEventHandler)(Events[LoadProgressChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnParentChanged (EventArgs e) + { + base.OnParentChanged (e); + } + + protected override void OnResize (EventArgs e) + { + base.OnResize (e); + + Invalidate (); + } + + internal override Size GetPreferredSizeCore (Size proposedSize) + { + if (image == null) + return base.GetPreferredSizeCore (proposedSize); + else + return image.Size; + } + #endregion // Protected Instance Methods + + #region ISupportInitialize Interface + void System.ComponentModel.ISupportInitialize.BeginInit() { + no_update++; + } + + void System.ComponentModel.ISupportInitialize.EndInit() { + if (no_update > 0) { + no_update--; + } + if (no_update == 0) { + Invalidate (); + } + } + #endregion // ISupportInitialize Interface + + #region Private Properties + private WebClient ImageDownload { + get { + if (image_download == null) + image_download = new WebClient (); + + return image_download; + } + } + #endregion + + #region Private Methods + + private void ChangeImage (Image value, bool from_url) + { + StopAnimation (); + + image_from_url = from_url; + image = value; + + if (IsHandleCreated) { + UpdateSize (); + if (image != null && ImageAnimator.CanAnimate (image)) { + frame_handler = new EventHandler (OnAnimateImage); + ImageAnimator.Animate (image, frame_handler); + } + if (no_update == 0) { + Invalidate (); + } + } + } + + private void StopAnimation () + { + if (frame_handler == null) + return; + ImageAnimator.StopAnimate (image, frame_handler); + frame_handler = null; + } + + private void UpdateSize () + { + if (image == null) + return; + + if (Parent != null) + Parent.PerformLayout (this, "AutoSize"); + } + + private void OnAnimateImage (object sender, EventArgs e) + { + // This is called from a worker thread,BeginInvoke is used + // so the control is updated from the correct thread + + // Check if we have a handle again, since it may have gotten + // destroyed since the last time we checked. + if (!IsHandleCreated) + return; + + BeginInvoke (new EventHandler (UpdateAnimatedImage), new object [] { this, e }); + } + + private void UpdateAnimatedImage (object sender, EventArgs e) + { + // Check if we have a handle again, since it may have gotten + // destroyed since the last time we checked. + if (!IsHandleCreated) + return; + + ImageAnimator.UpdateFrames (image); + Refresh (); + } + + private void PictureBox_HandleCreated(object sender, EventArgs e) { + UpdateSize (); + if (image != null && ImageAnimator.CanAnimate (image)) { + frame_handler = new EventHandler (OnAnimateImage); + ImageAnimator.Animate (image, frame_handler); + } + if (no_update == 0) { + Invalidate (); + } + } + + void ImageDownload_DownloadDataCompleted (object sender, DownloadDataCompletedEventArgs e) + { + if (e.Error != null && !e.Cancelled) + Image = error_image; + else if (e.Error == null && !e.Cancelled) + using (MemoryStream ms = new MemoryStream (e.Result)) + Image = Image.FromStream (ms); + + ImageDownload.DownloadProgressChanged -= new DownloadProgressChangedEventHandler (ImageDownload_DownloadProgressChanged); + ImageDownload.DownloadDataCompleted -= new DownloadDataCompletedEventHandler (ImageDownload_DownloadDataCompleted); + image_download = null; + + OnLoadCompleted (e); + } + + private void ImageDownload_DownloadProgressChanged (object sender, DownloadProgressChangedEventArgs e) + { + OnLoadProgressChanged (new ProgressChangedEventArgs (e.ProgressPercentage, e.UserState)); + } + #endregion // Private Methods + + #region Public Instance Methods + public void CancelAsync () + { + if (image_download != null) + image_download.CancelAsync (); + } + + public void Load () + { + Load (image_location); + } + + public void Load (string url) + { + if (string.IsNullOrEmpty (url)) + throw new InvalidOperationException ("ImageLocation not specified."); + + image_location = url; + + if (url.Contains ("://")) + using (Stream s = ImageDownload.OpenRead (url)) + ChangeImage (Image.FromStream (s), true); + else + ChangeImage (Image.FromFile (url), true); + } + + public void LoadAsync () + { + LoadAsync (image_location); + } + + public void LoadAsync (string url) + { + // If WaitOnLoad is true, do not do async + if (wait_on_load) { + Load (url); + return; + } + + if (string.IsNullOrEmpty (url)) + throw new InvalidOperationException ("ImageLocation not specified."); + + image_location = url; + ChangeImage (InitialImage, true); + + if (ImageDownload.IsBusy) + ImageDownload.CancelAsync (); + + Uri uri = null; + try { + uri = new Uri (url); + } catch (UriFormatException) { + uri = new Uri (Path.GetFullPath (url)); + } + + ImageDownload.DownloadProgressChanged += new DownloadProgressChangedEventHandler (ImageDownload_DownloadProgressChanged); + ImageDownload.DownloadDataCompleted += new DownloadDataCompletedEventHandler (ImageDownload_DownloadDataCompleted); + ImageDownload.DownloadDataAsync (uri); + } + + public override string ToString() { + return String.Format("{0}, SizeMode: {1}", base.ToString (), SizeMode); + } + #endregion + + #region Events + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler CausesValidationChanged { + add { base.CausesValidationChanged += value; } + remove { base.CausesValidationChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler Enter { + add { base.Enter += value; } + remove { base.Enter -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler FontChanged { + add { base.FontChanged += value; } + remove { base.FontChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler ForeColorChanged { + add { base.ForeColorChanged += value; } + remove { base.ForeColorChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler ImeModeChanged { + add { base.ImeModeChanged += value; } + remove { base.ImeModeChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event KeyEventHandler KeyDown { + add { base.KeyDown += value; } + remove { base.KeyDown -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event KeyPressEventHandler KeyPress { + add { base.KeyPress += value; } + remove { base.KeyPress -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event KeyEventHandler KeyUp { + add { base.KeyUp += value; } + remove { base.KeyUp -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler Leave { + add { base.Leave += value; } + remove { base.Leave -= value; } + } + + static object LoadCompletedEvent = new object (); + static object LoadProgressChangedEvent = new object (); + + public event AsyncCompletedEventHandler LoadCompleted { + add { Events.AddHandler (LoadCompletedEvent, value); } + remove { Events.RemoveHandler (LoadCompletedEvent, value); } + } + + public event ProgressChangedEventHandler LoadProgressChanged { + add { Events.AddHandler (LoadProgressChangedEvent, value); } + remove { Events.RemoveHandler (LoadProgressChangedEvent, value); } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler RightToLeftChanged { + add { base.RightToLeftChanged += value; } + remove { base.RightToLeftChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler TabIndexChanged { + add { base.TabIndexChanged += value; } + remove { base.TabIndexChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler TabStopChanged { + add { base.TabStopChanged += value; } + remove { base.TabStopChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + + static object SizeModeChangedEvent = new object (); + public event EventHandler SizeModeChanged { + add { Events.AddHandler (SizeModeChangedEvent, value); } + remove { Events.RemoveHandler (SizeModeChangedEvent, value); } + } + + #endregion // Events + } +} + diff --git a/source/ShiftUI/Widgets/PictureBoxSizeMode.cs b/source/ShiftUI/Widgets/PictureBoxSizeMode.cs new file mode 100644 index 0000000..80319a4 --- /dev/null +++ b/source/ShiftUI/Widgets/PictureBoxSizeMode.cs @@ -0,0 +1,38 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// + + +namespace ShiftUI { + + public enum PictureBoxSizeMode { + Normal = 0, + StretchImage = 1, + AutoSize = 2, + CenterImage = 3, + Zoom = 4 + } +} + + diff --git a/source/ShiftUI/Widgets/ProgressBar.cs b/source/ShiftUI/Widgets/ProgressBar.cs new file mode 100644 index 0000000..89d06d0 --- /dev/null +++ b/source/ShiftUI/Widgets/ProgressBar.cs @@ -0,0 +1,533 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (C) 2004-2006 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez jordi@ximian.com +// Peter Dennis Bartok pbartok@novell.com +// +// + +using System.Drawing; +using System.ComponentModel; +using System.Drawing.Imaging; +using System.Drawing.Drawing2D; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI +{ + [DefaultProperty ("Value")] + [DefaultBindingProperty ("Value")] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + [ToolboxWidget] + public class ProgressBar : Widget + { + #region Local Variables + private int maximum; + private int minimum; + internal int step; + internal int val; + internal DateTime start = DateTime.Now; + internal Rectangle client_area = new Rectangle (); + internal ProgressBarStyle style; + Timer marquee_timer; + bool right_to_left_layout; + private static readonly Color defaultForeColor = SystemColors.Highlight; + #endregion // Local Variables + + #region events + static object RightToLeftLayoutChangedEvent = new object (); + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageChanged { + add { base.BackgroundImageChanged += value; } + remove { base.BackgroundImageChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageLayoutChanged { + add { base.BackgroundImageLayoutChanged += value; } + remove { base.BackgroundImageLayoutChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler CausesValidationChanged { + add { base.CausesValidationChanged += value; } + remove { base.CausesValidationChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler DoubleClick { + add { base.DoubleClick += value; } + remove { base.DoubleClick -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler Enter { + add { base.Enter += value; } + remove { base.Enter -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler FontChanged { + add { base.FontChanged += value; } + remove { base.FontChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler ImeModeChanged { + add { base.ImeModeChanged += value; } + remove { base.ImeModeChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event KeyEventHandler KeyDown { + add { base.KeyDown += value; } + remove { base.KeyDown -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event KeyPressEventHandler KeyPress { + add { base.KeyPress += value; } + remove { base.KeyPress -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event KeyEventHandler KeyUp { + add { base.KeyUp += value; } + remove { base.KeyUp -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler Leave { + add { base.Leave += value; } + remove { base.Leave -= value; } + } + + //[EditorBrowsable(EditorBrowsableState.Never)] + [Browsable(false)] + public new event MouseEventHandler MouseDoubleClick { + add { base.MouseDoubleClick += value; } + remove { base.MouseDoubleClick -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler PaddingChanged { + add { base.PaddingChanged += value; } + remove { base.PaddingChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event PaintEventHandler Paint { + add { base.Paint += value; } + remove { base.Paint -= value; } + } + + public event EventHandler RightToLeftLayoutChanged { + add { Events.AddHandler (RightToLeftLayoutChangedEvent, value); } + remove { Events.RemoveHandler (RightToLeftLayoutChangedEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TabStopChanged { + add { base.TabStopChanged += value; } + remove { base.TabStopChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + #endregion Events + + #region Public Constructors + public ProgressBar() + { + maximum = 100; + minimum = 0; + step = 10; + val = 0; + + base.Resize += new EventHandler (OnResizeTB); + + SetStyle (Widgetstyles.UserPaint | + Widgetstyles.Selectable | + Widgetstyles.ResizeRedraw | + Widgetstyles.Opaque | + Widgetstyles.UseTextForAccessibility + , false); + + force_double_buffer = true; + + ForeColor = defaultForeColor; + } + #endregion // Public Constructors + + #region Public Instance Properties + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override bool AllowDrop + { + get { return base.AllowDrop; } + set { + base.AllowDrop = value; + } + } + + // Setting this property in MS .Net 1.1 does not have any visual effect and it + // does not fire a BackgroundImageChanged event + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override Image BackgroundImage + { + get { return base.BackgroundImage; } + set { base.BackgroundImage = value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new bool CausesValidation + { + get { return base.CausesValidation; } + set { base.CausesValidation = value; } + } + + protected override CreateParams CreateParams + { + get { return base.CreateParams; } + } + + protected override ImeMode DefaultImeMode + { + get { return base.DefaultImeMode; } + } + + protected override Size DefaultSize + { + get { return ThemeEngine.Current.ProgressBarDefaultSize; } + } + + //[EditorBrowsable(EditorBrowsableState.Never)] + protected override bool DoubleBuffered { + get { return base.DoubleBuffered; } + set { base.DoubleBuffered = value; } + } + + // Setting this property in MS .Net 1.1 does not have any visual effect and it + // does not fire a FontChanged event + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override Font Font + { + get { return base.Font; } + set { base.Font = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new ImeMode ImeMode + { + get { return base.ImeMode; } + set { base.ImeMode = value; } + } + + [RefreshProperties(RefreshProperties.Repaint)] + [DefaultValue (100)] + public int Maximum + { + get { + return maximum; + } + set { + if (value < 0) + throw new ArgumentOutOfRangeException ("Maximum", + string.Format("Value '{0}' must be greater than or equal to 0.", value )); + + maximum = value; + minimum = Math.Min (minimum, maximum); + val = Math.Min (val, maximum); + Refresh (); + } + } + + [RefreshProperties(RefreshProperties.Repaint)] + [DefaultValue (0)] + public int Minimum { + get { + return minimum; + } + set { + if (value < 0) + throw new ArgumentOutOfRangeException ("Minimum", + string.Format("Value '{0}' must be greater than or equal to 0.", value )); + + minimum = value; + maximum = Math.Max (maximum, minimum); + val = Math.Max (val, minimum); + Refresh (); + } + } + + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new Padding Padding { + get { return base.Padding; } + set { base.Padding = value; } + } + + [Localizable(true)] + [DefaultValue(false)] + [MonoTODO ("RTL is not supported")] + public virtual bool RightToLeftLayout { + get { return right_to_left_layout;} + set { + if (right_to_left_layout != value) { + right_to_left_layout = value; + OnRightToLeftLayoutChanged (EventArgs.Empty); + } + } + } + + [DefaultValue (10)] + public int Step + { + get { return step; } + set { + step = value; + Refresh (); + } + } + + [Browsable (true)] + [DefaultValue (ProgressBarStyle.Blocks)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public ProgressBarStyle Style { + get { + return style; + } + + set { + if (value != ProgressBarStyle.Blocks && value != ProgressBarStyle.Continuous + && value != ProgressBarStyle.Marquee) + throw new InvalidEnumArgumentException ("value", unchecked((int)value), typeof (ProgressBarStyle)); + if (style != value) { + style = value; + + if (style == ProgressBarStyle.Marquee) { + if (marquee_timer == null) { + marquee_timer = new Timer (); + marquee_timer.Interval = 10; + marquee_timer.Tick += new EventHandler (marquee_timer_Tick); + } + marquee_timer.Start (); + } else { + if (marquee_timer != null) { + marquee_timer.Stop (); + } + Refresh (); + } + } + } + } + + void marquee_timer_Tick (object sender, EventArgs e) + { + Invalidate (); + } + + int marquee_animation_speed = 100; + [DefaultValue (100)] + public int MarqueeAnimationSpeed { + get { + return marquee_animation_speed; + } + + set { + marquee_animation_speed = value; + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new bool TabStop + { + get { return base.TabStop; } + set { base.TabStop = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + [Bindable(false)] + public override string Text + { + get { return base.Text; } + set { base.Text = value; } + } + + [Bindable(true)] + [DefaultValue (0)] + public int Value + { + get { + return val; + } + set { + if (value < Minimum || value > Maximum) + throw new ArgumentOutOfRangeException ("Value", string.Format("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value)); + val = value; + Refresh (); + } + } + + + #endregion // Protected Instance Properties + + #region Public Instance Methods + + protected override void CreateHandle () + { + base.CreateHandle (); + } + + public void Increment (int value) + { + if (Style == ProgressBarStyle.Marquee) + throw new InvalidOperationException ("Increment should not be called if the style is Marquee."); + + int newValue = Value + value; + + if (newValue < Minimum) + newValue = Minimum; + + if (newValue > Maximum) + newValue = Maximum; + + Value = newValue; + Refresh (); + } + + protected override void OnHandleCreated (EventArgs e) + { + base.OnHandleCreated (e); + + UpdateAreas (); + } + + protected override void OnBackColorChanged (EventArgs e) + { + base.OnBackColorChanged (e); + } + + protected override void OnForeColorChanged (EventArgs e) + { + base.OnForeColorChanged (e); + } + + protected override void OnHandleDestroyed (EventArgs e) + { + base.OnHandleDestroyed (e); + } + + //[EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void OnRightToLeftLayoutChanged(EventArgs e) + { + EventHandler eh = (EventHandler) Events [RightToLeftLayoutChangedEvent]; + if (eh != null) + eh (this, e); + } + + public void PerformStep () + { + if (Style == ProgressBarStyle.Marquee) + throw new InvalidOperationException ("PerformStep should not be called if the style is Marquee."); + + Increment (Step); + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + public override void ResetForeColor () + { + ForeColor = defaultForeColor; + } + + public override string ToString() + { + return string.Format ("{0}, Minimum: {1}, Maximum: {2}, Value: {3}", + GetType().FullName, + Minimum.ToString (), + Maximum.ToString (), + Value.ToString () ); + } + + #endregion // Public Instance Methods + + #region Private Instance Methods + + private void UpdateAreas () + { + client_area.X = client_area.Y = 2; + client_area.Width = Width - 4; + client_area.Height = Height - 4; + } + + private void OnResizeTB (Object o, EventArgs e) + { + if (Width <= 0 || Height <= 0) + return; + + UpdateAreas (); + Invalidate(); // Invalidate the full surface, blocks will not match + } + + internal override void OnPaintInternal (PaintEventArgs pevent) + { + ThemeEngine.Current.DrawProgressBar (pevent.Graphics, pevent.ClipRectangle, this); + } + + #endregion + } +} diff --git a/source/ShiftUI/Widgets/PropertiesTab.cs b/source/ShiftUI/Widgets/PropertiesTab.cs new file mode 100644 index 0000000..a92fd33 --- /dev/null +++ b/source/ShiftUI/Widgets/PropertiesTab.cs @@ -0,0 +1,76 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005-2008 Novell, Inc. +// +// Authors: +// Jonathan Chambers jonathan.chambers@ansys.com +// Ivan N. Zlatev contact@i-nz.net +// + +using System; +using System.ComponentModel; +using ShiftUI.Design; + +namespace ShiftUI.PropertyGridInternal +{ + public class PropertiesTab : PropertyTab + { + public PropertiesTab () + { + } + + public override PropertyDescriptorCollection GetProperties (object component, Attribute[] attributes) + { + return GetProperties (null, component, attributes); + } + + public override PropertyDescriptorCollection GetProperties (ITypeDescriptorContext context, object component, Attribute[] attributes) + { + if (component == null) + return new PropertyDescriptorCollection (null); + if (attributes == null) + attributes = new Attribute[] { BrowsableAttribute.Yes }; + + PropertyDescriptorCollection properties = null; + TypeConverter converter = TypeDescriptor.GetConverter (component); + if (converter != null && converter.GetPropertiesSupported ()) + properties = converter.GetProperties (context, component, attributes); + if (properties == null) // try 3: TypeDescriptor + properties = TypeDescriptor.GetProperties (component, attributes); + return properties; + } + + public override PropertyDescriptor GetDefaultProperty (object obj) + { + if (obj == null) + return null; + + return TypeDescriptor.GetDefaultProperty (obj); + } + + public override string HelpKeyword { + get { return "vs.properties"; } + } + + public override string TabName { + get { return "Properties"; } + } + } +} diff --git a/source/ShiftUI/Widgets/PropertyGrid.cs b/source/ShiftUI/Widgets/PropertyGrid.cs new file mode 100644 index 0000000..36af17c --- /dev/null +++ b/source/ShiftUI/Widgets/PropertyGrid.cs @@ -0,0 +1,1626 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2008 Novell, Inc. +// +// Authors: +// Jonathan Chambers (jonathan.chambers@ansys.com) +// Ivan N. Zlatev (contact@i-nz.net) +// + +// NOT COMPLETE + +using System; +using System.IO; +using System.Drawing; +using System.Drawing.Design; +using System.ComponentModel; +using System.Collections; +using System.ComponentModel.Design; +using System.Reflection; +using System.Runtime.InteropServices; +using ShiftUI.Design; +using ShiftUI.PropertyGridInternal; + +namespace ShiftUI +{ + [Designer("ShiftUI.Design.PropertyGridDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + [ToolboxWidget] + public class PropertyGrid : ShiftUI.ContainerWidget + { + #region Private Members + + + private const string UNCATEGORIZED_CATEGORY_LABEL = "Misc"; + private AttributeCollection browsable_attributes = null; + private bool can_show_commands = false; + private Color commands_back_color; + private Color commands_fore_color; + private bool commands_visible; + private bool commands_visible_if_available; + private Point context_menu_default_location; + private bool large_buttons; + private Color line_color; + private PropertySort property_sort; + private PropertyTabCollection property_tabs; + private GridEntry selected_grid_item; + private GridEntry root_grid_item; + private object[] selected_objects; + private PropertyTab properties_tab; + private PropertyTab selected_tab; + + private ImageList toolbar_imagelist; + private Image categorized_image; + private Image alphabetical_image; + private Image propertypages_image; + private PropertyToolBarButton categorized_toolbarbutton; + private PropertyToolBarButton alphabetic_toolbarbutton; + private PropertyToolBarButton propertypages_toolbarbutton; + private PropertyToolBarSeparator separator_toolbarbutton; + private bool events_tab_visible; + + private PropertyToolBar toolbar; + + private PropertyGridView property_grid_view; + private Splitter splitter; + private Panel help_panel; + private Label help_title_label; + private Label help_description_label; + private MenuItem reset_menuitem; + private MenuItem description_menuitem; + + private Color category_fore_color; + private Color commands_active_link_color; + private Color commands_disabled_link_color; + private Color commands_link_color; + #endregion // Private Members + + #region Contructors + public PropertyGrid () + { + selected_objects = new object[0]; + property_tabs = new PropertyTabCollection(this); + + line_color = SystemColors.ScrollBar; + category_fore_color = line_color; + commands_visible = false; + commands_visible_if_available = false; + property_sort = PropertySort.CategorizedAlphabetical; + property_grid_view = new PropertyGridView(this); + + splitter = new Splitter(); + splitter.Dock = DockStyle.Bottom; + + help_panel = new Panel(); + help_panel.Dock = DockStyle.Bottom; + //help_panel.DockPadding.All = 3; + help_panel.Height = 50; + help_panel.BackColor = SystemColors.Control; + + + help_title_label = new Label(); + help_title_label.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + help_title_label.Name = "help_title_label"; + help_title_label.Font = new Font(this.Font,FontStyle.Bold); + help_title_label.Location = new Point(2,2); + help_title_label.Height = 17; + help_title_label.Width = help_panel.Width - 4; + + + help_description_label = new Label(); + help_description_label.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom; + help_description_label.AutoEllipsis = true; + help_description_label.AutoSize = false; + help_description_label.Font = this.Font; + help_description_label.Location = new Point(2,help_title_label.Top+help_title_label.Height); + help_description_label.Width = help_panel.Width - 4; + help_description_label.Height = help_panel.Height - help_description_label.Top - 2; + + help_panel.Widgets.Add(help_description_label); + help_panel.Widgets.Add(help_title_label); + help_panel.Paint+=new PaintEventHandler(help_panel_Paint); + + toolbar = new PropertyToolBar(); + toolbar.Dock = DockStyle.Top; + categorized_toolbarbutton = new PropertyToolBarButton (); + categorized_toolbarbutton.Pushed = true; + alphabetic_toolbarbutton = new PropertyToolBarButton (); + propertypages_toolbarbutton = new PropertyToolBarButton (); + separator_toolbarbutton = new PropertyToolBarSeparator (); + context_menu_default_location = Point.Empty; + + toolbar.Appearance = ToolBarAppearance.Flat; + toolbar.AutoSize = false; + + toolbar.Location = new System.Drawing.Point(0, 0); + toolbar.ShowToolTips = true; + toolbar.Size = new System.Drawing.Size(256, 27); + toolbar.TabIndex = 0; + + toolbar.Items.AddRange (new ToolStripItem [] {categorized_toolbarbutton, + alphabetic_toolbarbutton, + new PropertyToolBarSeparator (), + propertypages_toolbarbutton}); + //toolbar.ButtonSize = new System.Drawing.Size (20, 20); + categorized_toolbarbutton.Click += new EventHandler (toolbarbutton_clicked); + alphabetic_toolbarbutton.Click += new EventHandler (toolbarbutton_clicked); + propertypages_toolbarbutton.Click += new EventHandler (toolbarbutton_clicked); + + categorized_toolbarbutton.Style = ToolBarButtonStyle.ToggleButton; + categorized_toolbarbutton.ToolTipText = "Categorized"; + + alphabetic_toolbarbutton.Style = ToolBarButtonStyle.ToggleButton; + alphabetic_toolbarbutton.ToolTipText = "Alphabetic"; + + propertypages_toolbarbutton.Enabled = false; + propertypages_toolbarbutton.Style = ToolBarButtonStyle.ToggleButton; + propertypages_toolbarbutton.ToolTipText = "Property Pages"; + + properties_tab = CreatePropertyTab (this.DefaultTabType); + selected_tab = properties_tab; + RefreshToolbar (property_tabs); + + BorderHelperControl helper = new BorderHelperControl (); + helper.Dock = DockStyle.Fill; + helper.Widgets.Add (property_grid_view); + + this.Widgets.Add(helper); + this.Widgets.Add(toolbar); + this.Widgets.Add(splitter); + this.Widgets.Add(help_panel); + this.Name = "PropertyGrid"; + this.Size = new System.Drawing.Size(256, 400); + } + #endregion // Constructors + + #region Public Instance Properties + + [BrowsableAttribute(false)] + [EditorBrowsableAttribute(EditorBrowsableState.Advanced)] + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] + public AttributeCollection BrowsableAttributes { + get { + if (browsable_attributes == null) { + browsable_attributes = new AttributeCollection (new Attribute[] { + BrowsableAttribute.Yes }); + } + return browsable_attributes; + } + set { + if (browsable_attributes == value) + return; + + if (browsable_attributes == null || browsable_attributes.Count == 0) + browsable_attributes = null; + else + browsable_attributes = value; + } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool AutoScroll { + get { + return base.AutoScroll; + } + set { + base.AutoScroll = value; + } + } + + public override Color BackColor { + get { + return base.BackColor; + } + + set { + base.BackColor = value; + toolbar.BackColor = value; + Refresh (); + } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override Image BackgroundImage { + get { + return base.BackgroundImage; + } + set { + base.BackgroundImage = value; + } + } + + [EditorBrowsable(EditorBrowsableState.Never)] + [Browsable(false)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + [BrowsableAttribute(false)] + [EditorBrowsableAttribute(EditorBrowsableState.Advanced)] + public virtual bool CanShowCommands { + get { + return can_show_commands; + } + } + + [DefaultValue(typeof(Color), "ControlText")] + public Color CategoryForeColor { + get { + return category_fore_color; + } + set { + if (category_fore_color != value) { + category_fore_color = value; + Invalidate (); + } + } + } + + public Color CommandsBackColor { + get { + return commands_back_color; + } + + set { + if (commands_back_color == value) { + return; + } + commands_back_color = value; + } + } + + public Color CommandsForeColor { + get { + return commands_fore_color; + } + + set { + if (commands_fore_color == value) { + return; + } + commands_fore_color = value; + } + } + + public Color CommandsActiveLinkColor { + get { + return commands_active_link_color; + } + set { + commands_active_link_color = value; + } + } + + public Color CommandsDisabledLinkColor { + get { + return commands_disabled_link_color; + } + set { + commands_disabled_link_color = value; + } + } + + public Color CommandsLinkColor { + get { + return commands_link_color; + } + set { + commands_link_color = value; + } + } + + [BrowsableAttribute (false)] + [EditorBrowsableAttribute(EditorBrowsableState.Advanced)] + [MonoTODO ("Commands are not implemented yet.")] + public virtual bool CommandsVisible { + get { + return commands_visible; + } + } + + [DefaultValue (true)] + public virtual bool CommandsVisibleIfAvailable { + get { + return commands_visible_if_available; + } + + set { + if (commands_visible_if_available == value) { + return; + } + commands_visible_if_available = value; + } + } + + [BrowsableAttribute(false)] + [EditorBrowsableAttribute(EditorBrowsableState.Advanced)] + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] + public Point ContextMenuDefaultLocation { + get { + return context_menu_default_location; + } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public new Widget.WidgetCollection Widgets { + get { + return base.Widgets; + } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override Color ForeColor { + get { + return base.ForeColor; + } + set { + base.ForeColor = value; + } + } + + [DefaultValue ("Color [Widget]")] + public Color HelpBackColor { + get { + return help_panel.BackColor; + } + set { + help_panel.BackColor = value; + } + } + + [DefaultValue ("Color [ControlText]")] + public Color HelpForeColor { + get { + return help_panel.ForeColor; + } + + set { + help_panel.ForeColor = value; + } + } + + [DefaultValue(true)] + [Localizable(true)] + public virtual bool HelpVisible { + get { + return help_panel.Visible; + } + + set { + splitter.Visible = value; + help_panel.Visible = value; + } + } + + [DefaultValue (false)] + public bool LargeButtons { + get { + return large_buttons; + } + + set { + if (large_buttons == value) { + return; + } + + large_buttons = value; + } + } + + [DefaultValue ("Color [InactiveBorder]")] + public Color LineColor { + get { + return line_color; + } + + set { + if (line_color == value) { + return; + } + + line_color = value; + } + } + + [EditorBrowsable(EditorBrowsableState.Never)] + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public new Padding Padding { + get { return base.Padding; } + set { base.Padding = value; } + } + + [DefaultValue(PropertySort.CategorizedAlphabetical)] + public PropertySort PropertySort { + get { + return property_sort; + } + + set { + if (!Enum.IsDefined (typeof (PropertySort), value)) + throw new InvalidEnumArgumentException ("value", (int) value, typeof (PropertySort)); + if (property_sort == value) + return; + + // we do not need to update the the grid items and fire + // a PropertySortChanged event when switching between + // Categorized and CateogizedAlphabetical + bool needUpdate = (property_sort & PropertySort.Categorized) == 0 || + (value & PropertySort.Categorized) == 0; + property_sort = value; + if (needUpdate) { + UpdateSortLayout (root_grid_item); + // update selection + if (selected_grid_item != null) { + if (selected_grid_item.GridItemType == GridItemType.Category && + (value == PropertySort.Alphabetical || value == PropertySort.NoSort)) + SelectItemCore (null, null); + else + SelectItemCore (null, selected_grid_item); + } + property_grid_view.UpdateView (); + + EventHandler eh = (EventHandler)(Events [PropertySortChangedEvent]); + if (eh != null) + eh (this, EventArgs.Empty); + } + UpdatePropertySortButtonsState (); + } + } + + [BrowsableAttribute(false)] + [EditorBrowsableAttribute(EditorBrowsableState.Advanced)] + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] + public PropertyTabCollection PropertyTabs { + get { return property_tabs; } + } + + [BrowsableAttribute(false)] + [EditorBrowsableAttribute(EditorBrowsableState.Advanced)] + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] + public GridItem SelectedGridItem { + get { return selected_grid_item; } + set { + if (value == null) + throw new ArgumentException ("GridItem specified to PropertyGrid.SelectedGridItem must be a valid GridItem."); + if (value != selected_grid_item) { + GridEntry oldItem = selected_grid_item; + SelectItemCore (oldItem, (GridEntry)value); + OnSelectedGridItemChanged (new SelectedGridItemChangedEventArgs (oldItem, value)); + } + } + } + + internal GridItem RootGridItem { + get { return root_grid_item; } + } + + private void UpdateHelp (GridItem item) + { + if (item == null) { + help_title_label.Text = string.Empty; + help_description_label.Text = string.Empty; + } else { + help_title_label.Text = item.Label; + if (item.PropertyDescriptor != null) + this.help_description_label.Text = item.PropertyDescriptor.Description; + } + } + + private void SelectItemCore (GridEntry oldItem, GridEntry item) + { + UpdateHelp (item); + selected_grid_item = item; + property_grid_view.SelectItem (oldItem, item); + } + + internal void OnPropertyValueChangedInternal (GridItem item, object property_value) + { + property_grid_view.UpdateView (); + OnPropertyValueChanged (new PropertyValueChangedEventArgs (item, property_value)); + } + + internal void OnExpandItem (GridEntry item) + { + property_grid_view.ExpandItem (item); + } + + internal void OnCollapseItem (GridEntry item) + { + property_grid_view.CollapseItem (item); + } + + internal DialogResult ShowError (string text) + { + return this.ShowError (text, MessageBoxButtons.OK); + } + + internal DialogResult ShowError (string text, MessageBoxButtons buttons) + { + if (text == null) + throw new ArgumentNullException ("text"); + MessageBox.Show (text, "Properties Window"); + return DialogResult.OK; + } + + [DefaultValue(null)] + [TypeConverter("ShiftUI.PropertyGrid+SelectedObjectConverter, " + Consts.AssemblySystem_Windows_Forms)] + public object SelectedObject { + get { + if (selected_objects.Length > 0) + return selected_objects[0]; + return null; + } + + set { + if (selected_objects != null && selected_objects.Length == 1 && selected_objects[0] == value) + return; + if (value == null) + SelectedObjects = new object[0]; + else + SelectedObjects = new object[] {value}; + + } + } + + [BrowsableAttribute(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public object[] SelectedObjects { + get { + return selected_objects; + } + + set { + root_grid_item = null; + SelectItemCore (null, null); // unselect current item in the view + if (value != null) { + for (int i = 0; i < value.Length; i++) { + if (value [i] == null) + throw new ArgumentException (String.Format ("Item {0} in the objs array is null.", i)); + } + selected_objects = value; + } else { + selected_objects = new object [0]; + } + + ShowEventsButton (false); + PopulateGrid (selected_objects); + RefreshTabs(PropertyTabScope.Component); + if (root_grid_item != null) + SelectItemCore (null, GetDefaultPropertyItem (root_grid_item, selected_tab)); + property_grid_view.UpdateView (); + OnSelectedObjectsChanged (EventArgs.Empty); + } + } + + [BrowsableAttribute(false)] + [EditorBrowsable(EditorBrowsableState.Advanced)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public PropertyTab SelectedTab { + get { return selected_tab; } + } + + public override ISite Site { + get { return base.Site; } + set { base.Site = value; } + } + + [Browsable (false)] + [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override string Text { + get { return base.Text; } + set { base.Text = value; } + } + + [DefaultValue(true)] + public virtual bool ToolbarVisible { + get { return toolbar.Visible; } + set { + if (toolbar.Visible == value) { + return; + } + + toolbar.Visible = value; + } + } + + protected ToolStripRenderer ToolStripRenderer { + get { + if (toolbar != null) { + return toolbar.Renderer; + } + return null; + } + set { + if (toolbar != null) { + toolbar.Renderer = value; + } + } + } + + [DefaultValue ("Color [Window]")] + public Color ViewBackColor { + get { return property_grid_view.BackColor; } + set { + if (property_grid_view.BackColor == value) { + return; + } + + property_grid_view.BackColor = value; + } + } + + [DefaultValue ("Color [WindowText]")] + public Color ViewForeColor { + get { return property_grid_view.ForeColor; } + set { + if (property_grid_view.ForeColor == value) { + return; + } + + property_grid_view.ForeColor = value; + } + } + + [DefaultValue (false)] + public bool UseCompatibleTextRendering { + get { return use_compatible_text_rendering; } + set { + if (use_compatible_text_rendering != value) { + use_compatible_text_rendering = value; + if (Parent != null) + Parent.PerformLayout (this, "UseCompatibleTextRendering"); + Invalidate (); + } + } + } + + #endregion // Public Instance Properties + + #region Protected Instance Properties + + protected override Size DefaultSize { + get { return base.DefaultSize; } + } + + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Advanced)] + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] + protected virtual Type DefaultTabType { + get { return typeof(PropertiesTab); } + } + + protected bool DrawFlatToolbar { + get { return (toolbar.Appearance == ToolBarAppearance.Flat); } + set { + if (value) + toolbar.Appearance = ToolBarAppearance.Flat; + else + toolbar.Appearance = ToolBarAppearance.Normal; + } + } + + protected internal override bool ShowFocusCues { + get { return base.ShowFocusCues; } + } + + #endregion // Protected Instance Properties + + #region Public Instance Methods + + protected override void Dispose(bool disposing) { + base.Dispose(disposing); + } + + public void CollapseAllGridItems () + { + GridEntry category = FindCategoryItem (selected_grid_item); + if (category != null) + SelectedGridItem = category; + CollapseItemRecursive (root_grid_item); + property_grid_view.UpdateView (); + } + + private void CollapseItemRecursive (GridItem item) + { + if (item == null) + return; + + foreach (GridItem child in item.GridItems) { + CollapseItemRecursive (child); + if (child.Expandable) + child.Expanded = false; + } + } + + private GridEntry FindCategoryItem (GridEntry entry) + { + if (entry == null || (property_sort != PropertySort.Categorized && + property_sort != PropertySort.CategorizedAlphabetical)) + return null; + + if (entry.GridItemType == GridItemType.Category) + return entry; + + GridEntry category = null; + GridItem current = (GridItem)entry; + while (category == null) { + if (current.Parent != null && current.Parent.GridItemType == GridItemType.Category) + category = (GridEntry) current.Parent; + current = current.Parent; + if (current == null) + break; + } + return (GridEntry) category; + } + + public void ExpandAllGridItems () + { + ExpandItemRecursive (root_grid_item); + property_grid_view.UpdateView (); + } + + private void ExpandItemRecursive (GridItem item) + { + if (item == null) + return; + + foreach (GridItem child in item.GridItems) { + ExpandItemRecursive (child); + if (child.Expandable) + child.Expanded = true; + } + } + + public override void Refresh () + { + base.Refresh (); + // force a full reload here + SelectedObjects = SelectedObjects; + } + + private void toolbar_Clicked (PropertyToolBarButton button) + { + if (button == null) + return; + + if (button == alphabetic_toolbarbutton) { + this.PropertySort = PropertySort.Alphabetical; + alphabetic_toolbarbutton.Pushed = true; + categorized_toolbarbutton.Pushed = false; + } else if (button == categorized_toolbarbutton) { + this.PropertySort = PropertySort.CategorizedAlphabetical; + categorized_toolbarbutton.Pushed = true; + alphabetic_toolbarbutton.Pushed = false; + } else { + if (button.Enabled) + SelectPropertyTab (button.PropertyTab); + } + } + + private void toolbarbutton_clicked (object o, EventArgs args) + { + toolbar_Clicked (o as PropertyToolBarButton); + } + + private void SelectPropertyTab (PropertyTab propertyTab) + { + if (propertyTab != null && selected_tab != propertyTab) { + foreach (object toolbarItem in toolbar.Items) { + PropertyToolBarButton button = toolbarItem as PropertyToolBarButton; + if (button != null && button.PropertyTab != null) { + if (button.PropertyTab == selected_tab) + button.Pushed = false; + else if (button.PropertyTab == propertyTab) + button.Pushed = true; + } + } + selected_tab = propertyTab; + PopulateGrid (selected_objects); + SelectItemCore (null, GetDefaultPropertyItem (root_grid_item, selected_tab)); + property_grid_view.UpdateView (); + } + } + + private void UpdatePropertySortButtonsState () + { + if (property_sort == PropertySort.NoSort) { + alphabetic_toolbarbutton.Pushed = false; + categorized_toolbarbutton.Pushed = false; + } else if (property_sort == PropertySort.Alphabetical) { + alphabetic_toolbarbutton.Pushed = true; + categorized_toolbarbutton.Pushed = false; + } else if (property_sort == PropertySort.Categorized || + property_sort == PropertySort.CategorizedAlphabetical) { + alphabetic_toolbarbutton.Pushed = false; + categorized_toolbarbutton.Pushed = true; + } + } + + protected void ShowEventsButton (bool value) + { + if (value && property_tabs.Contains (typeof (EventsTab))) + events_tab_visible = true; + else + events_tab_visible = false; + RefreshTabs (PropertyTabScope.Component); + } + + public void RefreshTabs (PropertyTabScope tabScope) + { + property_tabs.Clear (tabScope); + if (selected_objects != null) { + Type[] tabTypes = null; + PropertyTabScope[] tabScopes = null; + + if (events_tab_visible && property_tabs.Contains (typeof (EventsTab))) + property_tabs.InsertTab (0, properties_tab, PropertyTabScope.Component); + + GetMergedPropertyTabs (selected_objects, out tabTypes, out tabScopes); + if (tabTypes != null && tabScopes != null && tabTypes.Length > 0) { + bool selectedTabPreserved = false; + for (int i=0; i < tabTypes.Length; i++) { + property_tabs.AddTabType (tabTypes[i], tabScopes[i]); + if (tabTypes[i] == selected_tab.GetType ()) + selectedTabPreserved = true; + } + if (!selectedTabPreserved) + SelectPropertyTab (properties_tab); + } + } else { + SelectPropertyTab (properties_tab); + } + RefreshToolbar (property_tabs); + } + + private void RefreshToolbar (PropertyTabCollection tabs) + { + EnsurePropertiesTab (); + + toolbar.SuspendLayout (); + toolbar.Items.Clear (); + + int imageIndex = 0; + toolbar.Items.Add (categorized_toolbarbutton); + categorized_toolbarbutton.DisplayStyle = ToolStripItemDisplayStyle.Text; + categorized_toolbarbutton.Text = "Categorized"; + imageIndex++; + toolbar.Items.Add (alphabetic_toolbarbutton); + alphabetic_toolbarbutton.DisplayStyle = ToolStripItemDisplayStyle.Text; + alphabetic_toolbarbutton.Text = "Alphabetical"; + imageIndex++; + toolbar.Items.Add (separator_toolbarbutton); + if (tabs != null && tabs.Count > 0) { + foreach (PropertyTab tab in tabs) { + PropertyToolBarButton button = new PropertyToolBarButton (tab); + toolbar.Items.Add (button); + if (tab == selected_tab) + button.Pushed = true; + } + toolbar.Items.Add (new PropertyToolBarSeparator ()); + } + + toolbar.Items.Add (propertypages_toolbarbutton); + + toolbar.ResumeLayout (); + } + + private void EnsurePropertiesTab () + { + if (property_tabs == null) + return; + + if (property_tabs.Count > 0 && !property_tabs.Contains (this.DefaultTabType)) + property_tabs.InsertTab (0, properties_tab, PropertyTabScope.Component); + } + + private void GetMergedPropertyTabs (object[] objects, out Type[] tabTypes, out PropertyTabScope[] tabScopes) + { + tabTypes = null; + tabScopes = null; + if (objects == null || objects.Length == 0) + return; + + ArrayList intersection = null; + ArrayList scopes = new ArrayList (); + for (int i=0; i < objects.Length; i++) { + if (objects[i] == null) + continue; + PropertyTabAttribute tabAttribute = (PropertyTabAttribute)TypeDescriptor.GetAttributes (objects[i])[typeof (PropertyTabAttribute)]; + if (tabAttribute == null || tabAttribute.TabClasses == null || tabAttribute.TabClasses.Length == 0) + return; + + ArrayList new_intersection = new ArrayList (); + scopes.Clear (); + IList currentIntersection = (i == 0 ? (IList)tabAttribute.TabClasses : (IList)intersection); + for (int j=0; j < currentIntersection.Count; j++) { + if ((Type)intersection[j] == tabAttribute.TabClasses[j]) { + new_intersection.Add (tabAttribute.TabClasses[j]); + scopes.Add (tabAttribute.TabScopes[j]); + } + } + intersection = new_intersection; + } + + tabTypes = new Type[intersection.Count]; + intersection.CopyTo (tabTypes); + tabScopes = new PropertyTabScope[tabTypes.Length]; + scopes.CopyTo (tabScopes); + } + + public void ResetSelectedProperty() + { + if (selected_grid_item == null) + return; + selected_grid_item.ResetValue (); + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + + protected virtual PropertyTab CreatePropertyTab (Type tabType) + { + if (!typeof(PropertyTab).IsAssignableFrom (tabType)) + return null; + + PropertyTab tab = null; + + ConstructorInfo ctor = tabType.GetConstructor (new Type[] { typeof (IServiceProvider) }); + if (ctor != null) + tab = (PropertyTab)ctor.Invoke (new object[] { this.Site }); + else + tab = (PropertyTab)Activator.CreateInstance (tabType); + return tab; + } + + protected override void OnEnabledChanged (EventArgs e) { + base.OnEnabledChanged (e); + } + + protected override void OnFontChanged(EventArgs e) { + base.OnFontChanged (e); + } + + protected override void OnGotFocus(EventArgs e) { + base.OnGotFocus(e); + } + + protected override void OnHandleCreated (EventArgs e) { + base.OnHandleCreated (e); + } + + protected override void OnHandleDestroyed (EventArgs e) { + base.OnHandleDestroyed (e); + } + + protected override void OnMouseDown (MouseEventArgs me) { + base.OnMouseDown (me); + } + + protected override void OnMouseMove (MouseEventArgs me) { + base.OnMouseMove (me); + } + + protected override void OnMouseUp (MouseEventArgs me) { + base.OnMouseUp (me); + } + + protected void OnNotifyPropertyValueUIItemsChanged(object sender, EventArgs e) + { + property_grid_view.UpdateView (); + } + + protected override void OnPaint (PaintEventArgs pevent) { + pevent.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(BackColor), pevent.ClipRectangle); + base.OnPaint (pevent); + } + + protected virtual void OnPropertySortChanged(EventArgs e) { + EventHandler eh = (EventHandler) Events [PropertySortChangedEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnPropertyTabChanged (PropertyTabChangedEventArgs e) + { + PropertyTabChangedEventHandler eh = (PropertyTabChangedEventHandler)(Events [PropertyTabChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnPropertyValueChanged (PropertyValueChangedEventArgs e) { + PropertyValueChangedEventHandler eh = (PropertyValueChangedEventHandler)(Events [PropertyValueChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnResize (EventArgs e) { + base.OnResize (e); + } + + protected virtual void OnSelectedGridItemChanged (SelectedGridItemChangedEventArgs e) { + SelectedGridItemChangedEventHandler eh = (SelectedGridItemChangedEventHandler)(Events [SelectedGridItemChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnSelectedObjectsChanged (EventArgs e) { + EventHandler eh = (EventHandler)(Events [SelectedObjectsChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnSystemColorsChanged (EventArgs e) { + base.OnSystemColorsChanged (e); + } + + protected override void OnVisibleChanged (EventArgs e) { + base.OnVisibleChanged (e); + } + + protected override bool ProcessDialogKey (Keys keyData) { + return base.ProcessDialogKey (keyData); + } + + [EditorBrowsable (EditorBrowsableState.Never)] + protected override void ScaleCore (float dx, float dy) { + base.ScaleCore (dx, dy); + } + + protected override void WndProc (ref Message m) + { + base.WndProc (ref m); + } + #endregion + + #region Events + static object PropertySortChangedEvent = new object (); + static object PropertyTabChangedEvent = new object (); + static object PropertyValueChangedEvent = new object (); + static object SelectedGridItemChangedEvent = new object (); + static object SelectedObjectsChangedEvent = new object (); + + public event EventHandler PropertySortChanged { + add { Events.AddHandler (PropertySortChangedEvent, value); } + remove { Events.RemoveHandler (PropertySortChangedEvent, value); } + } + + public event PropertyTabChangedEventHandler PropertyTabChanged { + add { Events.AddHandler (PropertyTabChangedEvent, value); } + remove { Events.RemoveHandler (PropertyTabChangedEvent, value); } + } + + public event PropertyValueChangedEventHandler PropertyValueChanged { + add { Events.AddHandler (PropertyValueChangedEvent, value); } + remove { Events.RemoveHandler (PropertyValueChangedEvent, value); } + } + + public event SelectedGridItemChangedEventHandler SelectedGridItemChanged { + add { Events.AddHandler (SelectedGridItemChangedEvent, value); } + remove { Events.RemoveHandler (SelectedGridItemChangedEvent, value); } + } + + public event EventHandler SelectedObjectsChanged { + add { Events.AddHandler (SelectedObjectsChangedEvent, value); } + remove { Events.RemoveHandler (SelectedObjectsChangedEvent, value); } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageChanged { + add { base.BackgroundImageChanged += value; } + remove { base.BackgroundImageChanged -= value; } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageLayoutChanged { + add { base.BackgroundImageLayoutChanged += value; } + remove { base.BackgroundImageLayoutChanged -= value; } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler ForeColorChanged { + add { base.ForeColorChanged += value; } + remove { base.ForeColorChanged -= value; } + } + + [EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + public new event KeyEventHandler KeyDown { + add { base.KeyDown += value; } + remove { base.KeyDown -= value; } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Advanced)] + public new event KeyPressEventHandler KeyPress { + add { base.KeyPress += value; } + remove { base.KeyPress -= value; } + } + + [EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + public new event KeyEventHandler KeyUp { + add { base.KeyUp += value; } + remove { base.KeyUp -= value; } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Advanced)] + public new event MouseEventHandler MouseDown { + add { base.MouseDown += value; } + remove { base.MouseDown -= value; } + } + + [EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + public new event EventHandler MouseEnter { + add { base.MouseEnter += value; } + remove { base.MouseEnter -= value; } + } + + [EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + public new event EventHandler MouseLeave { + add { base.MouseLeave += value; } + remove { base.MouseLeave -= value; } + } + + [EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + public new event MouseEventHandler MouseMove { + add { base.MouseMove += value; } + remove { base.MouseMove -= value; } + } + + [EditorBrowsable(EditorBrowsableState.Advanced)] + [Browsable(false)] + public new event MouseEventHandler MouseUp { + add { base.MouseUp += value; } + remove { base.MouseUp -= value; } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler PaddingChanged { + add { base.PaddingChanged += value; } + remove { base.PaddingChanged -= value; } + } + + [Browsable(false)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + #endregion + + #region PropertyTabCollection Class + public class PropertyTabCollection : ICollection, IEnumerable + { + ArrayList property_tabs; + ArrayList property_tabs_scopes; + PropertyGrid property_grid; + + internal PropertyTabCollection (PropertyGrid propertyGrid) + { + property_grid = propertyGrid; + property_tabs = new ArrayList (); + property_tabs_scopes = new ArrayList (); + } + + public PropertyTab this[int index] { + get { return (PropertyTab)property_tabs[index]; } + } + + bool ICollection.IsSynchronized { + get { return property_tabs.IsSynchronized; } + } + + void ICollection.CopyTo (Array dest, int index) + { + property_tabs.CopyTo (dest, index); + } + + object ICollection.SyncRoot { + get { return property_tabs.SyncRoot; } + } + + public IEnumerator GetEnumerator () + { + return property_tabs.GetEnumerator (); + } + + public int Count { + get { return property_tabs.Count; } + } + + public void AddTabType (Type propertyTabType) + { + AddTabType (propertyTabType, PropertyTabScope.Global); + } + + public void AddTabType (Type propertyTabType, PropertyTabScope tabScope) + { + if (propertyTabType == null) + throw new ArgumentNullException ("propertyTabType"); + + // Avoid duplicates + if (this.Contains (propertyTabType)) + return; + PropertyTab tab = property_grid.CreatePropertyTab (propertyTabType); + if (tab != null) { + property_tabs.Add (tab); + property_tabs_scopes.Add (tabScope); + } + property_grid.RefreshToolbar (this); + } + + internal PropertyTabScope GetTabScope (PropertyTab tab) + { + if (tab == null) + throw new ArgumentNullException ("tab"); + + int index = property_tabs.IndexOf (tab); + if (index != -1) + return (PropertyTabScope)property_tabs_scopes[index]; + return PropertyTabScope.Global; + } + + internal void InsertTab (int index, PropertyTab propertyTab, PropertyTabScope tabScope) + { + if (propertyTab == null) + throw new ArgumentNullException ("propertyTab"); + + if (!this.Contains (propertyTab.GetType ())) { + property_tabs.Insert (index, propertyTab); + property_tabs_scopes.Insert (index, tabScope); + } + } + + internal bool Contains (Type propertyType) + { + if (propertyType == null) + throw new ArgumentNullException ("propertyType"); + + foreach (PropertyTab t in property_tabs) { + if (t.GetType () == propertyType) + return true; + } + return false; + } + + internal PropertyTab this[Type tabType] { + get { + foreach (PropertyTab tab in property_tabs) { + if (tabType == tab.GetType ()) + return tab; + } + return null; + } + } + + public void Clear (PropertyTabScope tabScope) + { + ArrayList toRemove = new ArrayList (); + for (int i=0; i < property_tabs_scopes.Count; i++) { + if ((PropertyTabScope)property_tabs_scopes[i] == tabScope) + toRemove.Add (i); + } + foreach (int indexToRemove in toRemove) { + property_tabs.RemoveAt (indexToRemove); + property_tabs_scopes.RemoveAt (indexToRemove); + } + property_grid.RefreshToolbar (this); + } + + public void RemoveTabType (Type propertyTabType) + { + if (propertyTabType == null) + throw new ArgumentNullException ("propertyTabType"); + + ArrayList toRemove = new ArrayList (); + for (int i=0; i < property_tabs.Count; i++) { + if (property_tabs[i].GetType () == propertyTabType) + toRemove.Add (i); + } + foreach (int indexToRemove in toRemove) { + property_tabs.RemoveAt (indexToRemove); + property_tabs_scopes.RemoveAt (indexToRemove); + } + property_grid.RefreshToolbar (this); + } + } + #endregion // PropertyTabCollection Class + + #region Private Helper Methods + + private GridItem FindFirstPropertyItem (GridItem root) + { + if (root.GridItemType == GridItemType.Property) + return root; + + foreach (GridItem item in root.GridItems) { + GridItem subitem = FindFirstPropertyItem (item); + if (subitem != null) + return subitem; + } + + return null; + } + + private GridEntry GetDefaultPropertyItem (GridEntry rootItem, PropertyTab propertyTab) + { + if (rootItem == null || rootItem.GridItems.Count == 0 || propertyTab == null) + return null; + object[] propertyOwners = rootItem.Values; + if (propertyOwners == null || propertyOwners.Length == 0 || propertyOwners[0] == null) + return null; + + GridItem defaultSelected = null; + if (propertyOwners.Length > 1) + defaultSelected = rootItem.GridItems[0]; + else { + PropertyDescriptor defaultProperty = propertyTab.GetDefaultProperty (propertyOwners[0]); + if (defaultProperty != null) + defaultSelected = FindItem (defaultProperty.Name, rootItem); + if (defaultSelected == null) + defaultSelected = FindFirstPropertyItem (rootItem); + } + + return defaultSelected as GridEntry; + } + + private GridEntry FindItem (string name, GridEntry rootItem) + { + if (rootItem == null || name == null) + return null; + + if (property_sort == PropertySort.Alphabetical || property_sort == PropertySort.NoSort) { + foreach (GridItem item in rootItem.GridItems) { + if (item.Label == name) { + return (GridEntry)item; + } + } + } else if (property_sort == PropertySort.Categorized || + property_sort == PropertySort.CategorizedAlphabetical) { + foreach (GridItem categoryItem in rootItem.GridItems) { + foreach (GridItem item in categoryItem.GridItems) { + if (item.Label == name) { + return (GridEntry)item; + } + } + } + } + + return null; + } + + private void OnResetPropertyClick (object sender, EventArgs e) + { + ResetSelectedProperty(); + } + + private void OnDescriptionClick (object sender, EventArgs e) + { + this.HelpVisible = !this.HelpVisible; + description_menuitem.Checked = this.HelpVisible; + } + + private void PopulateGrid (object[] objects) + { + if (objects.Length > 0) { + root_grid_item = new RootGridEntry (this, objects); + root_grid_item.Expanded = true; + UpdateSortLayout (root_grid_item); + } else { + root_grid_item = null; + } + } + + private void UpdateSortLayout (GridEntry rootItem) + { + if (rootItem == null) + return; + + GridItemCollection reordered = new GridItemCollection (); + + if (property_sort == PropertySort.Alphabetical || property_sort == PropertySort.NoSort) { + alphabetic_toolbarbutton.Pushed = true; + categorized_toolbarbutton.Pushed = false; + foreach (GridItem item in rootItem.GridItems) { + if (item.GridItemType == GridItemType.Category) { + foreach (GridItem categoryChild in item.GridItems) { + reordered.Add (categoryChild); + ((GridEntry)categoryChild).SetParent (rootItem); + } + } else { + reordered.Add (item); + } + } + } else if (property_sort == PropertySort.Categorized || + property_sort == PropertySort.CategorizedAlphabetical) { + alphabetic_toolbarbutton.Pushed = false; + categorized_toolbarbutton.Pushed = true; + GridItemCollection categories = new GridItemCollection (); + + foreach (GridItem item in rootItem.GridItems) { + if (item.GridItemType == GridItemType.Category) { + categories.Add (item); + continue; + } + + string categoryName = item.PropertyDescriptor.Category; + if (categoryName == null) + categoryName = UNCATEGORIZED_CATEGORY_LABEL; + GridItem category_item = rootItem.GridItems [categoryName]; + if (category_item == null) + category_item = categories [categoryName]; + + if (category_item == null) { + // Create category grid items if they already don't + category_item = new CategoryGridEntry (this, categoryName, rootItem); + category_item.Expanded = true; + categories.Add (category_item); + } + + category_item.GridItems.Add (item); + ((GridEntry)item).SetParent (category_item); + } + + reordered.AddRange (categories); + } + + rootItem.GridItems.Clear (); + rootItem.GridItems.AddRange (reordered); + } + + private void help_panel_Paint(object sender, PaintEventArgs e) { + e.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(help_panel.BackColor), help_panel.ClientRectangle ); + e.Graphics.DrawRectangle(SystemPens.ControlDark, 0,0,help_panel.Width-1,help_panel.Height-1 ); + } + + #endregion // Private Helper Methods + +#region Internal helper classes + // as we can not change the color for BorderStyle.FixedSingle and we need the correct + // ClientRectangle so that the ScrollBar doesn't draw over the border we need this class + internal class BorderHelperControl : Widget { + + public BorderHelperControl () + { + BackColor = ThemeEngine.Current.ColorWindow; + } + + protected override void OnPaint (PaintEventArgs e) + { + e.Graphics.DrawRectangle (SystemPens.ControlDark, 0 , 0 , Width - 1, Height - 1); + base.OnPaint (e); + } + + protected override void OnSizeChanged (EventArgs e) + { + if (Widgets.Count == 1) { + Widget control = Widgets [0]; + + if (control.Location.X != 1 || control.Location.Y != 1) + control.Location = new Point (1, 1); + + control.Width = ClientRectangle.Width - 2; + control.Height = ClientRectangle.Height - 2; + } + base.OnSizeChanged (e); + } + } + + private class PropertyToolBarSeparator : ToolStripSeparator + { + public PropertyToolBarSeparator () + { + } + } + + private class PropertyToolBarButton : ToolStripButton + { + private PropertyTab property_tab; + + public PropertyToolBarButton () + { + } + + public PropertyToolBarButton (PropertyTab propertyTab) + { + if (propertyTab == null) + throw new ArgumentNullException ("propertyTab"); + property_tab = propertyTab; + } + + public PropertyTab PropertyTab { + get { return property_tab; } + } + + public bool Pushed { + get { return base.Checked; } + set { base.Checked = value; } + } + + public ToolBarButtonStyle Style { + get { return ToolBarButtonStyle.PushButton; } + set { } + } + } + + // needed! this little helper makes it possible to draw a different toolbar border + // and toolbar backcolor in ThemeWin32Classic + internal class PropertyToolBar : ToolStrip + { + ToolBarAppearance appearance; + + public PropertyToolBar () + { + SetStyle (Widgetstyles.ResizeRedraw, true); + GripStyle = ToolStripGripStyle.Hidden; + appearance = ToolBarAppearance.Normal; + } + + public bool ShowToolTips { + get { return base.ShowItemToolTips; } + set { base.ShowItemToolTips = value; } + } + + public ToolBarAppearance Appearance { + get { return appearance; } + set { + if (value == Appearance) + return; + + switch (value) { + case ToolBarAppearance.Flat: + Renderer = new ToolStripSystemRenderer (); + appearance = ToolBarAppearance.Flat; + break; + case ToolBarAppearance.Normal: + ProfessionalColorTable table = new ProfessionalColorTable (); + table.UseSystemColors = true; + Renderer = new ToolStripProfessionalRenderer (table); + appearance = ToolBarAppearance.Normal; + break; + } + } + } + } + + + [MonoInternalNote ("not sure what this class does, but it's listed as a type converter for a property in this class, and this causes problems if it's not present")] + private class SelectedObjectConverter : TypeConverter + { + } +#endregion + } +} diff --git a/source/ShiftUI/Widgets/PropertyGridCommands.cs b/source/ShiftUI/Widgets/PropertyGridCommands.cs new file mode 100644 index 0000000..d3d376e --- /dev/null +++ b/source/ShiftUI/Widgets/PropertyGridCommands.cs @@ -0,0 +1,47 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. +// +// Authors: +// Jonathan Chambers jonathan.chambers@ansys.com +// + + +// COMPLETE + +using System; +using System.ComponentModel.Design; + +namespace ShiftUI.PropertyGridInternal +{ + public class PropertyGridCommands + { + public PropertyGridCommands() + { + } + + public static readonly CommandID Commands; + public static readonly CommandID Description; + public static readonly CommandID Hide; + public static readonly CommandID Reset; + protected static readonly Guid wfcMenuCommand; + protected static readonly Guid wfcMenuGroup; + } +} diff --git a/source/ShiftUI/Widgets/PropertyGridTextBox.cs b/source/ShiftUI/Widgets/PropertyGridTextBox.cs new file mode 100644 index 0000000..a815f28 --- /dev/null +++ b/source/ShiftUI/Widgets/PropertyGridTextBox.cs @@ -0,0 +1,320 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jonathan Chambers (jonathan.chambers@ansys.com) +// + +// COMPLETE + +using System; +using System.Drawing; +using System.ComponentModel; + +namespace ShiftUI.PropertyGridInternal +{ + internal class PGTextBox : TextBox + { + private bool _focusing = false; + + public void FocusAt (Point location) + { + _focusing = true; + Point pnt = PointToClient (location); + XplatUI.SendMessage (Handle, Msg.WM_LBUTTONDOWN, new IntPtr ((int)MsgButtons.MK_LBUTTON), Widget.MakeParam (pnt.X, pnt.Y)); + } + + protected override bool IsInputKey (Keys keyData) + { + // To be handled by the PropertyGridView + if ((keyData & Keys.Alt) != 0 && + (keyData & Keys.KeyCode) == Keys.Down) + return true; + return base.IsInputKey (keyData); + } + + protected override void WndProc (ref Message m) + { + // Swallow the first MOUSEMOVE after the focusing WM_LBUTTONDOWN + if (_focusing && m.Msg == (int)Msg.WM_MOUSEMOVE) { + _focusing = false; + return; + } + base.WndProc (ref m); + } + } + + internal class PropertyGridTextBox : ShiftUI.UserWidget, IMessageFilter + { + #region Private Members + + private PGTextBox textbox; + private Button dialog_button; + private Button dropdown_button; + private bool validating = false; + private bool filtering = false; + + #endregion Private Members + + #region Contructors + public PropertyGridTextBox() { + dialog_button = new Button(); + dropdown_button = new Button(); + textbox = new PGTextBox (); + + SuspendLayout(); + + dialog_button.Dock = DockStyle.Right; + dialog_button.BackColor = SystemColors.Control; + dialog_button.Size = new Size(16, 16); + dialog_button.TabIndex = 1; + dialog_button.Visible = false; + dialog_button.Click += new System.EventHandler(dialog_button_Click); + + dropdown_button.Dock = DockStyle.Right; + dropdown_button.BackColor = SystemColors.Control; + dropdown_button.Size = new Size(16, 16); + dropdown_button.TabIndex = 2; + dropdown_button.Visible = false; + dropdown_button.Click += new System.EventHandler(dropdown_button_Click); + + textbox.AutoSize = false; + textbox.BorderStyle = BorderStyle.None; + textbox.Dock = DockStyle.Fill; + textbox.TabIndex = 3; + + Widgets.Add(textbox); + Widgets.Add(dropdown_button); + Widgets.Add(dialog_button); + + SetStyle (Widgetstyles.Selectable, true); + + ResumeLayout(false); + + dropdown_button.Paint+=new PaintEventHandler(dropdown_button_Paint); + dialog_button.Paint+=new PaintEventHandler(dialog_button_Paint); + textbox.DoubleClick+=new EventHandler(textbox_DoubleClick); + textbox.KeyDown+=new KeyEventHandler(textbox_KeyDown); + textbox.GotFocus+=new EventHandler(textbox_GotFocus); + } + + + #endregion Contructors + + #region Protected Instance Properties + + protected override void OnGotFocus (EventArgs args) + { + base.OnGotFocus (args); + // force-disable selection + textbox.has_been_focused = true; + textbox.Focus (); + textbox.SelectionLength = 0; + } + + #endregion + + #region Public Instance Properties + + public bool DialogButtonVisible { + get{ + return dialog_button.Visible; + } + set { + dialog_button.Visible = value; + } + } + public bool DropDownButtonVisible { + get{ + return dropdown_button.Visible; + } + set { + dropdown_button.Visible = value; + } + } + + public new Color ForeColor { + get { + return base.ForeColor; + } + set { + textbox.ForeColor = value; + dropdown_button.ForeColor = value; + dialog_button.ForeColor = value; + base.ForeColor = value; + } + } + + public new Color BackColor { + get { + return base.BackColor; + } + set { + textbox.BackColor = value; + base.BackColor = value; + } + } + public bool ReadOnly { + get { + return textbox.ReadOnly; + } + set { + textbox.ReadOnly = value; + } + } + + public new string Text { + get { + return textbox.Text; + } + set { + textbox.Text = value; + } + } + + public char PasswordChar { + set { textbox.PasswordChar = value; } + } + + #endregion Public Instance Properties + + #region Events + static object DropDownButtonClickedEvent = new object (); + static object DialogButtonClickedEvent = new object (); + static object ToggleValueEvent = new object (); + static object KeyDownEvent = new object (); + static object ValidateEvent = new object (); + + public event EventHandler DropDownButtonClicked { + add { Events.AddHandler (DropDownButtonClickedEvent, value); } + remove { Events.RemoveHandler (DropDownButtonClickedEvent, value); } + } + + public event EventHandler DialogButtonClicked { + add { Events.AddHandler (DialogButtonClickedEvent, value); } + remove { Events.RemoveHandler (DialogButtonClickedEvent, value); } + } + + public event EventHandler ToggleValue { + add { Events.AddHandler (ToggleValueEvent, value); } + remove { Events.RemoveHandler (ToggleValueEvent, value); } + } + + public new event KeyEventHandler KeyDown { + add { Events.AddHandler (KeyDownEvent, value); } + remove { Events.RemoveHandler (KeyDownEvent, value); } + } + + public new event CancelEventHandler Validate { + add { Events.AddHandler (ValidateEvent, value); } + remove { Events.RemoveHandler (ValidateEvent, value); } + } + #endregion Events + + #region Private Helper Methods + + private void dropdown_button_Paint(object sender, PaintEventArgs e) + { + ThemeEngine.Current.CPDrawComboButton(e.Graphics, dropdown_button.ClientRectangle, dropdown_button.ButtonState); + } + + private void dialog_button_Paint(object sender, PaintEventArgs e) { + // best way to draw the ellipse? + e.Graphics.DrawString("...", new Font(Font,FontStyle.Bold), Brushes.Black, 0,0); + } + + private void dropdown_button_Click(object sender, EventArgs e) { + EventHandler eh = (EventHandler)(Events [DropDownButtonClickedEvent]); + if (eh != null) + eh (this, e); + } + + private void dialog_button_Click(object sender, EventArgs e) { + EventHandler eh = (EventHandler)(Events [DialogButtonClickedEvent]); + if (eh != null) + eh (this, e); + } + + #endregion Private Helper Methods + + internal void SendMouseDown (Point screenLocation) + { + Point clientLocation = PointToClient (screenLocation); + XplatUI.SendMessage (Handle, Msg.WM_LBUTTONDOWN, new IntPtr ((int) MsgButtons.MK_LBUTTON), Widget.MakeParam (clientLocation.X, clientLocation.Y)); + textbox.FocusAt (screenLocation); + } + + private void textbox_DoubleClick(object sender, EventArgs e) { + EventHandler eh = (EventHandler)(Events [ToggleValueEvent]); + if (eh != null) + eh (this, e); + } + + private void textbox_KeyDown(object sender, KeyEventArgs e) { + KeyEventHandler eh = (KeyEventHandler)(Events [KeyDownEvent]); + if (eh != null) + eh (this, e); + } + + private void textbox_GotFocus(object sender, EventArgs e) { + if (!filtering) { + filtering = true; + Application.AddMessageFilter ((IMessageFilter)this); + } + } + + + protected override void DestroyHandle () + { + Application.RemoveMessageFilter ((IMessageFilter)this); + filtering = false; + base.DestroyHandle (); + } + + bool IMessageFilter.PreFilterMessage(ref Message m) + { + // validating check is to allow whatever UI code to execute + // without filtering messages (i.e. error dialogs, etc) + // + if (!validating && m.HWnd != textbox.Handle && textbox.Focused && + (m.Msg == (int)Msg.WM_LBUTTONDOWN || + m.Msg == (int)Msg.WM_MBUTTONDOWN || + m.Msg == (int)Msg.WM_RBUTTONDOWN || + m.Msg == (int)Msg.WM_NCLBUTTONDOWN || + m.Msg == (int)Msg.WM_NCMBUTTONDOWN || + m.Msg == (int)Msg.WM_NCRBUTTONDOWN)) { + CancelEventHandler validateHandler = (CancelEventHandler)(Events [ValidateEvent]); + if (validateHandler != null) { + CancelEventArgs args = new CancelEventArgs (); + validating = true; + validateHandler (this, args); + validating = false; + if (!args.Cancel) { + Application.RemoveMessageFilter ((IMessageFilter)this); + filtering = false; + } + return args.Cancel; + } + } + return false; + } + } +} diff --git a/source/ShiftUI/Widgets/PropertyGridView.cs b/source/ShiftUI/Widgets/PropertyGridView.cs new file mode 100644 index 0000000..ea26d0e --- /dev/null +++ b/source/ShiftUI/Widgets/PropertyGridView.cs @@ -0,0 +1,1101 @@ + +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005-2008 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Jonathan Chambers (jonathan.chambers@ansys.com) +// Ivan N. Zlatev (contact@i-nz.net) +// +// + +// NOT COMPLETE + +using System; +using System.Collections; +using System.ComponentModel.Design; +using System.Drawing; +using System.Drawing.Design; +using System.ComponentModel; +using System.Threading; +using ShiftUI.Design; +using System.Collections.Generic; + +namespace ShiftUI.PropertyGridInternal { + internal class PropertyGridView : ScrollableWidget, IWindowsFormsEditorService { + + #region Private Members + private const char PASSWORD_PAINT_CHAR = '\u25cf'; // the dot char + private const char PASSWORD_TEXT_CHAR = '*'; + private const int V_INDENT = 16; + private const int ENTRY_SPACING = 2; + private const int RESIZE_WIDTH = 3; + private const int BUTTON_WIDTH = 25; + private const int VALUE_PAINT_WIDTH = 19; + private const int VALUE_PAINT_INDENT = 27; + private double splitter_percent = .5; + private int row_height; + private int font_height_padding = 3; + private PropertyGridTextBox grid_textbox; + private PropertyGrid property_grid; + private bool resizing_grid; + private PropertyGridDropDown dropdown_form; + private Form dialog_form; + private ImplicitVScrollBar vbar; + private StringFormat string_format; + private Font bold_font; + private Brush inactive_text_brush; + private ListBox dropdown_list; + private Point last_click; + private Padding dropdown_form_padding; + #endregion + + #region Contructors + public PropertyGridView (PropertyGrid propertyGrid) { + property_grid = propertyGrid; + + string_format = new StringFormat (); + string_format.FormatFlags = StringFormatFlags.NoWrap; + string_format.Trimming = StringTrimming.None; + + grid_textbox = new PropertyGridTextBox (); + grid_textbox.DropDownButtonClicked +=new EventHandler (DropDownButtonClicked); + grid_textbox.DialogButtonClicked +=new EventHandler (DialogButtonClicked); + + dropdown_form = new PropertyGridDropDown (); + dropdown_form.FormBorderStyle = FormBorderStyle.None; + dropdown_form.StartPosition = FormStartPosition.Manual; + dropdown_form.ShowInTaskbar = false; + + dialog_form = new Form (); + dialog_form.StartPosition = FormStartPosition.Manual; + dialog_form.FormBorderStyle = FormBorderStyle.None; + dialog_form.ShowInTaskbar = false; + + dropdown_form_padding = new Padding (0, 0, 2, 2); + + row_height = Font.Height + font_height_padding; + + grid_textbox.Visible = false; + grid_textbox.Font = this.Font; + grid_textbox.BackColor = SystemColors.Window; + grid_textbox.Validate += new CancelEventHandler (grid_textbox_Validate); + grid_textbox.ToggleValue+=new EventHandler (grid_textbox_ToggleValue); + grid_textbox.KeyDown+=new KeyEventHandler (grid_textbox_KeyDown); + this.Widgets.Add (grid_textbox); + + vbar = new ImplicitVScrollBar (); + vbar.Visible = false; + vbar.Value = 0; + vbar.ValueChanged+=new EventHandler (VScrollBar_HandleValueChanged); + vbar.Dock = DockStyle.Right; + this.Widgets.AddImplicit (vbar); + + resizing_grid = false; + + bold_font = new Font (this.Font, FontStyle.Bold); + inactive_text_brush = new SolidBrush (ThemeEngine.Current.ColorGrayText); + + ForeColorChanged+=new EventHandler (RedrawEvent); + BackColorChanged+=new System.EventHandler (RedrawEvent); + FontChanged+=new EventHandler (RedrawEvent); + + SetStyle (Widgetstyles.Selectable, true); + SetStyle (Widgetstyles.DoubleBuffer, true); + SetStyle (Widgetstyles.UserPaint, true); + SetStyle (Widgetstyles.AllPaintingInWmPaint, true); + SetStyle (Widgetstyles.ResizeRedraw, true); + } + + #endregion + + private GridEntry RootGridItem { + get { return (GridEntry)property_grid.RootGridItem; } + } + + private GridEntry SelectedGridItem { + get { return (GridEntry)property_grid.SelectedGridItem; } + set { property_grid.SelectedGridItem = value; } + } + + #region Protected Instance Methods + + protected override void OnFontChanged (EventArgs e) { + base.OnFontChanged (e); + + bold_font = new Font (this.Font, FontStyle.Bold); + row_height = Font.Height + font_height_padding; + } + + private void InvalidateItemLabel (GridEntry item) + { + Invalidate (new Rectangle (0, ((GridEntry)item).Top, SplitterLocation, row_height)); + } + + private void InvalidateItem (GridEntry item) + { + if (item == null) + return; + + Rectangle rect = new Rectangle (0, item.Top, Width, row_height); + Invalidate (rect); + + if (item.Expanded) { + rect = new Rectangle (0, item.Top + row_height, Width, + Height - (item.Top + row_height)); + Invalidate (rect); + } + } + + // [+] expanding is handled in OnMouseDown, so in order to prevent + // duplicate expanding ignore it here. + // + protected override void OnDoubleClick (EventArgs e) + { + if (this.SelectedGridItem != null && this.SelectedGridItem.Expandable && + !this.SelectedGridItem.PlusMinusBounds.Contains (last_click)) + this.SelectedGridItem.Expanded = !this.SelectedGridItem.Expanded; + else + ToggleValue (this.SelectedGridItem); + } + + protected override void OnPaint (PaintEventArgs e) + { + // Background + e.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), ClientRectangle); + + int yLoc = -vbar.Value*row_height; + if (this.RootGridItem != null) + DrawGridItems (this.RootGridItem.GridItems, e, 1, ref yLoc); + + UpdateScrollBar (); + } + + protected override void OnMouseWheel (MouseEventArgs e) + { + if (vbar == null || !vbar.Visible) + return; + if (e.Delta < 0) + vbar.Value = Math.Min (vbar.Maximum - GetVisibleRowsCount () + 1, vbar.Value + SystemInformation.MouseWheelScrollLines); + else + vbar.Value = Math.Max (0, vbar.Value - SystemInformation.MouseWheelScrollLines); + base.OnMouseWheel (e); + } + + + protected override void OnMouseMove (MouseEventArgs e) { + if (this.RootGridItem == null) + return; + + if (resizing_grid) { + int loc = Math.Max (e.X,2*V_INDENT); + SplitterPercent = 1.0*loc/Width; + } + if (e.X > SplitterLocation - RESIZE_WIDTH && e.X < SplitterLocation + RESIZE_WIDTH) + this.Cursor = Cursors.SizeWE; + else + this.Cursor = Cursors.Default; + base.OnMouseMove (e); + } + + protected override void OnMouseDown (MouseEventArgs e) + { + base.OnMouseDown (e); + last_click = e.Location; + if (this.RootGridItem == null) + return; + + if (e.X > SplitterLocation - RESIZE_WIDTH && e.X < SplitterLocation + RESIZE_WIDTH) { + resizing_grid = true; + } + else { + int offset = -vbar.Value*row_height; + GridItem foundItem = GetSelectedGridItem (this.RootGridItem.GridItems, e.Y, ref offset); + + if (foundItem != null) { + if (foundItem.Expandable && ((GridEntry)foundItem).PlusMinusBounds.Contains (e.X, e.Y)) + foundItem.Expanded = !foundItem.Expanded; + + this.SelectedGridItem = (GridEntry)foundItem; + if (!GridLabelHitTest (e.X)) { + // send mouse down so we get the carret under cursor + grid_textbox.SendMouseDown (PointToScreen (e.Location)); + } + } + } + } + + protected override void OnMouseUp (MouseEventArgs e) { + resizing_grid = false; + base.OnMouseUp (e); + } + + protected override void OnResize (EventArgs e) { + base.OnResize (e); + if (this.SelectedGridItem != null) // initialized already + UpdateView (); + } + + private void UnfocusSelection () + { + Select (this); + } + + private void FocusSelection () + { + Select (grid_textbox); + } + + protected override bool ProcessDialogKey (Keys keyData) { + GridEntry selectedItem = this.SelectedGridItem; + if (selectedItem != null + && grid_textbox.Visible) { + switch (keyData) { + case Keys.Enter: + if (TrySetEntry (selectedItem, grid_textbox.Text)) + UnfocusSelection (); + return true; + case Keys.Escape: + if (selectedItem.IsEditable) + UpdateItem (selectedItem); // reset value + UnfocusSelection (); + return true; + case Keys.Tab: + FocusSelection (); + return true; + default: + return false; + } + } + return base.ProcessDialogKey (keyData); + } + + private bool TrySetEntry (GridEntry entry, object value) + { + if (entry == null || grid_textbox.Text.Equals (entry.ValueText)) + return true; + + if (entry.IsEditable || !entry.IsEditable && (entry.HasCustomEditor || entry.AcceptedValues != null) || + !entry.IsMerged || entry.HasMergedValue || + (!entry.HasMergedValue && grid_textbox.Text != String.Empty)) { + string error = null; + bool changed = entry.SetValue (value, out error); + if (!changed && error != null) { + if (property_grid.ShowError (error, MessageBoxButtons.OKCancel) == DialogResult.Cancel) { + UpdateItem (entry); // restore value, repaint, etc + UnfocusSelection (); + } + return false; + } + } + UpdateItem (entry); // restore value, repaint, etc + return true; + } + + protected override bool IsInputKey (Keys keyData) { + switch (keyData) { + case Keys.Left: + case Keys.Right: + case Keys.Enter: + case Keys.Escape: + case Keys.Up: + case Keys.Down: + case Keys.PageDown: + case Keys.PageUp: + case Keys.Home: + case Keys.End: + return true; + default: + return false; + } + } + + private GridEntry MoveUpFromItem (GridEntry item, int up_count) + { + GridItemCollection items; + int index; + + /* move back up the visible rows (and up the hierarchy as necessary) until + up_count == 0, or we reach the top of the display */ + while (up_count > 0) { + items = item.Parent != null ? item.Parent.GridItems : this.RootGridItem.GridItems; + index = items.IndexOf (item); + + if (index == 0) { + if (item.Parent.GridItemType == GridItemType.Root) // we're at the top row + return item; + item = (GridEntry)item.Parent; + up_count --; + } + else { + GridEntry prev_item = (GridEntry)items[index-1]; + if (prev_item.Expandable && prev_item.Expanded) { + item = (GridEntry)prev_item.GridItems[prev_item.GridItems.Count - 1]; + } + else { + item = prev_item; + } + up_count --; + } + } + return item; + } + + private GridEntry MoveDownFromItem (GridEntry item, int down_count) + { + while (down_count > 0) { + /* if we're a parent node and we're expanded, move to our first child */ + if (item.Expandable && item.Expanded) { + item = (GridEntry)item.GridItems[0]; + down_count--; + } + else { + GridItem searchItem = item; + GridItemCollection searchItems = searchItem.Parent.GridItems; + int searchIndex = searchItems.IndexOf (searchItem); + + while (searchIndex == searchItems.Count - 1) { + searchItem = searchItem.Parent; + + if (searchItem == null || searchItem.Parent == null) + break; + + searchItems = searchItem.Parent.GridItems; + searchIndex = searchItems.IndexOf (searchItem); + } + + if (searchIndex == searchItems.Count - 1) { + /* if we got all the way back to the root with no nodes after + us, the original item was the last one */ + return item; + } + else { + item = (GridEntry)searchItems[searchIndex+1]; + down_count--; + } + } + } + + return item; + } + + protected override void OnKeyDown (KeyEventArgs e) + { + GridEntry selectedItem = this.SelectedGridItem; + + if (selectedItem == null) { + /* XXX not sure what MS does, but at least we shouldn't crash */ + base.OnKeyDown (e); + return; + } + + switch (e.KeyData & Keys.KeyCode) { + case Keys.Left: + if (e.Widget) { + if (SplitterLocation > 2 * V_INDENT) + SplitterPercent -= 0.01; + + e.Handled = true; + break; + } + else { + /* if the node is expandable and is expanded, collapse it. + otherwise, act just like the user pressed up */ + if (selectedItem.Expandable && selectedItem.Expanded) { + selectedItem.Expanded = false; + e.Handled = true; + break; + } + else + goto case Keys.Up; + } + case Keys.Right: + if (e.Widget) { + if (SplitterLocation < Width) + SplitterPercent += 0.01; + + e.Handled = true; + break; + } + else { + /* if the node is expandable and not expanded, expand it. + otherwise, act just like the user pressed down */ + if (selectedItem.Expandable && !selectedItem.Expanded) { + selectedItem.Expanded = true; + e.Handled = true; + break; + } + else + goto case Keys.Down; + } + case Keys.Enter: + /* toggle the expanded state of the selected item */ + if (selectedItem.Expandable) { + selectedItem.Expanded = !selectedItem.Expanded; + } + e.Handled = true; + break; + case Keys.Up: + this.SelectedGridItem = MoveUpFromItem (selectedItem, 1); + e.Handled = true; + break; + case Keys.Down: + this.SelectedGridItem = MoveDownFromItem (selectedItem, 1); + e.Handled = true; + break; + case Keys.PageUp: + this.SelectedGridItem = MoveUpFromItem (selectedItem, vbar.LargeChange); + e.Handled = true; + break; + case Keys.PageDown: + this.SelectedGridItem = MoveDownFromItem (selectedItem, vbar.LargeChange); + e.Handled = true; + break; + case Keys.End: + /* find the last, most deeply nested visible item */ + GridEntry item = (GridEntry)this.RootGridItem.GridItems[this.RootGridItem.GridItems.Count - 1]; + while (item.Expandable && item.Expanded) + item = (GridEntry)item.GridItems[item.GridItems.Count - 1]; + this.SelectedGridItem = item; + e.Handled = true; + break; + case Keys.Home: + this.SelectedGridItem = (GridEntry)this.RootGridItem.GridItems[0]; + e.Handled = true; + break; + } + + base.OnKeyDown (e); + } + + #endregion + + #region Private Helper Methods + + private int SplitterLocation { + get { + return (int)(splitter_percent*Width); + } + } + + private double SplitterPercent { + set { + int old_splitter_location = SplitterLocation; + + splitter_percent = Math.Max (Math.Min (value, .9),.1); + + if (old_splitter_location != SplitterLocation) { + int x = old_splitter_location > SplitterLocation ? SplitterLocation : old_splitter_location; + Invalidate (new Rectangle (x, 0, Width - x - (vbar.Visible ? vbar.Width : 0), Height)); + UpdateItem (this.SelectedGridItem); + } + } + get { + return splitter_percent; + } + } + + private bool GridLabelHitTest (int x) + { + if (0 <= x && x <= splitter_percent * this.Width) + return true; + return false; + } + + private GridItem GetSelectedGridItem (GridItemCollection grid_items, int y, ref int current) { + foreach (GridItem child_grid_item in grid_items) { + if (y > current && y < current + row_height) { + return child_grid_item; + } + current += row_height; + if (child_grid_item.Expanded) { + GridItem foundItem = GetSelectedGridItem (child_grid_item.GridItems, y, ref current); + if (foundItem != null) + return foundItem; + } + } + return null; + } + + private int GetVisibleItemsCount (GridEntry entry) + { + if (entry == null) + return 0; + + int count = 0; + foreach (GridEntry e in entry.GridItems) { + count += 1; + if (e.Expandable && e.Expanded) + count += GetVisibleItemsCount (e); + } + return count; + } + + private int GetVisibleRowsCount () + { + return this.Height / row_height; + } + + private void UpdateScrollBar () + { + if (this.RootGridItem == null) + return; + + int visibleRows = GetVisibleRowsCount (); + int openedItems = GetVisibleItemsCount (this.RootGridItem); + if (openedItems > visibleRows) { + vbar.Visible = true; + vbar.SmallChange = 1; + vbar.LargeChange = visibleRows; + vbar.Maximum = Math.Max (0, openedItems - 1); + } else { + vbar.Value = 0; + vbar.Visible = false; + } + UpdateGridTextBoxBounds (this.SelectedGridItem); + } + + // private bool GetScrollBarVisible () + // { + // if (this.RootGridItem == null) + // return false; + // + // int visibleRows = GetVisibleRowsCount (); + // int openedItems = GetVisibleItemsCount (this.RootGridItem); + // if (openedItems > visibleRows) + // return true; + // return false; + // } + #region Drawing Code + + private void DrawGridItems (GridItemCollection grid_items, PaintEventArgs pevent, int depth, ref int yLoc) { + foreach (GridItem grid_item in grid_items) { + DrawGridItem ((GridEntry)grid_item, pevent, depth, ref yLoc); + if (grid_item.Expanded) + DrawGridItems (grid_item.GridItems, pevent, (grid_item.GridItemType == GridItemType.Category) ? depth : depth+1, ref yLoc); + } + } + + private void DrawGridItemLabel (GridEntry grid_item, PaintEventArgs pevent, int depth, Rectangle rect) { + Font font = this.Font; + Brush brush; + + if (grid_item.GridItemType == GridItemType.Category) { + font = bold_font; + brush = SystemBrushes.ControlText; + + pevent.Graphics.DrawString (grid_item.Label, font, brush, rect.X + 1, rect.Y + ENTRY_SPACING); + if (grid_item == this.SelectedGridItem) { + SizeF size = pevent.Graphics.MeasureString (grid_item.Label, font); + WidgetPaint.DrawFocusRectangle (pevent.Graphics, new Rectangle (rect.X + 1, rect.Y+ENTRY_SPACING, (int)size.Width, (int)size.Height)); + } + } + else { + if (grid_item == this.SelectedGridItem) { + Rectangle highlight = rect; + if (depth > 1) { + highlight.X -= V_INDENT; + highlight.Width += V_INDENT; + } + pevent.Graphics.FillRectangle (SystemBrushes.Highlight, highlight); + // Label + brush = SystemBrushes.HighlightText; + } + else { + brush = grid_item.IsReadOnly ? inactive_text_brush : SystemBrushes.ControlText; + } + } + pevent.Graphics.DrawString (grid_item.Label, font, brush, + new Rectangle (rect.X + 1, rect.Y + ENTRY_SPACING, rect.Width - ENTRY_SPACING, rect.Height - ENTRY_SPACING), + string_format); + } + + private void DrawGridItemValue (GridEntry grid_item, PaintEventArgs pevent, int depth, Rectangle rect) + { + if (grid_item.PropertyDescriptor == null) + return; + + int xLoc = SplitterLocation+ENTRY_SPACING; + if (grid_item.PaintValueSupported) { + pevent.Graphics.DrawRectangle (Pens.Black, SplitterLocation + ENTRY_SPACING, + rect.Y + 2, VALUE_PAINT_WIDTH + 1, row_height - ENTRY_SPACING*2); + grid_item.PaintValue (pevent.Graphics, + new Rectangle (SplitterLocation + ENTRY_SPACING + 1, + rect.Y + ENTRY_SPACING + 1, + VALUE_PAINT_WIDTH, row_height - (ENTRY_SPACING*2 +1))); + xLoc += VALUE_PAINT_INDENT; + } + + Font font = this.Font; + if (grid_item.IsResetable || !grid_item.HasDefaultValue) + font = bold_font; + Brush brush = grid_item.IsReadOnly ? inactive_text_brush : SystemBrushes.ControlText; + string valueText = String.Empty; + if (!grid_item.IsMerged || grid_item.IsMerged && grid_item.HasMergedValue) { + if (grid_item.IsPassword) + valueText = new String (PASSWORD_PAINT_CHAR, grid_item.ValueText.Length); + else + valueText = grid_item.ValueText; + } + pevent.Graphics.DrawString (valueText, font, + brush, + new RectangleF (xLoc + ENTRY_SPACING, rect.Y + ENTRY_SPACING, + ClientRectangle.Width-(xLoc), row_height - ENTRY_SPACING*2), + string_format); + } + + private void DrawGridItem (GridEntry grid_item, PaintEventArgs pevent, int depth, ref int yLoc) { + if (yLoc > -row_height && yLoc < ClientRectangle.Height) { + // Left column + pevent.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (property_grid.LineColor), + 0, yLoc, V_INDENT, row_height); + + if (grid_item.GridItemType == GridItemType.Category) { + pevent.Graphics.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (property_grid.CategoryForeColor), depth*V_INDENT,yLoc,ClientRectangle.Width-(depth*V_INDENT), row_height); + } + + DrawGridItemLabel (grid_item, pevent, + depth, + new Rectangle (depth * V_INDENT, yLoc, SplitterLocation - depth * V_INDENT, row_height)); + DrawGridItemValue (grid_item, pevent, + depth, + new Rectangle (SplitterLocation + ENTRY_SPACING , yLoc, + ClientRectangle.Width - SplitterLocation - ENTRY_SPACING - (vbar.Visible ? vbar.Width : 0), + row_height)); + + if (grid_item.GridItemType != GridItemType.Category) { + Pen pen = ThemeEngine.Current.ResPool.GetPen (property_grid.LineColor); + // vertical divider line + pevent.Graphics.DrawLine (pen, SplitterLocation, yLoc, SplitterLocation, yLoc + row_height); + + // draw the horizontal line + pevent.Graphics.DrawLine (pen, 0, yLoc + row_height, ClientRectangle.Width, yLoc + row_height); + } + + if (grid_item.Expandable) { + int y = yLoc + row_height / 2 - ENTRY_SPACING + 1; + grid_item.PlusMinusBounds = DrawPlusMinus (pevent.Graphics, (depth - 1) * V_INDENT + ENTRY_SPACING + 1, + y, grid_item.Expanded, grid_item.GridItemType == GridItemType.Category); + } + + } + grid_item.Top = yLoc; + yLoc += row_height; + } + + private Rectangle DrawPlusMinus (Graphics g, int x, int y, bool expanded, bool category) { + Rectangle bounds = new Rectangle (x, y, 8, 8); + if (!category) g.FillRectangle (Brushes.White, bounds); + Pen pen = ThemeEngine.Current.ResPool.GetPen (property_grid.ViewForeColor); + g.DrawRectangle (pen, bounds); + g.DrawLine (pen, x+2, y+4, x + 6, y+4); + if (!expanded) + g.DrawLine (pen, x+4, y+2, x+4, y+6); + + return bounds; + } + + #endregion + + #region Event Handling + private void RedrawEvent (object sender, System.EventArgs e) + { + Refresh (); + } + + #endregion + + private void listBox_MouseUp (object sender, MouseEventArgs e) { + AcceptListBoxSelection (sender); + } + + private void listBox_KeyDown (object sender, KeyEventArgs e) + { + switch (e.KeyData & Keys.KeyCode) { + case Keys.Enter: + AcceptListBoxSelection (sender); + return; + case Keys.Escape: + CloseDropDown (); + return; + } + } + + void AcceptListBoxSelection (object sender) + { + GridEntry entry = this.SelectedGridItem as GridEntry; + if (entry != null) { + grid_textbox.Text = (string) ((ListBox) sender).SelectedItem; + CloseDropDown (); + if (TrySetEntry (entry, grid_textbox.Text)) + UnfocusSelection (); + } + } + + private void DropDownButtonClicked (object sender, EventArgs e) + { + DropDownEdit (); + } + + private void DropDownEdit () + { + GridEntry entry = SelectedGridItem as GridEntry; + if (entry == null) + return; + + if (entry.HasCustomEditor) { + entry.EditValue ((IWindowsFormsEditorService) this); + } else { + if (dropdown_form.Visible) { + CloseDropDown (); + } + else { + ICollection std_values = entry.AcceptedValues; + if (std_values != null) { + if (dropdown_list == null) { + dropdown_list = new ListBox (); + dropdown_list.KeyDown += new KeyEventHandler (listBox_KeyDown); + dropdown_list.MouseUp += new MouseEventHandler (listBox_MouseUp); + } + dropdown_list.Items.Clear (); + dropdown_list.BorderStyle = BorderStyle.FixedSingle; + int selected_index = 0; + int i = 0; + string valueText = entry.ValueText; + foreach (object obj in std_values) { + dropdown_list.Items.Add (obj); + if (valueText != null && valueText.Equals (obj)) + selected_index = i; + i++; + } + dropdown_list.Height = row_height * Math.Min (dropdown_list.Items.Count, 15); + dropdown_list.Width = ClientRectangle.Width - SplitterLocation - (vbar.Visible ? vbar.Width : 0); + if (std_values.Count > 0) + dropdown_list.SelectedIndex = selected_index; + DropDownWidget (dropdown_list); + } + } + } + } + + private void DialogButtonClicked (object sender, EventArgs e) + { + GridEntry entry = this.SelectedGridItem as GridEntry; + if (entry != null && entry.HasCustomEditor) + { + entry.Value = GetResultFromEditor(entry.Value); + } + } + + public object GetResultFromEditor(object val) + { + var EditorDialogs = new Dictionary(); + EditorDialogs.Add(typeof(string[]), new Dialogs.StringArrayDialog()); + EditorDialogs.Add(typeof(ComboBox.ObjectCollection), new Dialogs.ComboBoxEditorDialog((val as ComboBox.ObjectCollection).Owner)); + object retval = val; + try + { + var dialog = EditorDialogs[retval.GetType()]; + dialog.ShowEditor(); + retval = dialog.Value; + } + catch (Exception ex) + { + MessageBox.Show($"Object {retval} is not valid for the given property. {ex.Message}", "Property Grid"); + retval = val; + } + MessageBox.Show($"val: {val.GetType().Name}, retval: {retval.GetType().Name}", "Property Grid"); + return retval; + } + + private void VScrollBar_HandleValueChanged (object sender, EventArgs e) + { + UpdateView (); + } + + private void grid_textbox_ToggleValue (object sender, EventArgs args) + { + ToggleValue (this.SelectedGridItem); + } + + private void grid_textbox_KeyDown (object sender, KeyEventArgs e) + { + switch (e.KeyData & Keys.KeyCode) { + case Keys.Down: + if (e.Alt) { + DropDownEdit (); + e.Handled = true; + } + break; + } + } + + private void grid_textbox_Validate (object sender, CancelEventArgs args) + { + if (!TrySetEntry (this.SelectedGridItem, grid_textbox.Text)) + args.Cancel = true; + } + + private void ToggleValue (GridEntry entry) + { + if (entry != null && !entry.IsReadOnly && entry.GridItemType == GridItemType.Property) + entry.ToggleValue (); + } + + internal void UpdateItem (GridEntry entry) + { + if (entry == null || entry.GridItemType == GridItemType.Category || + entry.GridItemType == GridItemType.Root) { + grid_textbox.Visible = false; + InvalidateItem (entry); + return; + } + + if (this.SelectedGridItem == entry) { + SuspendLayout (); + grid_textbox.Visible = false; + if (entry.IsResetable || !entry.HasDefaultValue) + grid_textbox.Font = bold_font; + else + grid_textbox.Font = this.Font; + + if (entry.IsReadOnly) { + grid_textbox.DropDownButtonVisible = false; + grid_textbox.DialogButtonVisible = false; + grid_textbox.ReadOnly = true; + grid_textbox.ForeColor = SystemColors.GrayText; + } else { + grid_textbox.DropDownButtonVisible = entry.AcceptedValues != null || + entry.EditorStyle == UITypeEditorEditStyle.DropDown; + grid_textbox.DialogButtonVisible = entry.EditorStyle == UITypeEditorEditStyle.Modal; + grid_textbox.ForeColor = SystemColors.ControlText; + grid_textbox.ReadOnly = !entry.IsEditable; + } + UpdateGridTextBoxBounds (entry); + grid_textbox.PasswordChar = entry.IsPassword ? PASSWORD_TEXT_CHAR : '\0'; + grid_textbox.Text = entry.IsMerged && !entry.HasMergedValue ? String.Empty : entry.ValueText; + grid_textbox.Visible = true; + InvalidateItem (entry); + ResumeLayout (false); + } else { + grid_textbox.Visible = false; + } + } + + private void UpdateGridTextBoxBounds (GridEntry entry) + { + if (entry == null || this.RootGridItem == null) + return; + + int y = -vbar.Value*row_height; + CalculateItemY (entry, this.RootGridItem.GridItems, ref y); + int x = SplitterLocation + ENTRY_SPACING + (entry.PaintValueSupported ? VALUE_PAINT_INDENT : 0); + grid_textbox.SetBounds (x + ENTRY_SPACING, y + ENTRY_SPACING, + ClientRectangle.Width - ENTRY_SPACING - x - (vbar.Visible ? vbar.Width : 0), + row_height - ENTRY_SPACING); + } + + // Calculates the sum of the heights of all items before the one + // + private bool CalculateItemY (GridEntry entry, GridItemCollection items, ref int y) + { + foreach (GridItem item in items) { + if (item == entry) + return true; + y += row_height; + if (item.Expandable && item.Expanded) + if (CalculateItemY (entry, item.GridItems, ref y)) + return true; + } + return false; + } + + private void ScrollToItem (GridEntry item) + { + if (item == null || this.RootGridItem == null) + return; + + int itemY = -vbar.Value*row_height; + int value = vbar.Value;; + CalculateItemY (item, this.RootGridItem.GridItems, ref itemY); + if (itemY < 0) // the new item is above the viewable area + value += itemY / row_height; + else if (itemY + row_height > Height) // the new item is below the viewable area + value += ((itemY + row_height) - Height) / row_height + 1; + if (value >= vbar.Minimum && value <= vbar.Maximum) + vbar.Value = value; + } + + internal void SelectItem (GridEntry oldItem, GridEntry newItem) + { + if (oldItem != null) + InvalidateItemLabel (oldItem); + if (newItem != null) { + UpdateItem (newItem); + ScrollToItem (newItem); + } else { + grid_textbox.Visible = false; + vbar.Visible = false; + } + } + + internal void UpdateView () + { + UpdateScrollBar (); + Invalidate (); + Update (); + UpdateItem (this.SelectedGridItem); + } + + internal void ExpandItem (GridEntry item) + { + UpdateItem (this.SelectedGridItem); + Invalidate (new Rectangle (0, item.Top, Width, Height - item.Top)); + } + + internal void CollapseItem (GridEntry item) + { + UpdateItem (this.SelectedGridItem); + Invalidate (new Rectangle (0, item.Top, Width, Height - item.Top)); + } + + private void ShowDropDownControl (Widget control, bool resizeable) + { + dropdown_form.Size = control.Size; + control.Dock = DockStyle.Fill; + + if (resizeable) { + dropdown_form.Padding = dropdown_form_padding; + dropdown_form.Width += dropdown_form_padding.Right; + dropdown_form.Height += dropdown_form_padding.Bottom; + dropdown_form.FormBorderStyle = FormBorderStyle.Sizable; + dropdown_form.SizeGripStyle = SizeGripStyle.Show; + } else { + dropdown_form.FormBorderStyle = FormBorderStyle.None; + dropdown_form.SizeGripStyle = SizeGripStyle.Hide; + dropdown_form.Padding = Padding.Empty; + } + + dropdown_form.Widgets.Add (control); + dropdown_form.Width = Math.Max (ClientRectangle.Width - SplitterLocation - (vbar.Visible ? vbar.Width : 0), + control.Width); + dropdown_form.Location = PointToScreen (new Point (grid_textbox.Right - dropdown_form.Width, grid_textbox.Location.Y + row_height)); + RepositionInScreenWorkingArea (dropdown_form); + Point location = dropdown_form.Location; + + Form owner = FindForm (); + owner.AddOwnedForm (dropdown_form); + dropdown_form.Show (); + if (dropdown_form.Location != location) + dropdown_form.Location = location; + control.Show(); + ShiftUI.MSG msg = new MSG (); + object queue_id = XplatUI.StartLoop (Thread.CurrentThread); + control.Focus (); + while (dropdown_form.Visible && XplatUI.GetMessage (queue_id, ref msg, IntPtr.Zero, 0, 0)) { + switch (msg.message) { + case Msg.WM_NCLBUTTONDOWN: + case Msg.WM_NCMBUTTONDOWN: + case Msg.WM_NCRBUTTONDOWN: + case Msg.WM_LBUTTONDOWN: + case Msg.WM_MBUTTONDOWN: + case Msg.WM_RBUTTONDOWN: + if (!HwndInControl (dropdown_form, msg.hwnd)) + CloseDropDown (); + break; + case Msg.WM_ACTIVATE: + case Msg.WM_NCPAINT: + if (owner.window.Handle == msg.hwnd) + CloseDropDown (); + break; + } + XplatUI.TranslateMessage (ref msg); + XplatUI.DispatchMessage (ref msg); + } + XplatUI.EndLoop (Thread.CurrentThread); + } + + private void RepositionInScreenWorkingArea (Form form) + { + Rectangle workingArea = Screen.FromControl (form).WorkingArea; + if (!workingArea.Contains (form.Bounds)) { + int x, y; + x = form.Location.X; + y = form.Location.Y; + + if (form.Location.X < workingArea.X) + x = workingArea.X; + + if (form.Location.Y + form.Size.Height > workingArea.Height) { + Point aboveTextBox = PointToScreen (new Point (grid_textbox.Right - form.Width, grid_textbox.Location.Y)); + y = aboveTextBox.Y - form.Size.Height; + } + + form.Location = new Point (x, y); + } + } + + private bool HwndInControl (Widget c, IntPtr hwnd) + { + if (hwnd == c.window.Handle) + return true; + foreach (Widget cc in c.Widgets.GetAllWidgets ()) { + if (HwndInControl (cc, hwnd)) + return true; + } + return false; + } + #endregion + + #region IWindowsFormsEditorService Members + + + public void CloseDropDown () + { + dropdown_form.Hide (); + dropdown_form.Widgets.Clear (); + } + + public void DropDownWidget (Widget control) + { + bool resizeable = this.SelectedGridItem != null ? SelectedGridItem.EditorResizeable : false; + ShowDropDownControl (control, resizeable); + } + + public ShiftUI.DialogResult ShowDialog (Form dialog) { + return dialog.ShowDialog (this); + } + + #endregion + + internal class PropertyGridDropDown : Form + { + protected override CreateParams CreateParams { + get { + CreateParams cp = base.CreateParams; + cp.Style = unchecked ((int)(WindowStyles.WS_POPUP | WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_CLIPCHILDREN)); + cp.ExStyle |= (int)(WindowExStyles.WS_EX_TOPMOST); + return cp; + } + } + + } + } +} diff --git a/source/ShiftUI/Widgets/RadioButton.cs b/source/ShiftUI/Widgets/RadioButton.cs new file mode 100644 index 0000000..83a4f7c --- /dev/null +++ b/source/ShiftUI/Widgets/RadioButton.cs @@ -0,0 +1,391 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Text; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + [DefaultProperty("Checked")] + [DefaultEvent("CheckedChanged")] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + [DefaultBindingProperty ("Checked")] + [ToolboxItem ("ShiftUI.Design.AutoSizeToolboxItem," + Consts.AssemblySystem_Design)] + //[Designer ("ShiftUI.Design.RadioButtonDesigner, " + Consts.AssemblySystem_Design)] + [ToolboxWidget] + public class RadioButton : ButtonBase { + #region Local Variables + internal Appearance appearance; + internal bool auto_check; + internal ContentAlignment radiobutton_alignment; + internal CheckState check_state; + #endregion // Local Variables + + #region RadioButtonAccessibleObject Subclass + [ComVisible(true)] + public class RadioButtonAccessibleObject : ButtonBaseAccessibleObject { + #region RadioButtonAccessibleObject Local Variables + private new RadioButton owner; + #endregion // RadioButtonAccessibleObject Local Variables + + #region RadioButtonAccessibleObject Constructors + public RadioButtonAccessibleObject(RadioButton owner) : base(owner) { + this.owner = owner; + } + #endregion // RadioButtonAccessibleObject Constructors + + #region RadioButtonAccessibleObject Properties + public override string DefaultAction { + get { + return "Select"; + } + } + + public override AccessibleRole Role { + get { + return AccessibleRole.RadioButton; + } + } + + public override AccessibleStates State { + get { + AccessibleStates retval; + + retval = AccessibleStates.Default; + + if (owner.check_state == CheckState.Checked) { + retval |= AccessibleStates.Checked; + } + + if (owner.Focused) { + retval |= AccessibleStates.Focused; + } + + if (owner.CanFocus) { + retval |= AccessibleStates.Focusable; + } + + return retval; + } + } + #endregion // RadioButtonAccessibleObject Properties + + #region RadioButtonAccessibleObject Methods + public override void DoDefaultAction() { + owner.PerformClick(); + } + #endregion // RadioButtonAccessibleObject Methods + } + #endregion // RadioButtonAccessibleObject Sub-class + + #region Public Constructors + public RadioButton() { + appearance = Appearance.Normal; + auto_check = true; + radiobutton_alignment = ContentAlignment.MiddleLeft; + TextAlign = ContentAlignment.MiddleLeft; + TabStop = false; + } + #endregion // Public Constructors + + #region Private Methods + + // When getting OnEnter we need to set Checked as true in case none of the sibling radio + // buttons is checked. + private void PerformDefaultCheck () + { + // if we are already checked, no need to check the other Widgets + if (!auto_check || Checked) + return; + + bool is_any_selected = false; + Widget c = Parent; + if (c != null) { + for (int i = 0; i < c.Widgets.Count; i++) { + RadioButton rb = c.Widgets [i] as RadioButton; + if (rb == null || !rb.auto_check) + continue; + + if (rb.check_state == CheckState.Checked) { + is_any_selected = true; + break; + } + } + } + + if (!is_any_selected) + Checked = true; + } + + private void UpdateSiblings() { + Widget c; + + if (auto_check == false) { + return; + } + + // Remove tabstop property from and uncheck our radio-button siblings + c = this.Parent; + if (c != null) { + for (int i = 0; i < c.Widgets.Count; i++) { + if ((this != c.Widgets[i]) && (c.Widgets[i] is RadioButton)) { + if (((RadioButton)(c.Widgets[i])).auto_check) { + c.Widgets[i].TabStop = false; + ((RadioButton)(c.Widgets[i])).Checked = false; + } + } + } + } + + this.TabStop = true; + } + + internal override void Draw (PaintEventArgs pe) { + // FIXME: This should be called every time something that can affect it + // is changed, not every paint. Can only change so many things at a time. + + // Figure out where our text and image should go + Rectangle glyph_rectangle; + Rectangle text_rectangle; + Rectangle image_rectangle; + + ThemeEngine.Current.CalculateRadioButtonTextAndImageLayout (this, Point.Empty, out glyph_rectangle, out text_rectangle, out image_rectangle); + + // Draw our button + if (FlatStyle != FlatStyle.System && Appearance != Appearance.Button) + ThemeEngine.Current.DrawRadioButton (pe.Graphics, this, glyph_rectangle, text_rectangle, image_rectangle, pe.ClipRectangle); + else + ThemeEngine.Current.DrawRadioButton (pe.Graphics, this.ClientRectangle, this); + } + + internal override Size GetPreferredSizeCore (Size proposedSize) + { + if (this.AutoSize) + return ThemeEngine.Current.CalculateRadioButtonAutoSize (this); + + return base.GetPreferredSizeCore (proposedSize); + } + #endregion // Private Methods + + #region Public Instance Properties + [DefaultValue(Appearance.Normal)] + [Localizable(true)] + public Appearance Appearance { + get { + return appearance; + } + + set { + if (value != appearance) { + appearance = value; + EventHandler eh = (EventHandler)(Events [AppearanceChangedEvent]); + if (eh != null) + eh (this, EventArgs.Empty); + if (Parent != null) + Parent.PerformLayout (this, "Appearance"); + Invalidate(); + } + } + } + + [DefaultValue(true)] + public bool AutoCheck { + get { + return auto_check; + } + + set { + auto_check = value; + } + } + + [Localizable(true)] + [DefaultValue(ContentAlignment.MiddleLeft)] + public ContentAlignment CheckAlign { + get { + return radiobutton_alignment; + } + + set { + if (value != radiobutton_alignment) { + radiobutton_alignment = value; + + Invalidate(); + } + } + } + + [DefaultValue(false)] + [SettingsBindable (true)] + [Bindable (true, BindingDirection.OneWay)] + public bool Checked { + get { + if (check_state != CheckState.Unchecked) { + return true; + } + return false; + } + + set { + if (value && (check_state != CheckState.Checked)) { + check_state = CheckState.Checked; + Invalidate(); + UpdateSiblings(); + OnCheckedChanged(EventArgs.Empty); + } else if (!value && (check_state != CheckState.Unchecked)) { + TabStop = false; + check_state = CheckState.Unchecked; + Invalidate(); + OnCheckedChanged(EventArgs.Empty); + } + } + } + + [DefaultValue(false)] + public new bool TabStop { + get { return base.TabStop; } + set { base.TabStop = value; } + } + + [DefaultValue(ContentAlignment.MiddleLeft)] + [Localizable(true)] + public override ContentAlignment TextAlign { + get { return base.TextAlign; } + set { base.TextAlign = value; } + } + #endregion // Public Instance Properties + + #region Protected Instance Properties + protected override CreateParams CreateParams { + get { + SetStyle(Widgetstyles.AllPaintingInWmPaint, true); + SetStyle(Widgetstyles.UserPaint, true); + + return base.CreateParams; + } + } + + protected override Size DefaultSize { + get { + return ThemeEngine.Current.RadioButtonDefaultSize; + } + } + #endregion // Protected Instance Properties + + #region Public Instance Methods + public void PerformClick() { + OnClick(EventArgs.Empty); + } + + public override string ToString() { + return base.ToString() + ", Checked: " + this.Checked; + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + protected override AccessibleObject CreateAccessibilityInstance() { + AccessibleObject ao; + + ao = base.CreateAccessibilityInstance (); + ao.role = AccessibleRole.RadioButton; + + return ao; + } + + protected virtual void OnCheckedChanged(EventArgs e) { + EventHandler eh = (EventHandler)(Events [CheckedChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnClick(EventArgs e) { + if (auto_check) { + if (!Checked) { + Checked = true; + } + } else { + Checked = !Checked; + } + + base.OnClick (e); + } + + protected override void OnEnter(EventArgs e) { + PerformDefaultCheck (); + base.OnEnter(e); + } + + protected override void OnHandleCreated(EventArgs e) { + base.OnHandleCreated(e); + } + + protected override void OnMouseUp(MouseEventArgs mevent) { + base.OnMouseUp(mevent); + } + + protected override bool ProcessMnemonic(char charCode) { + if (IsMnemonic(charCode, Text) == true) { + Select(); + PerformClick(); + return true; + } + + return base.ProcessMnemonic(charCode); + } + #endregion // Protected Instance Methods + + #region Events + static object AppearanceChangedEvent = new object (); + static object CheckedChangedEvent = new object (); + + public event EventHandler AppearanceChanged { + add { Events.AddHandler (AppearanceChangedEvent, value); } + remove { Events.RemoveHandler (AppearanceChangedEvent, value); } + } + + public event EventHandler CheckedChanged { + add { Events.AddHandler (CheckedChangedEvent, value); } + remove { Events.RemoveHandler (CheckedChangedEvent, value); } + } + + [Browsable(false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler DoubleClick { + add { base.DoubleClick += value; } + remove { base.DoubleClick -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event MouseEventHandler MouseDoubleClick { + add { base.MouseDoubleClick += value; } + remove { base.MouseDoubleClick -= value; } + } + #endregion // Events + } +} diff --git a/source/ShiftUI/Widgets/RichTextBox.cs b/source/ShiftUI/Widgets/RichTextBox.cs new file mode 100644 index 0000000..c1d2325 --- /dev/null +++ b/source/ShiftUI/Widgets/RichTextBox.cs @@ -0,0 +1,2089 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005-2006 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok +// +// + +// #define DEBUG + +using System; +using System.Collections; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Text; +using System.Runtime.InteropServices; +using RTF=ShiftUI.RTF; + +namespace ShiftUI { + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [Docking (DockingBehavior.Ask)] + [ComVisible (true)] + [Designer ("ShiftUI.Design.RichTextBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [ToolboxWidget] + public class RichTextBox : TextBoxBase { + #region Local Variables + internal bool auto_word_select; + internal int bullet_indent; + internal bool detect_urls; + private bool reuse_line; // Sometimes we are loading text with already available lines + internal int margin_right; + internal float zoom; + private StringBuilder rtf_line; + + private RtfSectionStyle rtf_style; // Replaces individual style + // properties so we can revert + private Stack rtf_section_stack; + + private RTF.TextMap rtf_text_map; + private int rtf_skip_count; + private int rtf_cursor_x; + private int rtf_cursor_y; + private int rtf_chars; + + private bool enable_auto_drag_drop; + private RichTextBoxLanguageOptions language_option; + private bool rich_text_shortcuts_enabled; + private Color selection_back_color; + #endregion // Local Variables + + #region Public Constructors + public RichTextBox() { + accepts_return = true; + auto_size = false; + auto_word_select = false; + bullet_indent = 0; + base.MaxLength = Int32.MaxValue; + margin_right = 0; + zoom = 1; + base.Multiline = true; + document.CRLFSize = 1; + shortcuts_enabled = true; + base.EnableLinks = true; + richtext = true; + + rtf_style = new RtfSectionStyle (); + rtf_section_stack = null; + + scrollbars = RichTextBoxScrollBars.Both; + alignment = HorizontalAlignment.Left; + LostFocus += new EventHandler(RichTextBox_LostFocus); + GotFocus += new EventHandler(RichTextBox_GotFocus); + BackColor = ThemeEngine.Current.ColorWindow; + backcolor_set = false; + language_option = RichTextBoxLanguageOptions.AutoFontSizeAdjust; + rich_text_shortcuts_enabled = true; + selection_back_color = DefaultBackColor; + ForeColor = ThemeEngine.Current.ColorWindowText; + + base.HScrolled += new EventHandler(RichTextBox_HScrolled); + base.VScrolled += new EventHandler(RichTextBox_VScrolled); + + SetStyle (Widgetstyles.StandardDoubleClick, false); + } + #endregion // Public Constructors + + #region Private & Internal Methods + + internal override void HandleLinkClicked (LinkRectangle link) + { + OnLinkClicked (new LinkClickedEventArgs (link.LinkTag.LinkText)); + } + + internal override Color ChangeBackColor (Color backColor) + { + if (backColor == Color.Empty) { + backcolor_set = false; + if (!ReadOnly) { + backColor = SystemColors.Window; + } + } + return backColor; + } + + internal override void RaiseSelectionChanged() + { + OnSelectionChanged (EventArgs.Empty); + } + + private void RichTextBox_LostFocus(object sender, EventArgs e) { + Invalidate(); + } + + private void RichTextBox_GotFocus(object sender, EventArgs e) { + Invalidate(); + } + #endregion // Private & Internal Methods + + #region Public Instance Properties + [Browsable (false)] + public override bool AllowDrop { + get { + return base.AllowDrop; + } + + set { + base.AllowDrop = value; + } + } + + [DefaultValue(false)] + [DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)] + [RefreshProperties (RefreshProperties.Repaint)] + [EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public override bool AutoSize { + get { + return auto_size; + } + + set { + base.AutoSize = value; + } + } + + [MonoTODO ("Value not respected, always true")] + [DefaultValue(false)] + public bool AutoWordSelection { + get { return auto_word_select; } + set { auto_word_select = value; } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override System.Drawing.Image BackgroundImage { + get { return base.BackgroundImage; } + set { base.BackgroundImage = value; } + } + + [Browsable (false)] + [EditorBrowsable (EditorBrowsableState.Never)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + [DefaultValue(0)] + [Localizable(true)] + public int BulletIndent { + get { + return bullet_indent; + } + + set { + bullet_indent = value; + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool CanRedo { + get { + return document.undo.CanRedo; + } + } + + [DefaultValue(true)] + public bool DetectUrls { + get { return base.EnableLinks; } + set { base.EnableLinks = value; } + } + + [MonoTODO ("Stub, does nothing")] + [DefaultValue (false)] + public bool EnableAutoDragDrop { + get { return enable_auto_drag_drop; } + set { enable_auto_drag_drop = value; } + } + + public override Font Font { + get { + return base.Font; + } + + set { + if (font != value) { + Line start; + Line end; + + if (auto_size) { + if (PreferredHeight != Height) { + Height = PreferredHeight; + } + } + + base.Font = value; + + // Font changes always set the whole doc to that font + start = document.GetLine(1); + end = document.GetLine(document.Lines); + document.FormatText(start, 1, end, end.text.Length + 1, base.Font, Color.Empty, Color.Empty, FormatSpecified.Font); + } + } + } + + public override Color ForeColor { + get { + return base.ForeColor; + } + + set { + base.ForeColor = value; + } + } + + [MonoTODO ("Stub, does nothing")] + [Browsable (false)] + [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public RichTextBoxLanguageOptions LanguageOption { + get { return language_option; } + set { language_option = value; } + } + + [DefaultValue(Int32.MaxValue)] + public override int MaxLength { + get { return base.MaxLength; } + set { base.MaxLength = value; } + } + + [DefaultValue(true)] + public override bool Multiline { + get { + return base.Multiline; + } + + set { + base.Multiline = value; + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string RedoActionName { + get { + return document.undo.RedoActionName; + } + } + + [MonoTODO ("Stub, does nothing")] + [Browsable (false)] + [DefaultValue (true)] + [EditorBrowsable (EditorBrowsableState.Never)] + public bool RichTextShortcutsEnabled { + get { return rich_text_shortcuts_enabled; } + set { rich_text_shortcuts_enabled = value; } + } + + [DefaultValue(0)] + [Localizable(true)] + [MonoTODO ("Stub, does nothing")] + [MonoInternalNote ("Teach TextControl.RecalculateLine to consider the right margin as well")] + public int RightMargin { + get { + return margin_right; + } + + set { + margin_right = value; + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [RefreshProperties (RefreshProperties.All)] + public string Rtf { + get { + Line start_line; + Line end_line; + + start_line = document.GetLine(1); + end_line = document.GetLine(document.Lines); + return GenerateRTF(start_line, 0, end_line, end_line.text.Length).ToString(); + } + + set { + MemoryStream data; + + document.Empty(); + data = new MemoryStream(Encoding.ASCII.GetBytes(value), false); + + InsertRTFFromStream(data, 0, 1); + + data.Close(); + + Invalidate(); + } + } + + [DefaultValue(RichTextBoxScrollBars.Both)] + [Localizable(true)] + public RichTextBoxScrollBars ScrollBars { + get { + return scrollbars; + } + + set { + if (!Enum.IsDefined (typeof (RichTextBoxScrollBars), value)) + throw new InvalidEnumArgumentException ("value", (int) value, + typeof (RichTextBoxScrollBars)); + + if (value != scrollbars) { + scrollbars = value; + CalculateDocument (); + } + } + } + + [Browsable(false)] + [DefaultValue("")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string SelectedRtf { + get { + return GenerateRTF(document.selection_start.line, document.selection_start.pos, document.selection_end.line, document.selection_end.pos).ToString(); + } + + set { + MemoryStream data; + int x; + int y; + int sel_start; + int chars; + Line line; + LineTag tag; + + if (document.selection_visible) { + document.ReplaceSelection("", false); + } + + sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos); + + data = new MemoryStream(Encoding.ASCII.GetBytes(value), false); + int cursor_x = document.selection_start.pos; + int cursor_y = document.selection_start.line.line_no; + + // The RFT parser by default, when finds our x cursor in 0, it thinks if needs to + // add a new line; but in *this* scenario the line is already created, so force it to reuse it. + // Hackish, but works without touching the heart of the buggy parser. + if (cursor_x == 0) + reuse_line = true; + + InsertRTFFromStream(data, cursor_x, cursor_y, out x, out y, out chars); + data.Close(); + + int nl_length = document.LineEndingLength (XplatUI.RunningOnUnix ? LineEnding.Rich : LineEnding.Hard); + document.CharIndexToLineTag(sel_start + chars + (y - document.selection_start.line.line_no) * nl_length, + out line, out tag, out sel_start); + if (sel_start >= line.text.Length) + sel_start = line.text.Length -1; + + document.SetSelection(line, sel_start); + document.PositionCaret(line, sel_start); + document.DisplayCaret(); + ScrollToCaret(); + OnTextChanged(EventArgs.Empty); + } + } + + [Browsable(false)] + [DefaultValue("")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public override string SelectedText { + get { + return base.SelectedText; + } + + set { + // TextBox/TextBoxBase don't set Modified in this same property + Modified = true; + base.SelectedText = value; + } + } + + [Browsable(false)] + [DefaultValue(HorizontalAlignment.Left)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public HorizontalAlignment SelectionAlignment { + get { + HorizontalAlignment align; + Line start; + Line end; + Line line; + + start = document.ParagraphStart(document.selection_start.line); + align = start.alignment; + + end = document.ParagraphEnd(document.selection_end.line); + + line = start; + + while (true) { + if (line.alignment != align) { + return HorizontalAlignment.Left; + } + + if (line == end) { + break; + } + line = document.GetLine(line.line_no + 1); + } + + return align; + } + + set { + Line start; + Line end; + Line line; + + start = document.ParagraphStart(document.selection_start.line); + + end = document.ParagraphEnd(document.selection_end.line); + + line = start; + + while (true) { + line.alignment = value; + + if (line == end) { + break; + } + line = document.GetLine(line.line_no + 1); + } + this.CalculateDocument(); + } + } + + [MonoTODO ("Stub, does nothing")] + [Browsable (false)] + [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public Color SelectionBackColor { + get { return selection_back_color; } + set { selection_back_color = value; } + } + + [Browsable(false)] + [DefaultValue(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [MonoTODO ("Stub, does nothing")] + public bool SelectionBullet { + get { + return false; + } + + set { + } + } + + [Browsable(false)] + [DefaultValue(0)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [MonoTODO ("Stub, does nothing")] + public int SelectionCharOffset { + get { + return 0; + } + + set { + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Color SelectionColor { + get { + Color color; + LineTag start; + LineTag end; + LineTag tag; + + if (selection_length > 0) { + start = document.selection_start.line.FindTag (document.selection_start.pos + 1); + end = document.selection_start.line.FindTag (document.selection_end.pos); + } else { + start = document.selection_start.line.FindTag (document.selection_start.pos); + end = start; + } + + color = start.Color; + + tag = start; + while (tag != null) { + + if (!color.Equals (tag.Color)) + return Color.Empty; + + if (tag == end) + break; + + tag = document.NextTag (tag); + } + + return color; + } + + set { + if (value == Color.Empty) + value = DefaultForeColor; + + int sel_start; + int sel_end; + + sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos); + sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos); + + document.FormatText (document.selection_start.line, document.selection_start.pos + 1, + document.selection_end.line, document.selection_end.pos + 1, null, + value, Color.Empty, FormatSpecified.Color); + + document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos); + document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos); + + document.UpdateView(document.selection_start.line, 0); + + //Re-Align the caret in case its changed size or position + //probably not necessary here + document.AlignCaret(false); + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Font SelectionFont { + get { + Font font; + LineTag start; + LineTag end; + LineTag tag; + + if (selection_length > 0) { + start = document.selection_start.line.FindTag (document.selection_start.pos + 1); + end = document.selection_start.line.FindTag (document.selection_end.pos); + } else { + start = document.selection_start.line.FindTag (document.selection_start.pos); + end = start; + } + + font = start.Font; + + if (selection_length > 1) { + tag = start; + while (tag != null) { + + if (!font.Equals(tag.Font)) + return null; + + if (tag == end) + break; + + tag = document.NextTag (tag); + } + } + + return font; + } + + set { + int sel_start; + int sel_end; + + sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos); + sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos); + + document.FormatText (document.selection_start.line, document.selection_start.pos + 1, + document.selection_end.line, document.selection_end.pos + 1, value, + Color.Empty, Color.Empty, FormatSpecified.Font); + + document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos); + document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos); + + document.UpdateView(document.selection_start.line, 0); + //Re-Align the caret in case its changed size or position + Document.AlignCaret (false); + + } + } + + [Browsable(false)] + [DefaultValue(0)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [MonoTODO ("Stub, does nothing")] + public int SelectionHangingIndent { + get { + return 0; + } + + set { + } + } + + [Browsable(false)] + [DefaultValue(0)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [MonoTODO ("Stub, does nothing")] + public int SelectionIndent { + get { + return 0; + } + + set { + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public override int SelectionLength { + get { + return base.SelectionLength; + } + + set { + base.SelectionLength = value; + } + } + + [Browsable(false)] + [DefaultValue(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [MonoTODO ("Stub, does nothing")] + public bool SelectionProtected { + get { + return false; + } + + set { + } + } + + [Browsable(false)] + [DefaultValue(0)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [MonoTODO ("Stub, does nothing")] + public int SelectionRightIndent { + get { + return 0; + } + + set { + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [MonoTODO ("Stub, does nothing")] + public int[] SelectionTabs { + get { + return new int[0]; + } + + set { + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public RichTextBoxSelectionTypes SelectionType { + get { + if (document.selection_start == document.selection_end) { + return RichTextBoxSelectionTypes.Empty; + } + + // Lazy, but works + if (SelectedText.Length > 1) { + return RichTextBoxSelectionTypes.MultiChar | RichTextBoxSelectionTypes.Text; + } + + return RichTextBoxSelectionTypes.Text; + } + } + + [DefaultValue(false)] + [MonoTODO ("Stub, does nothing")] + public bool ShowSelectionMargin { + get { + return false; + } + + set { + } + } + + [Localizable(true)] + [RefreshProperties (RefreshProperties.All)] + public override string Text { + get { + return base.Text; + } + + set { + base.Text = value; + } + } + + [Browsable(false)] + public override int TextLength { + get { + return base.TextLength; + } + } + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string UndoActionName { + get { + return document.undo.UndoActionName; + } + } + + [Localizable(true)] + [DefaultValue(1)] + public float ZoomFactor { + get { + return zoom; + } + + set { + zoom = value; + } + } + #endregion // Public Instance Properties + + #region Protected Instance Properties + protected override CreateParams CreateParams { + get { + return base.CreateParams; + } + } + + protected override Size DefaultSize { + get { + return new Size(100, 96); + } + } + #endregion // Protected Instance Properties + + #region Public Instance Methods + public bool CanPaste(DataFormats.Format clipFormat) { + if ((clipFormat.Name == DataFormats.Rtf) || + (clipFormat.Name == DataFormats.Text) || + (clipFormat.Name == DataFormats.UnicodeText)) { + return true; + } + return false; + } + + public int Find(char[] characterSet) { + return Find(characterSet, -1, -1); + } + + public int Find(char[] characterSet, int start) { + return Find(characterSet, start, -1); + } + + public int Find(char[] characterSet, int start, int end) { + Document.Marker start_mark; + Document.Marker end_mark; + Document.Marker result; + + if (start == -1) { + document.GetMarker(out start_mark, true); + } else { + Line line; + LineTag tag; + int pos; + + start_mark = new Document.Marker(); + + document.CharIndexToLineTag(start, out line, out tag, out pos); + start_mark.line = line; + start_mark.tag = tag; + start_mark.pos = pos; + } + + if (end == -1) { + document.GetMarker(out end_mark, false); + } else { + Line line; + LineTag tag; + int pos; + + end_mark = new Document.Marker(); + + document.CharIndexToLineTag(end, out line, out tag, out pos); + end_mark.line = line; + end_mark.tag = tag; + end_mark.pos = pos; + } + + if (document.FindChars(characterSet, start_mark, end_mark, out result)) { + return document.LineTagToCharIndex(result.line, result.pos); + } + + return -1; + } + + public int Find(string str) { + return Find(str, -1, -1, RichTextBoxFinds.None); + } + + public int Find(string str, int start, int end, RichTextBoxFinds options) { + Document.Marker start_mark; + Document.Marker end_mark; + Document.Marker result; + + if (start == -1) { + document.GetMarker(out start_mark, true); + } else { + Line line; + LineTag tag; + int pos; + + start_mark = new Document.Marker(); + + document.CharIndexToLineTag(start, out line, out tag, out pos); + + start_mark.line = line; + start_mark.tag = tag; + start_mark.pos = pos; + } + + if (end == -1) { + document.GetMarker(out end_mark, false); + } else { + Line line; + LineTag tag; + int pos; + + end_mark = new Document.Marker(); + + document.CharIndexToLineTag(end, out line, out tag, out pos); + + end_mark.line = line; + end_mark.tag = tag; + end_mark.pos = pos; + } + + if (document.Find(str, start_mark, end_mark, out result, options)) { + return document.LineTagToCharIndex(result.line, result.pos); + } + + return -1; + } + + public int Find(string str, int start, RichTextBoxFinds options) { + return Find(str, start, -1, options); + } + + public int Find(string str, RichTextBoxFinds options) { + return Find(str, -1, -1, options); + } + + + internal override char GetCharFromPositionInternal (Point p) + { + LineTag tag; + int pos; + + PointToTagPos (p, out tag, out pos); + + if (pos >= tag.Line.text.Length) + return '\n'; + + return tag.Line.text[pos]; + } + + public override int GetCharIndexFromPosition(Point pt) { + LineTag tag; + int pos; + + PointToTagPos(pt, out tag, out pos); + + return document.LineTagToCharIndex(tag.Line, pos); + } + + public override int GetLineFromCharIndex(int index) { + Line line; + LineTag tag; + int pos; + + document.CharIndexToLineTag(index, out line, out tag, out pos); + + return line.LineNo - 1; + } + + public override Point GetPositionFromCharIndex(int index) { + Line line; + LineTag tag; + int pos; + + document.CharIndexToLineTag(index, out line, out tag, out pos); + return new Point(line.X + (int)line.widths[pos] + document.OffsetX - document.ViewPortX, + line.Y + document.OffsetY - document.ViewPortY); + } + + public void LoadFile(System.IO.Stream data, RichTextBoxStreamType fileType) { + document.Empty(); + + + // FIXME - ignoring unicode + if (fileType == RichTextBoxStreamType.PlainText) { + StringBuilder sb; + char[] buffer; + + try { + sb = new StringBuilder ((int) data.Length); + buffer = new char [1024]; + } catch { + throw new IOException("Not enough memory to load document"); + } + + StreamReader sr = new StreamReader (data, Encoding.Default, true); + int charsRead = sr.Read (buffer, 0, buffer.Length); + while (charsRead > 0) { + sb.Append (buffer, 0, charsRead); + charsRead = sr.Read (buffer, 0, buffer.Length); + } + + // Remove the EOF converted to an extra EOL by the StreamReader + if (sb.Length > 0 && sb [sb.Length - 1] == '\n') + sb.Remove (sb.Length - 1, 1); + + base.Text = sb.ToString(); + return; + } + + InsertRTFFromStream(data, 0, 1); + + document.PositionCaret (document.GetLine (1), 0); + document.SetSelectionToCaret (true); + ScrollToCaret (); + } + + public void LoadFile(string path) { + LoadFile (path, RichTextBoxStreamType.RichText); + } + + public void LoadFile(string path, RichTextBoxStreamType fileType) { + FileStream data; + + data = null; + + + try { + data = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024); + + LoadFile(data, fileType); + } +#if !DEBUG + catch (Exception ex) { + throw new IOException("Could not open file " + path, ex); + } +#endif + finally { + if (data != null) { + data.Close(); + } + } + } + + public void Paste(DataFormats.Format clipFormat) { + base.Paste(Clipboard.GetDataObject(), clipFormat, false); + } + + public void Redo() + { + if (document.undo.Redo ()) + OnTextChanged (EventArgs.Empty); + } + + public void SaveFile(Stream data, RichTextBoxStreamType fileType) { + Encoding encoding; + int i; + Byte[] bytes; + + + if (fileType == RichTextBoxStreamType.UnicodePlainText) { + encoding = Encoding.Unicode; + } else { + encoding = Encoding.ASCII; + } + + switch(fileType) { + case RichTextBoxStreamType.PlainText: + case RichTextBoxStreamType.TextTextOleObjs: + case RichTextBoxStreamType.UnicodePlainText: { + if (!Multiline) { + bytes = encoding.GetBytes(document.Root.text.ToString()); + data.Write(bytes, 0, bytes.Length); + return; + } + + for (i = 1; i < document.Lines; i++) { + // Normalize the new lines to the system ones + string line_text = document.GetLine (i).TextWithoutEnding () + Environment.NewLine; + bytes = encoding.GetBytes(line_text); + data.Write(bytes, 0, bytes.Length); + } + bytes = encoding.GetBytes(document.GetLine(document.Lines).text.ToString()); + data.Write(bytes, 0, bytes.Length); + return; + } + } + + // If we're here we're saving RTF + Line start_line; + Line end_line; + StringBuilder rtf; + int current; + int total; + + start_line = document.GetLine(1); + end_line = document.GetLine(document.Lines); + rtf = GenerateRTF(start_line, 0, end_line, end_line.text.Length); + total = rtf.Length; + bytes = new Byte[4096]; + + // Let's chunk it so we don't use up all memory... + for (i = 0; i < total; i += 1024) { + if ((i + 1024) < total) { + current = encoding.GetBytes(rtf.ToString(i, 1024), 0, 1024, bytes, 0); + } else { + current = total - i; + current = encoding.GetBytes(rtf.ToString(i, current), 0, current, bytes, 0); + } + data.Write(bytes, 0, current); + } + } + + public void SaveFile(string path) { + if (path.EndsWith(".rtf")) { + SaveFile(path, RichTextBoxStreamType.RichText); + } else { + SaveFile(path, RichTextBoxStreamType.PlainText); + } + } + + public void SaveFile(string path, RichTextBoxStreamType fileType) { + FileStream data; + + data = null; + +// try { + data = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 1024, false); + SaveFile(data, fileType); +// } + +// catch { +// throw new IOException("Could not write document to file " + path); +// } + +// finally { + if (data != null) { + data.Close(); + } +// } + } + + [EditorBrowsable (EditorBrowsableState.Never)] + public new void DrawToBitmap (Bitmap bitmap, Rectangle targetBounds) + { + using (Graphics dc = Graphics.FromImage (bitmap)) + Draw (dc, targetBounds); + } + + #endregion // Public Instance Methods + + #region Protected Instance Methods + protected virtual object CreateRichEditOleCallback() + { + throw new NotImplementedException (); + } + + protected override void OnBackColorChanged (EventArgs e) + { + base.OnBackColorChanged (e); + } + + protected virtual void OnContentsResized (ContentsResizedEventArgs e) + { + ContentsResizedEventHandler eh = (ContentsResizedEventHandler)(Events [ContentsResizedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnContextMenuChanged (EventArgs e) + { + base.OnContextMenuChanged (e); + } + + protected override void OnHandleCreated (EventArgs e) + { + base.OnHandleCreated (e); + } + + protected override void OnHandleDestroyed (EventArgs e) + { + base.OnHandleDestroyed (e); + } + + protected virtual void OnHScroll(EventArgs e) + { + EventHandler eh = (EventHandler)(Events [HScrollEvent]); + if (eh != null) + eh (this, e); + } + + [MonoTODO ("Stub, never called")] + protected virtual void OnImeChange(EventArgs e) { + EventHandler eh = (EventHandler)(Events [ImeChangeEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnLinkClicked(LinkClickedEventArgs e) { + LinkClickedEventHandler eh = (LinkClickedEventHandler)(Events [LinkClickedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnProtected(EventArgs e) { + EventHandler eh = (EventHandler)(Events [ProtectedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnRightToLeftChanged(EventArgs e) { + base.OnRightToLeftChanged (e); + } + + protected virtual void OnSelectionChanged(EventArgs e) { + EventHandler eh = (EventHandler)(Events [SelectionChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnVScroll(EventArgs e) { + EventHandler eh = (EventHandler)(Events [VScrollEvent]); + if (eh != null) + eh (this, e); + } + + protected override void WndProc(ref Message m) { + base.WndProc (ref m); + } + + protected override bool ProcessCmdKey (ref Message m, Keys keyData) + { + return base.ProcessCmdKey (ref m, keyData); + } + #endregion // Protected Instance Methods + + #region Events + static object ContentsResizedEvent = new object (); + static object HScrollEvent = new object (); + static object ImeChangeEvent = new object (); + static object LinkClickedEvent = new object (); + static object ProtectedEvent = new object (); + static object SelectionChangedEvent = new object (); + static object VScrollEvent = new object (); + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageChanged { + add { base.BackgroundImageChanged += value; } + remove { base.BackgroundImageChanged -= value; } + } + + [Browsable (false)] + [EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageLayoutChanged { + add { base.BackgroundImageLayoutChanged += value; } + remove { base.BackgroundImageLayoutChanged -= value; } + } + + public event ContentsResizedEventHandler ContentsResized { + add { Events.AddHandler (ContentsResizedEvent, value); } + remove { Events.RemoveHandler (ContentsResizedEvent, value); } + } + + [Browsable(false)] + public new event DragEventHandler DragDrop { + add { base.DragDrop += value; } + remove { base.DragDrop -= value; } + } + + [Browsable(false)] + public new event DragEventHandler DragEnter { + add { base.DragEnter += value; } + remove { base.DragEnter -= value; } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler DragLeave { + add { base.DragLeave += value; } + remove { base.DragLeave -= value; } + } + + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event DragEventHandler DragOver { + add { base.DragOver += value; } + remove { base.DragOver -= value; } + } + + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event GiveFeedbackEventHandler GiveFeedback { + add { base.GiveFeedback += value; } + remove { base.GiveFeedback -= value; } + } + + public event EventHandler HScroll { + add { Events.AddHandler (HScrollEvent, value); } + remove { Events.RemoveHandler (HScrollEvent, value); } + } + + public event EventHandler ImeChange { + add { Events.AddHandler (ImeChangeEvent, value); } + remove { Events.RemoveHandler (ImeChangeEvent, value); } + } + + public event LinkClickedEventHandler LinkClicked { + add { Events.AddHandler (LinkClickedEvent, value); } + remove { Events.RemoveHandler (LinkClickedEvent, value); } + } + + public event EventHandler Protected { + add { Events.AddHandler (ProtectedEvent, value); } + remove { Events.RemoveHandler (ProtectedEvent, value); } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event QueryContinueDragEventHandler QueryContinueDrag { + add { base.QueryContinueDrag += value; } + remove { base.QueryContinueDrag -= value; } + } + + [MonoTODO ("Event never raised")] + public event EventHandler SelectionChanged { + add { Events.AddHandler (SelectionChangedEvent, value); } + remove { Events.RemoveHandler (SelectionChangedEvent, value); } + } + + public event EventHandler VScroll { + add { Events.AddHandler (VScrollEvent, value); } + remove { Events.RemoveHandler (VScrollEvent, value); } + } + #endregion // Events + + #region Private Methods + + internal override void SelectWord () + { + document.ExpandSelection(CaretSelection.Word, false); + } + + private class RtfSectionStyle : ICloneable { + internal Color rtf_color; + internal RTF.Font rtf_rtffont; + internal int rtf_rtffont_size; + internal FontStyle rtf_rtfstyle; + internal HorizontalAlignment rtf_rtfalign; + internal int rtf_par_line_left_indent; + internal bool rtf_visible; + internal int rtf_skip_width; + + public object Clone () + { + RtfSectionStyle new_style = new RtfSectionStyle (); + + new_style.rtf_color = rtf_color; + new_style.rtf_par_line_left_indent = rtf_par_line_left_indent; + new_style.rtf_rtfalign = rtf_rtfalign; + new_style.rtf_rtffont = rtf_rtffont; + new_style.rtf_rtffont_size = rtf_rtffont_size; + new_style.rtf_rtfstyle = rtf_rtfstyle; + new_style.rtf_visible = rtf_visible; + new_style.rtf_skip_width = rtf_skip_width; + + return new_style; + } + } + + // To allow us to keep track of the sections and revert formatting + // as we go in and out of sections of the document. + private void HandleGroup (RTF.RTF rtf) + { + //start group - save the current formatting on to a stack + //end group - go back to the formatting at the current group + if (rtf_section_stack == null) { + rtf_section_stack = new Stack (); + } + + if (rtf.Major == RTF.Major.BeginGroup) { + rtf_section_stack.Push (rtf_style.Clone ()); + //spec specifies resetting unicode ignore at begin group as an attempt at error + //recovery. + rtf_skip_count = 0; + } else if (rtf.Major == RTF.Major.EndGroup) { + if (rtf_section_stack.Count > 0) { + FlushText (rtf, false); + + rtf_style = (RtfSectionStyle) rtf_section_stack.Pop (); + } + } + } + + [MonoInternalNote ("Add QuadJust support for justified alignment")] + private void HandleControl(RTF.RTF rtf) { + switch(rtf.Major) { + case RTF.Major.Unicode: { + switch(rtf.Minor) { + case RTF.Minor.UnicodeCharBytes: { + rtf_style.rtf_skip_width = rtf.Param; + break; + } + + case RTF.Minor.UnicodeChar: { + FlushText (rtf, false); + rtf_skip_count += rtf_style.rtf_skip_width; + rtf_line.Append((char)rtf.Param); + break; + } + } + break; + } + + case RTF.Major.Destination: { +// Console.Write("[Got Destination control {0}]", rtf.Minor); + rtf.SkipGroup(); + break; + } + + case RTF.Major.PictAttr: + if (rtf.Picture != null && rtf.Picture.IsValid ()) { + Line line = document.GetLine (rtf_cursor_y); + document.InsertPicture (line, 0, rtf.Picture); + rtf_cursor_x++; + + FlushText (rtf, true); + rtf.Picture = null; + } + break; + + case RTF.Major.CharAttr: { + switch(rtf.Minor) { + case RTF.Minor.ForeColor: { + ShiftUI.RTF.Color color; + + color = ShiftUI.RTF.Color.GetColor(rtf, rtf.Param); + + if (color != null) { + FlushText(rtf, false); + if (color.Red == -1 && color.Green == -1 && color.Blue == -1) { + this.rtf_style.rtf_color = ForeColor; + } else { + this.rtf_style.rtf_color = Color.FromArgb(color.Red, color.Green, color.Blue); + } + FlushText (rtf, false); + } + break; + } + + case RTF.Minor.FontSize: { + FlushText(rtf, false); + this.rtf_style.rtf_rtffont_size = rtf.Param / 2; + break; + } + + case RTF.Minor.FontNum: { + ShiftUI.RTF.Font font; + + font = ShiftUI.RTF.Font.GetFont(rtf, rtf.Param); + if (font != null) { + FlushText(rtf, false); + this.rtf_style.rtf_rtffont = font; + } + break; + } + + case RTF.Minor.Plain: { + FlushText(rtf, false); + rtf_style.rtf_rtfstyle = FontStyle.Regular; + break; + } + + case RTF.Minor.Bold: { + FlushText(rtf, false); + if (rtf.Param == RTF.RTF.NoParam) { + rtf_style.rtf_rtfstyle |= FontStyle.Bold; + } else { + rtf_style.rtf_rtfstyle &= ~FontStyle.Bold; + } + break; + } + + case RTF.Minor.Italic: { + FlushText(rtf, false); + if (rtf.Param == RTF.RTF.NoParam) { + rtf_style.rtf_rtfstyle |= FontStyle.Italic; + } else { + rtf_style.rtf_rtfstyle &= ~FontStyle.Italic; + } + break; + } + + case RTF.Minor.StrikeThru: { + FlushText(rtf, false); + if (rtf.Param == RTF.RTF.NoParam) { + rtf_style.rtf_rtfstyle |= FontStyle.Strikeout; + } else { + rtf_style.rtf_rtfstyle &= ~FontStyle.Strikeout; + } + break; + } + + case RTF.Minor.Underline: { + FlushText(rtf, false); + if (rtf.Param == RTF.RTF.NoParam) { + rtf_style.rtf_rtfstyle |= FontStyle.Underline; + } else { + rtf_style.rtf_rtfstyle = rtf_style.rtf_rtfstyle & ~FontStyle.Underline; + } + break; + } + + case RTF.Minor.Invisible: { + FlushText (rtf, false); + rtf_style.rtf_visible = false; + break; + } + + case RTF.Minor.NoUnderline: { + FlushText(rtf, false); + rtf_style.rtf_rtfstyle &= ~FontStyle.Underline; + break; + } + } + break; + } + + case RTF.Major.ParAttr: { + switch (rtf.Minor) { + + case RTF.Minor.ParDef: + FlushText (rtf, false); + rtf_style.rtf_par_line_left_indent = 0; + rtf_style.rtf_rtfalign = HorizontalAlignment.Left; + break; + + case RTF.Minor.LeftIndent: + using (Graphics g = CreateGraphics ()) + rtf_style.rtf_par_line_left_indent = (int) (((float) rtf.Param / 1440.0F) * g.DpiX + 0.5F); + break; + + case RTF.Minor.QuadCenter: + FlushText (rtf, false); + rtf_style.rtf_rtfalign = HorizontalAlignment.Center; + break; + + case RTF.Minor.QuadJust: + FlushText (rtf, false); + rtf_style.rtf_rtfalign = HorizontalAlignment.Center; + break; + + case RTF.Minor.QuadLeft: + FlushText (rtf, false); + rtf_style.rtf_rtfalign = HorizontalAlignment.Left; + break; + + case RTF.Minor.QuadRight: + FlushText (rtf, false); + rtf_style.rtf_rtfalign = HorizontalAlignment.Right; + break; + } + break; + } + + case RTF.Major.SpecialChar: { + //Console.Write("[Got SpecialChar control {0}]", rtf.Minor); + SpecialChar (rtf); + break; + } + } + } + + private void SpecialChar(RTF.RTF rtf) { + switch(rtf.Minor) { + case RTF.Minor.Page: + case RTF.Minor.Sect: + case RTF.Minor.Row: + case RTF.Minor.Line: + case RTF.Minor.Par: { + FlushText(rtf, true); + break; + } + + case RTF.Minor.Cell: { + Console.Write(" "); + break; + } + + case RTF.Minor.NoBrkSpace: { + Console.Write(" "); + break; + } + + case RTF.Minor.Tab: { + rtf_line.Append ("\t"); +// FlushText (rtf, false); + break; + } + + case RTF.Minor.NoReqHyphen: + case RTF.Minor.NoBrkHyphen: { + rtf_line.Append ("-"); +// FlushText (rtf, false); + break; + } + + case RTF.Minor.Bullet: { + Console.WriteLine("*"); + break; + } + + case RTF.Minor.WidowCtrl: + break; + + case RTF.Minor.EmDash: { + rtf_line.Append ("\u2014"); + break; + } + + case RTF.Minor.EnDash: { + rtf_line.Append ("\u2013"); + break; + } +/* + case RTF.Minor.LQuote: { + Console.Write("\u2018"); + break; + } + + case RTF.Minor.RQuote: { + Console.Write("\u2019"); + break; + } + + case RTF.Minor.LDblQuote: { + Console.Write("\u201C"); + break; + } + + case RTF.Minor.RDblQuote: { + Console.Write("\u201D"); + break; + } +*/ + default: { +// Console.WriteLine ("skipped special char: {0}", rtf.Minor); +// rtf.SkipGroup(); + break; + } + } + } + + private void HandleText(RTF.RTF rtf) { + string str = rtf.EncodedText; + + //todo - simplistically skips characters, should skip bytes? + if (rtf_skip_count > 0 && str.Length > 0) { + int iToRemove = Math.Min (rtf_skip_count, str.Length); + + str = str.Substring (iToRemove); + rtf_skip_count-=iToRemove; + } + + /* + if ((RTF.StandardCharCode)rtf.Minor != RTF.StandardCharCode.nothing) { + rtf_line.Append(rtf_text_map[(RTF.StandardCharCode)rtf.Minor]); + } else { + if ((int)rtf.Major > 31 && (int)rtf.Major < 128) { + rtf_line.Append((char)rtf.Major); + } else { + //rtf_line.Append((char)rtf.Major); + Console.Write("[Literal:0x{0:X2}]", (int)rtf.Major); + } + } + */ + + if (rtf_style.rtf_visible) + rtf_line.Append (str); + } + + private void FlushText(RTF.RTF rtf, bool newline) { + int length; + Font font; + + length = rtf_line.Length; + if (!newline && (length == 0)) { + return; + } + + if (rtf_style.rtf_rtffont == null) { + // First font in table is default + rtf_style.rtf_rtffont = ShiftUI.RTF.Font.GetFont (rtf, 0); + } + + font = new Font (rtf_style.rtf_rtffont.Name, rtf_style.rtf_rtffont_size, rtf_style.rtf_rtfstyle); + + if (rtf_style.rtf_color == Color.Empty) { + ShiftUI.RTF.Color color; + + // First color in table is default + color = ShiftUI.RTF.Color.GetColor (rtf, 0); + + if ((color == null) || (color.Red == -1 && color.Green == -1 && color.Blue == -1)) { + rtf_style.rtf_color = ForeColor; + } else { + rtf_style.rtf_color = Color.FromArgb (color.Red, color.Green, color.Blue); + } + + } + + rtf_chars += rtf_line.Length; + + // Try to re-use if we are told so - this usually happens when we are inserting a flow of rtf text + // with an already alive line. + if (rtf_cursor_x == 0 && !reuse_line) { + if (newline && rtf_line.ToString ().EndsWith (Environment.NewLine) == false) + rtf_line.Append (Environment.NewLine); + + document.Add (rtf_cursor_y, rtf_line.ToString (), rtf_style.rtf_rtfalign, font, rtf_style.rtf_color, + newline ? LineEnding.Rich : LineEnding.Wrap); + if (rtf_style.rtf_par_line_left_indent != 0) { + Line line = document.GetLine (rtf_cursor_y); + line.indent = rtf_style.rtf_par_line_left_indent; + } + } else { + Line line; + + line = document.GetLine (rtf_cursor_y); + line.indent = rtf_style.rtf_par_line_left_indent; + if (rtf_line.Length > 0) { + document.InsertString (line, rtf_cursor_x, rtf_line.ToString ()); + document.FormatText (line, rtf_cursor_x + 1, line, rtf_cursor_x + 1 + length, + font, rtf_style.rtf_color, Color.Empty, + FormatSpecified.Font | FormatSpecified.Color); + } + if (newline) { + line = document.GetLine (rtf_cursor_y); + line.ending = LineEnding.Rich; + + if (line.Text.EndsWith (Environment.NewLine) == false) + line.Text += Environment.NewLine; + } + + reuse_line = false; // sanity assignment - in this case we have already re-used one line. + } + + if (newline) { + rtf_cursor_x = 0; + rtf_cursor_y++; + } else { + rtf_cursor_x += length; + } + rtf_line.Length = 0; // Empty line + } + + private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y) { + int x; + int y; + int chars; + + InsertRTFFromStream(data, cursor_x, cursor_y, out x, out y, out chars); + } + + private void InsertRTFFromStream(Stream data, int cursor_x, int cursor_y, out int to_x, out int to_y, out int chars) { + RTF.RTF rtf; + + rtf = new RTF.RTF(data); + + // Prepare + rtf.ClassCallback[RTF.TokenClass.Text] = new RTF.ClassDelegate(HandleText); + rtf.ClassCallback[RTF.TokenClass.Widget] = new RTF.ClassDelegate(HandleControl); + rtf.ClassCallback[RTF.TokenClass.Group] = new RTF.ClassDelegate(HandleGroup); + + rtf_skip_count = 0; + rtf_line = new StringBuilder(); + rtf_style.rtf_color = Color.Empty; + rtf_style.rtf_rtffont_size = (int)this.Font.Size; + rtf_style.rtf_rtfalign = HorizontalAlignment.Left; + rtf_style.rtf_rtfstyle = FontStyle.Regular; + rtf_style.rtf_rtffont = null; + rtf_style.rtf_visible = true; + rtf_style.rtf_skip_width = 1; + rtf_cursor_x = cursor_x; + rtf_cursor_y = cursor_y; + rtf_chars = 0; + rtf.DefaultFont(this.Font.Name); + + rtf_text_map = new RTF.TextMap(); + RTF.TextMap.SetupStandardTable(rtf_text_map.Table); + + document.SuspendRecalc (); + + try { + rtf.Read(); // That's it + FlushText(rtf, false); + + } + + + catch (RTF.RTFException e) { +#if DEBUG + throw e; +#endif + // Seems to be plain text or broken RTF + } + + to_x = rtf_cursor_x; + to_y = rtf_cursor_y; + chars = rtf_chars; + + // clear the section stack if it was used + if (rtf_section_stack != null) + rtf_section_stack.Clear(); + + document.RecalculateDocument(CreateGraphicsInternal(), cursor_y, document.Lines, false); + document.ResumeRecalc (true); + + document.Invalidate (document.GetLine(cursor_y), 0, document.GetLine(document.Lines), -1); + } + + private void RichTextBox_HScrolled(object sender, EventArgs e) { + OnHScroll(e); + } + + private void RichTextBox_VScrolled(object sender, EventArgs e) { + OnVScroll(e); + } + + private void PointToTagPos(Point pt, out LineTag tag, out int pos) { + Point p; + + p = pt; + + if (p.X >= document.ViewPortWidth) { + p.X = document.ViewPortWidth - 1; + } else if (p.X < 0) { + p.X = 0; + } + + if (p.Y >= document.ViewPortHeight) { + p.Y = document.ViewPortHeight - 1; + } else if (p.Y < 0) { + p.Y = 0; + } + + tag = document.FindCursor(p.X + document.ViewPortX, p.Y + document.ViewPortY, out pos); + } + + private void EmitRTFFontProperties(StringBuilder rtf, int prev_index, int font_index, Font prev_font, Font font) { + if (prev_index != font_index) { + rtf.Append(String.Format("\\f{0}", font_index)); // Font table entry + } + + if ((prev_font == null) || (prev_font.Size != font.Size)) { + rtf.Append(String.Format("\\fs{0}", (int)(font.Size * 2))); // Font size + } + + if ((prev_font == null) || (font.Bold != prev_font.Bold)) { + if (font.Bold) { + rtf.Append("\\b"); + } else { + if (prev_font != null) { + rtf.Append("\\b0"); + } + } + } + + if ((prev_font == null) || (font.Italic != prev_font.Italic)) { + if (font.Italic) { + rtf.Append("\\i"); + } else { + if (prev_font != null) { + rtf.Append("\\i0"); + } + } + } + + if ((prev_font == null) || (font.Strikeout != prev_font.Strikeout)) { + if (font.Strikeout) { + rtf.Append("\\strike"); + } else { + if (prev_font != null) { + rtf.Append("\\strike0"); + } + } + } + + if ((prev_font == null) || (font.Underline != prev_font.Underline)) { + if (font.Underline) { + rtf.Append("\\ul"); + } else { + if (prev_font != null) { + rtf.Append("\\ul0"); + } + } + } + } + + static readonly char [] ReservedRTFChars = new char [] { '\\', '{', '}' }; + + private void EmitRTFText(StringBuilder rtf, string text) { + int start = rtf.Length; + int count = text.Length; + + // First emit simple unicode chars as escaped + EmitEscapedUnicode (rtf, text); + + // This method emits user text *only*, so it's safe to escape any reserved rtf chars + // Escape '\' first, since it is used later to escape the other chars + if (text.IndexOfAny (ReservedRTFChars) > -1) { + rtf.Replace ("\\", "\\\\", start, count); + rtf.Replace ("{", "\\{", start, count); + rtf.Replace ("}", "\\}", start, count); + } + } + + // The chars to be escaped use "\'" + its hexadecimal value. + private void EmitEscapedUnicode (StringBuilder sb, string text) + { + int pos; + int start = 0; + + while ((pos = IndexOfNonAscii (text, start)) > -1) { + sb.Append (text, start, pos - start); + + int n = (int)text [pos]; + sb.Append ("\\'"); + sb.Append (n.ToString ("X")); + + start = pos + 1; + } + + // Append remaining (maybe all) the text value. + if (start < text.Length) + sb.Append (text, start, text.Length - start); + } + + // MS seems to be escaping values larger than 0x80 + private int IndexOfNonAscii (string text, int startIndex) + { + for (int i = startIndex; i < text.Length; i++) { + int n = (int)text [i]; + if (n < 0 || n >= 0x80) + return i; + } + + return -1; + } + + // start_pos and end_pos are 0-based + private StringBuilder GenerateRTF(Line start_line, int start_pos, Line end_line, int end_pos) { + StringBuilder sb; + ArrayList fonts; + ArrayList colors; + Color color; + Font font; + Line line; + LineTag tag; + int pos; + int line_no; + int line_len; + int i; + int length; + + sb = new StringBuilder(); + fonts = new ArrayList(10); + colors = new ArrayList(10); + + // Two runs, first we parse to determine tables; + // and unlike most of our processing here we work on tags + + line = start_line; + line_no = start_line.line_no; + pos = start_pos; + + // Add default font and color; to optimize document content we don't + // use this.Font and this.ForeColor but the font/color from the first tag + tag = LineTag.FindTag(start_line, pos); + font = tag.Font; + color = tag.Color; + fonts.Add(font.Name); + colors.Add(color); + + while (line_no <= end_line.line_no) { + line = document.GetLine(line_no); + tag = LineTag.FindTag(line, pos); + + if (line_no != end_line.line_no) { + line_len = line.text.Length; + } else { + line_len = end_pos; + } + + while (pos < line_len) { + if (tag.Font.Name != font.Name) { + font = tag.Font; + if (!fonts.Contains(font.Name)) { + fonts.Add(font.Name); + } + } + + if (tag.Color != color) { + color = tag.Color; + if (!colors.Contains(color)) { + colors.Add(color); + } + } + + pos = tag.Start + tag.Length - 1; + tag = tag.Next; + } + pos = 0; + line_no++; + } + + // We have the tables, emit the header + sb.Append("{\\rtf1\\ansi"); + sb.Append("\\ansicpg1252"); // FIXME - is this correct? + + // Default Font + sb.Append(String.Format("\\deff{0}", fonts.IndexOf(this.Font.Name))); + + // Default Language + sb.Append("\\deflang1033" + Environment.NewLine); // FIXME - always 1033? + + // Emit the font table + sb.Append("{\\fonttbl"); + for (i = 0; i < fonts.Count; i++) { + sb.Append(String.Format("{{\\f{0}", i)); // {Font + sb.Append("\\fnil"); // Family + sb.Append("\\fcharset0 "); // Charset ANSI + sb.Append((string)fonts[i]); // Font name + sb.Append(";}"); // } + } + sb.Append("}"); + sb.Append(Environment.NewLine); + + // Emit the color table (if needed) + if ((colors.Count > 1) || ((((Color)colors[0]).R != this.ForeColor.R) || (((Color)colors[0]).G != this.ForeColor.G) || (((Color)colors[0]).B != this.ForeColor.B))) { + sb.Append("{\\colortbl "); // Header and NO! default color + for (i = 0; i < colors.Count; i++) { + sb.Append(String.Format("\\red{0}", ((Color)colors[i]).R)); + sb.Append(String.Format("\\green{0}", ((Color)colors[i]).G)); + sb.Append(String.Format("\\blue{0}", ((Color)colors[i]).B)); + sb.Append(";"); + } + sb.Append("}"); + sb.Append(Environment.NewLine); + } + + sb.Append("{\\*\\generator Mono RichTextBox;}"); + // Emit initial paragraph settings + tag = LineTag.FindTag(start_line, start_pos); + sb.Append("\\pard"); // Reset to default paragraph properties + EmitRTFFontProperties(sb, -1, fonts.IndexOf(tag.Font.Name), null, tag.Font); // Font properties + sb.Append(" "); // Space separator + + font = tag.Font; + color = (Color)colors[0]; + line = start_line; + line_no = start_line.line_no; + pos = start_pos; + + while (line_no <= end_line.line_no) { + line = document.GetLine(line_no); + tag = LineTag.FindTag(line, pos); + + if (line_no != end_line.line_no) { + line_len = line.text.Length; + } else { + line_len = end_pos; + } + + while (pos < line_len) { + length = sb.Length; + + if (tag.Font != font) { + EmitRTFFontProperties(sb, fonts.IndexOf(font.Name), fonts.IndexOf(tag.Font.Name), font, tag.Font); + font = tag.Font; + } + + if (tag.Color != color) { + color = tag.Color; + sb.Append(String.Format("\\cf{0}", colors.IndexOf(color))); + } + if (length != sb.Length) { + sb.Append(" "); // Emit space to separate keywords from text + } + + // Emit the string itself + if (line_no != end_line.line_no) { + EmitRTFText(sb, tag.Line.text.ToString(pos, tag.Start + tag.Length - pos - 1)); + } else { + if (end_pos < (tag.Start + tag.Length - 1)) { + // Emit partial tag only, end_pos is inside this tag + EmitRTFText(sb, tag.Line.text.ToString(pos, end_pos - pos)); + } else { + EmitRTFText(sb, tag.Line.text.ToString(pos, tag.Start + tag.Length - pos - 1)); + } + } + + pos = tag.Start + tag.Length - 1; + tag = tag.Next; + } + if (pos >= line.text.Length) { + if (line.ending != LineEnding.Wrap) { + sb.Append("\\par"); + sb.Append(Environment.NewLine); + } + } + pos = 0; + line_no++; + } + + sb.Append("}"); + sb.Append(Environment.NewLine); + + return sb; + } + #endregion // Private Methods + } +} diff --git a/source/ShiftUI/Widgets/RootGridEntry.cs b/source/ShiftUI/Widgets/RootGridEntry.cs new file mode 100644 index 0000000..534e166 --- /dev/null +++ b/source/ShiftUI/Widgets/RootGridEntry.cs @@ -0,0 +1,88 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Chris Toshok (toshok@novell.com) +// + +using System; +using System.Drawing; + +namespace ShiftUI.PropertyGridInternal +{ + /// + /// Summary description for PropertyGridRootGridItem + /// + [MonoInternalNote ("needs to implement IRootGridEntry")] + internal class RootGridEntry : GridEntry /*, IRootGridEntry */ + { + object[] val; + + public RootGridEntry (PropertyGrid owner, object[] obj) + : base (owner, null) + { + if (obj == null || obj.Length == 0) + throw new ArgumentNullException ("obj"); + val = obj; + } + + public override bool Expandable { + get { return true; } + } + + public override GridItemType GridItemType { + get { return GridItemType.Root; } + } + + public override string Label { + get { return val.Length > 1 ? val.GetType().ToString() : val[0].GetType().ToString(); } + } + + public override object Value { + get { return val.Length > 1 ? val : val[0]; } + } + + public override object[] Values { + get { return val; } + } + + public override bool Select () + { + return false; /* root entries aren't selectable */ + } + + public override bool IsReadOnly { + get { return true; } + } + + public override bool IsEditable { + get { return false; } + } + + public override bool IsResetable { + get { return false; } + } + + public override bool IsMerged { + get { return val.Length > 1; } + } + } +} diff --git a/source/ShiftUI/Widgets/ScrollBar.cs b/source/ShiftUI/Widgets/ScrollBar.cs new file mode 100644 index 0000000..9fceb0b --- /dev/null +++ b/source/ShiftUI/Widgets/ScrollBar.cs @@ -0,0 +1,1624 @@ +// +// ShiftUI.ScrollBar.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (C) 2004-2005, Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez jordi@ximian.com +// +// + +// COMPLETE + +using System.Drawing; +using System.Drawing.Imaging; +using System.Drawing.Drawing2D; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI +{ + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [DefaultEvent ("Scroll")] + [DefaultProperty ("Value")] + public abstract class ScrollBar : Widget + { + #region Local Variables + private int position; + private int minimum; + private int maximum; + private int large_change; + private int small_change; + internal int scrollbutton_height; + internal int scrollbutton_width; + private Rectangle first_arrow_area = new Rectangle (); // up or left + private Rectangle second_arrow_area = new Rectangle (); // down or right + private Rectangle thumb_pos = new Rectangle (); + private Rectangle thumb_area = new Rectangle (); + internal ButtonState firstbutton_state = ButtonState.Normal; + internal ButtonState secondbutton_state = ButtonState.Normal; + private bool firstbutton_pressed = false; + private bool secondbutton_pressed = false; + private bool thumb_pressed = false; + private float pixel_per_pos = 0; + private Timer timer = new Timer (); + private TimerType timer_type; + private int thumb_size = 40; + private const int thumb_min_size = 8; + private const int thumb_notshown_size = 40; + internal bool use_manual_thumb_size; + internal int manual_thumb_size; + internal bool vert; + internal bool implicit_Widget; + private int lastclick_pos; // Position of the last button-down event + private int thumbclick_offset; // Position of the last button-down event relative to the thumb edge + private Rectangle dirty; + + internal ThumbMoving thumb_moving = ThumbMoving.None; + bool first_button_entered; + bool second_button_entered; + bool thumb_entered; + #endregion // Local Variables + + private enum TimerType + { + HoldButton, + RepeatButton, + HoldThumbArea, + RepeatThumbArea + } + + internal enum ThumbMoving + { + None, + Forward, + Backwards, + } + + #region events + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler AutoSizeChanged { + add { base.AutoSizeChanged += value; } + remove { base.AutoSizeChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackColorChanged { + add { base.BackColorChanged += value; } + remove { base.BackColorChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageChanged { + add { base.BackgroundImageChanged += value; } + remove { base.BackgroundImageChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageLayoutChanged { + add { base.BackgroundImageLayoutChanged += value; } + remove { base.BackgroundImageLayoutChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler Click { + add { base.Click += value; } + remove { base.Click -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler DoubleClick { + add { base.DoubleClick += value; } + remove { base.DoubleClick -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler FontChanged { + add { base.FontChanged += value; } + remove { base.FontChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler ForeColorChanged { + add { base.ForeColorChanged += value; } + remove { base.ForeColorChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler ImeModeChanged { + add { base.ImeModeChanged += value; } + remove { base.ImeModeChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event MouseEventHandler MouseClick { + add { base.MouseClick += value; } + remove { base.MouseClick -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event MouseEventHandler MouseDoubleClick { + add { base.MouseDoubleClick += value; } + remove { base.MouseDoubleClick -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event MouseEventHandler MouseDown { + add { base.MouseDown += value; } + remove { base.MouseDown -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event MouseEventHandler MouseMove { + add { base.MouseMove += value; } + remove { base.MouseMove -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event MouseEventHandler MouseUp { + add { base.MouseUp += value; } + remove { base.MouseUp -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event PaintEventHandler Paint { + add { base.Paint += value; } + remove { base.Paint -= value; } + } + + static object ScrollEvent = new object (); + static object ValueChangedEvent = new object (); + + public event ScrollEventHandler Scroll { + add { Events.AddHandler (ScrollEvent, value); } + remove { Events.RemoveHandler (ScrollEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + + public event EventHandler ValueChanged { + add { Events.AddHandler (ValueChangedEvent, value); } + remove { Events.RemoveHandler (ValueChangedEvent, value); } + } + #endregion Events + + public ScrollBar () + { + position = 0; + minimum = 0; + maximum = 100; + large_change = 10; + small_change = 1; + + timer.Tick += new EventHandler (OnTimer); + MouseEnter += new EventHandler (OnMouseEnter); + MouseLeave += new EventHandler (OnMouseLeave); + base.KeyDown += new KeyEventHandler (OnKeyDownSB); + base.MouseDown += new MouseEventHandler (OnMouseDownSB); + base.MouseUp += new MouseEventHandler (OnMouseUpSB); + base.MouseMove += new MouseEventHandler (OnMouseMoveSB); + base.Resize += new EventHandler (OnResizeSB); + base.TabStop = false; + base.Cursor = Cursors.Default; + + SetStyle (Widgetstyles.UserPaint | Widgetstyles.StandardClick | Widgetstyles.UseTextForAccessibility, false); + } + + #region Internal & Private Properties + internal Rectangle FirstArrowArea { + get { + return this.first_arrow_area; + } + + set { + this.first_arrow_area = value; + } + } + + internal Rectangle SecondArrowArea { + get { + return this.second_arrow_area; + } + + set { + this.second_arrow_area = value; + } + } + + int MaximumAllowed { + get { + return use_manual_thumb_size ? maximum - manual_thumb_size + 1 : + maximum - LargeChange + 1; + } + } + + internal Rectangle ThumbPos { + get { + return thumb_pos; + } + + set { + thumb_pos = value; + } + } + + internal bool FirstButtonEntered { + get { return first_button_entered; } + private set { + if (first_button_entered == value) + return; + first_button_entered = value; + if (ThemeEngine.Current.ScrollBarHasHotElementStyles) + Invalidate (first_arrow_area); + } + } + + internal bool SecondButtonEntered { + get { return second_button_entered; } + private set { + if (second_button_entered == value) + return; + second_button_entered = value; + if (ThemeEngine.Current.ScrollBarHasHotElementStyles) + Invalidate (second_arrow_area); + } + } + + internal bool ThumbEntered { + get { return thumb_entered; } + private set { + if (thumb_entered == value) + return; + thumb_entered = value; + if (ThemeEngine.Current.ScrollBarHasHotElementStyles) + Invalidate (thumb_pos); + } + } + + internal bool ThumbPressed { + get { return thumb_pressed; } + private set { + if (thumb_pressed == value) + return; + thumb_pressed = value; + if (ThemeEngine.Current.ScrollBarHasPressedThumbStyle) + Invalidate (thumb_pos); + } + } + + #endregion // Internal & Private Properties + + #region Public Properties + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override bool AutoSize { + get { return base.AutoSize; } + set { base.AutoSize = value; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public override Color BackColor + { + get { return base.BackColor; } + set { + if (base.BackColor == value) + return; + base.BackColor = value; + Refresh (); + } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public override Image BackgroundImage + { + get { return base.BackgroundImage; } + set { + if (base.BackgroundImage == value) + return; + + base.BackgroundImage = value; + } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + protected override CreateParams CreateParams + { + get { return base.CreateParams; } + } + + protected override Padding DefaultMargin { + get { return Padding.Empty; } + } + + protected override ImeMode DefaultImeMode + { + get { return ImeMode.Disable; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public override Font Font + { + get { return base.Font; } + set { + if (base.Font.Equals (value)) + return; + + base.Font = value; + } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public override Color ForeColor + { + get { return base.ForeColor; } + set { + if (base.ForeColor == value) + return; + + base.ForeColor = value; + Refresh (); + } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public new ImeMode ImeMode + { + get { return base.ImeMode; } + set { + if (base.ImeMode == value) + return; + + base.ImeMode = value; + } + } + + [DefaultValue (10)] + [RefreshProperties(RefreshProperties.Repaint)] + [MWFDescription("Scroll amount when clicking in the scroll area"), MWFCategory("Behaviour")] + public int LargeChange { + get { return Math.Min (large_change, maximum - minimum + 1); } + set { + if (value < 0) + throw new ArgumentOutOfRangeException ("LargeChange", string.Format ("Value '{0}' must be greater than or equal to 0.", value)); + + if (large_change != value) { + large_change = value; + + // thumb area depends on large change value, + // so we need to recalculate it. + CalcThumbArea (); + UpdatePos (Value, true); + InvalidateDirty (); + + // UIA Framework: Generate UIA Event to indicate LargeChange change + OnUIAValueChanged (new ScrollEventArgs (ScrollEventType.LargeIncrement, value)); + } + } + } + + [DefaultValue (100)] + [RefreshProperties(RefreshProperties.Repaint)] + [MWFDescription("Highest value for scrollbar"), MWFCategory("Behaviour")] + public int Maximum { + get { return maximum; } + set { + if (maximum == value) + return; + + maximum = value; + + // UIA Framework: Generate UIA Event to indicate Maximum change + OnUIAValueChanged (new ScrollEventArgs (ScrollEventType.Last, value)); + + if (maximum < minimum) + minimum = maximum; + if (Value > maximum) + Value = maximum; + + // thumb area depends on maximum value, + // so we need to recalculate it. + CalcThumbArea (); + UpdatePos (Value, true); + InvalidateDirty (); + } + } + + internal void SetValues (int maximum, int large_change) + { + SetValues (-1, maximum, -1, large_change); + } + + internal void SetValues (int minimum, int maximum, int small_change, int large_change) + { + bool update = false; + + if (-1 != minimum && this.minimum != minimum) { + this.minimum = minimum; + + if (minimum > this.maximum) + this.maximum = minimum; + update = true; + + // change the position if it is out of range now + position = Math.Max (position, minimum); + } + + if (-1 != maximum && this.maximum != maximum) { + this.maximum = maximum; + + if (maximum < this.minimum) + this.minimum = maximum; + update = true; + + // change the position if it is out of range now + position = Math.Min (position, maximum); + } + + if (-1 != small_change && this.small_change != small_change) { + this.small_change = small_change; + } + + if (this.large_change != large_change) { + this.large_change = large_change; + update = true; + } + + if (update) { + CalcThumbArea (); + UpdatePos (Value, true); + InvalidateDirty (); + } + } + + [DefaultValue (0)] + [RefreshProperties(RefreshProperties.Repaint)] + [MWFDescription("Smallest value for scrollbar"), MWFCategory("Behaviour")] + public int Minimum { + get { return minimum; } + set { + if (minimum == value) + return; + + minimum = value; + + // UIA Framework: Generate UIA Event to indicate Minimum change + OnUIAValueChanged (new ScrollEventArgs (ScrollEventType.First, value)); + + if (minimum > maximum) + maximum = minimum; + + // thumb area depends on minimum value, + // so we need to recalculate it. + CalcThumbArea (); + UpdatePos (Value, true); + InvalidateDirty (); + } + } + + [DefaultValue (1)] + [MWFDescription("Scroll amount when clicking scroll arrows"), MWFCategory("Behaviour")] + public int SmallChange { + get { return small_change > LargeChange ? LargeChange : small_change; } + set { + if ( value < 0 ) + throw new ArgumentOutOfRangeException ("SmallChange", string.Format ("Value '{0}' must be greater than or equal to 0.", value)); + + if (small_change != value) { + small_change = value; + UpdatePos (Value, true); + InvalidateDirty (); + + // UIA Framework: Generate UIA Event to indicate SmallChange change + OnUIAValueChanged (new ScrollEventArgs (ScrollEventType.SmallIncrement, value)); + } + } + } + + [DefaultValue (false)] + public new bool TabStop { + get { return base.TabStop; } + set { base.TabStop = value; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Bindable (false)] + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override string Text { + get { return base.Text; } + set { base.Text = value; } + } + + [Bindable(true)] + [DefaultValue (0)] + [MWFDescription("Current value for scrollbar"), MWFCategory("Behaviour")] + public int Value { + get { return position; } + set { + if ( value < minimum || value > maximum ) + throw new ArgumentOutOfRangeException ("Value", string.Format ("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value)); + + if (position != value){ + position = value; + + OnValueChanged (EventArgs.Empty); + + if (IsHandleCreated) { + Rectangle thumb_rect = thumb_pos; + + UpdateThumbPos ((vert ? thumb_area.Y : thumb_area.X) + (int)(((float)(position - minimum)) * pixel_per_pos), false, false); + + MoveThumb (thumb_rect, vert ? thumb_pos.Y : thumb_pos.X); + } + } + } + } + + #endregion //Public Properties + + #region Public Methods + protected override Rectangle GetScaledBounds (Rectangle bounds, SizeF factor, BoundsSpecified specified) + { + // Basically, we want to keep our small edge and scale the long edge + // ie: if we are vertical, don't scale our width + if (vert) + return base.GetScaledBounds (bounds, factor, (specified & BoundsSpecified.Height) | (specified & BoundsSpecified.Location)); + else + return base.GetScaledBounds (bounds, factor, (specified & BoundsSpecified.Width) | (specified & BoundsSpecified.Location)); + } + + protected override void OnEnabledChanged (EventArgs e) + { + base.OnEnabledChanged (e); + + if (Enabled) + firstbutton_state = secondbutton_state = ButtonState.Normal; + else + firstbutton_state = secondbutton_state = ButtonState.Inactive; + + Refresh (); + } + + protected override void OnHandleCreated (System.EventArgs e) + { + base.OnHandleCreated (e); + + CalcButtonSizes (); + CalcThumbArea (); + UpdateThumbPos (thumb_area.Y + (int)(((float)(position - minimum)) * pixel_per_pos), true, false); + } + + protected virtual void OnScroll (ScrollEventArgs se) + { + ScrollEventHandler eh = (ScrollEventHandler)(Events [ScrollEvent]); + if (eh == null) + return; + + if (se.NewValue < Minimum) { + se.NewValue = Minimum; + } + + if (se.NewValue > Maximum) { + se.NewValue = Maximum; + } + + eh (this, se); + } + + private void SendWMScroll(ScrollBarCommands cmd) { + if ((Parent != null) && Parent.IsHandleCreated) { + if (vert) { + XplatUI.SendMessage(Parent.Handle, Msg.WM_VSCROLL, (IntPtr)cmd, implicit_Widget ? IntPtr.Zero : Handle); + } else { + XplatUI.SendMessage(Parent.Handle, Msg.WM_HSCROLL, (IntPtr)cmd, implicit_Widget ? IntPtr.Zero : Handle); + } + } + } + + protected virtual void OnValueChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [ValueChangedEvent]); + if (eh != null) + eh (this, e); + } + + public override string ToString() + { + return string.Format("{0}, Minimum: {1}, Maximum: {2}, Value: {3}", + GetType( ).FullName, minimum, maximum, position); + } + + protected void UpdateScrollInfo () + { + Refresh (); + } + + protected override void WndProc (ref Message m) + { + base.WndProc (ref m); + } + + #endregion //Public Methods + + #region Private Methods + + private void CalcButtonSizes () + { + if (vert) { + if (Height < ThemeEngine.Current.ScrollBarButtonSize * 2) + scrollbutton_height = Height /2; + else + scrollbutton_height = ThemeEngine.Current.ScrollBarButtonSize; + + } else { + if (Width < ThemeEngine.Current.ScrollBarButtonSize * 2) + scrollbutton_width = Width /2; + else + scrollbutton_width = ThemeEngine.Current.ScrollBarButtonSize; + } + } + + private void CalcThumbArea () + { + int lchange = use_manual_thumb_size ? manual_thumb_size : LargeChange; + + // Thumb area + if (vert) { + + thumb_area.Height = Height - scrollbutton_height - scrollbutton_height; + thumb_area.X = 0; + thumb_area.Y = scrollbutton_height; + thumb_area.Width = Width; + + if (Height < thumb_notshown_size) + thumb_size = 0; + else { + double per = ((double) lchange / (double)((1 + maximum - minimum))); + thumb_size = 1 + (int) (thumb_area.Height * per); + + if (thumb_size < thumb_min_size) + thumb_size = thumb_min_size; + + // Give the user something to drag if LargeChange is zero + if (LargeChange == 0) + thumb_size = 17; + } + + pixel_per_pos = ((float)(thumb_area.Height - thumb_size) / (float) ((maximum - minimum - lchange) + 1)); + + } else { + + thumb_area.Y = 0; + thumb_area.X = scrollbutton_width; + thumb_area.Height = Height; + thumb_area.Width = Width - scrollbutton_width - scrollbutton_width; + + if (Width < thumb_notshown_size) + thumb_size = 0; + else { + double per = ((double) lchange / (double)((1 + maximum - minimum))); + thumb_size = 1 + (int) (thumb_area.Width * per); + + if (thumb_size < thumb_min_size) + thumb_size = thumb_min_size; + + // Give the user something to drag if LargeChange is zero + if (LargeChange == 0) + thumb_size = 17; + } + + pixel_per_pos = ((float)(thumb_area.Width - thumb_size) / (float) ((maximum - minimum - lchange) + 1)); + } + } + + private void LargeIncrement () + { + ScrollEventArgs event_args; + int pos = Math.Min (MaximumAllowed, position + large_change); + + event_args = new ScrollEventArgs (ScrollEventType.LargeIncrement, pos); + OnScroll (event_args); + Value = event_args.NewValue; + + event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value); + OnScroll (event_args); + Value = event_args.NewValue; + + // UIA Framework event invoked when the "LargeIncrement + // Button" is "clicked" either by using the Invoke Pattern + // or the space between the thumb and the bottom/right button + OnUIAScroll (new ScrollEventArgs (ScrollEventType.LargeIncrement, Value)); + } + + private void LargeDecrement () + { + ScrollEventArgs event_args; + int pos = Math.Max (Minimum, position - large_change); + + event_args = new ScrollEventArgs (ScrollEventType.LargeDecrement, pos); + OnScroll (event_args); + Value = event_args.NewValue; + + event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value); + OnScroll (event_args); + Value = event_args.NewValue; + + // UIA Framework event invoked when the "LargeDecrement + // Button" is "clicked" either by using the Invoke Pattern + // or the space between the thumb and the top/left button + OnUIAScroll (new ScrollEventArgs (ScrollEventType.LargeDecrement, Value)); + } + + private void OnResizeSB (Object o, EventArgs e) + { + if (Width <= 0 || Height <= 0) + return; + + CalcButtonSizes (); + CalcThumbArea (); + UpdatePos (position, true); + + Refresh (); + } + + internal override void OnPaintInternal (PaintEventArgs pevent) + { + ThemeEngine.Current.DrawScrollBar (pevent.Graphics, pevent.ClipRectangle, this); + } + + private void OnTimer (Object source, EventArgs e) + { + ClearDirty (); + + switch (timer_type) { + + case TimerType.HoldButton: + SetRepeatButtonTimer (); + break; + + case TimerType.RepeatButton: + { + if ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed && position != Minimum) { + SmallDecrement(); + SendWMScroll(ScrollBarCommands.SB_LINEUP); + } + + if ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed && position != Maximum) { + SmallIncrement(); + SendWMScroll(ScrollBarCommands.SB_LINEDOWN); + } + + break; + } + + case TimerType.HoldThumbArea: + SetRepeatThumbAreaTimer (); + break; + + case TimerType.RepeatThumbArea: + { + Point pnt, pnt_screen; + Rectangle thumb_area_screen = thumb_area; + + pnt_screen = PointToScreen (new Point (thumb_area.X, thumb_area.Y)); + thumb_area_screen.X = pnt_screen.X; + thumb_area_screen.Y = pnt_screen.Y; + + if (thumb_area_screen.Contains (MousePosition) == false) { + timer.Enabled = false; + thumb_moving = ThumbMoving.None; + DirtyThumbArea (); + InvalidateDirty (); + } + + pnt = PointToClient (MousePosition); + + if (vert) + lastclick_pos = pnt.Y; + else + lastclick_pos = pnt.X; + + if (thumb_moving == ThumbMoving.Forward) { + if ((vert && (thumb_pos.Y + thumb_size > lastclick_pos)) || + (!vert && (thumb_pos.X + thumb_size > lastclick_pos)) || + (thumb_area.Contains (pnt) == false)) { + timer.Enabled = false; + thumb_moving = ThumbMoving.None; + Refresh (); + return; + } else { + LargeIncrement (); + SendWMScroll(ScrollBarCommands.SB_PAGEDOWN); + } + } else { + if ((vert && (thumb_pos.Y < lastclick_pos)) || + (!vert && (thumb_pos.X < lastclick_pos))){ + timer.Enabled = false; + thumb_moving = ThumbMoving.None; + SendWMScroll(ScrollBarCommands.SB_PAGEUP); + Refresh (); + } else { + LargeDecrement (); + SendWMScroll(ScrollBarCommands.SB_PAGEUP); + } + } + + break; + } + default: + break; + } + + InvalidateDirty (); + } + + private void MoveThumb (Rectangle original_thumbpos, int value) + { + /* so, the reason this works can best be + * described by the following 1 dimensional + * pictures + * + * say you have a scrollbar thumb positioned + * thusly: + * + * <---------------------| |------------------------------> + * + * and you want it to end up looking like this: + * + * <-----------------------------| |----------------------> + * + * that can be done with the scrolling api by + * extending the rectangle to encompass both + * positions: + * + * start of range end of range + * \ / + * <---------------------| |-------|----------------------> + * + * so, we end up scrolling just this little region: + * + * | |-------| + * + * and end up with ********| | + * + * where ****** is space that is automatically + * redrawn. + * + * It's clear that in both cases (left to + * right, right to left) we need to extend the + * size of the scroll rectangle to encompass + * both. In the right to left case, we also + * need to decrement the X coordinate. + * + * We call Update after scrolling to make sure + * there's no garbage left in the window to be + * copied again if we're called before the + * paint events have been handled. + * + */ + int delta; + + if (vert) { + delta = value - original_thumbpos.Y; + + if (delta < 0) { + original_thumbpos.Y += delta; + original_thumbpos.Height -= delta; + } + else { + original_thumbpos.Height += delta; + } + + XplatUI.ScrollWindow (Handle, original_thumbpos, 0, delta, false); + } + else { + delta = value - original_thumbpos.X; + + if (delta < 0) { + original_thumbpos.X += delta; + original_thumbpos.Width -= delta; + } + else { + original_thumbpos.Width += delta; + } + + XplatUI.ScrollWindow (Handle, original_thumbpos, delta, 0, false); + } + + Update (); + } + + private void OnMouseMoveSB (object sender, MouseEventArgs e) + { + if (Enabled == false) + return; + + FirstButtonEntered = first_arrow_area.Contains (e.Location); + SecondButtonEntered = second_arrow_area.Contains (e.Location); + + if (thumb_size == 0) + return; + + ThumbEntered = thumb_pos.Contains (e.Location); + + if (firstbutton_pressed) { + if (!first_arrow_area.Contains (e.X, e.Y) && ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) { + firstbutton_state = ButtonState.Normal; + Invalidate (first_arrow_area); + Update(); + return; + } else if (first_arrow_area.Contains (e.X, e.Y) && ((firstbutton_state & ButtonState.Normal) == ButtonState.Normal)) { + firstbutton_state = ButtonState.Pushed; + Invalidate (first_arrow_area); + Update(); + return; + } + } else if (secondbutton_pressed) { + if (!second_arrow_area.Contains (e.X, e.Y) && ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) { + secondbutton_state = ButtonState.Normal; + Invalidate (second_arrow_area); + Update(); + return; + } else if (second_arrow_area.Contains (e.X, e.Y) && ((secondbutton_state & ButtonState.Normal) == ButtonState.Normal)) { + secondbutton_state = ButtonState.Pushed; + Invalidate (second_arrow_area); + Update(); + return; + } + } else if (thumb_pressed == true) { + if (vert) { + int thumb_edge = e.Y - thumbclick_offset; + + if (thumb_edge < thumb_area.Y) + thumb_edge = thumb_area.Y; + else if (thumb_edge > thumb_area.Bottom - thumb_size) + thumb_edge = thumb_area.Bottom - thumb_size; + + if (thumb_edge != thumb_pos.Y) { + Rectangle thumb_rect = thumb_pos; + + UpdateThumbPos (thumb_edge, false, true); + + MoveThumb (thumb_rect, thumb_pos.Y); + + OnScroll (new ScrollEventArgs (ScrollEventType.ThumbTrack, position)); + } + SendWMScroll(ScrollBarCommands.SB_THUMBTRACK); + } else { + int thumb_edge = e.X - thumbclick_offset; + + if (thumb_edge < thumb_area.X) + thumb_edge = thumb_area.X; + else if (thumb_edge > thumb_area.Right - thumb_size) + thumb_edge = thumb_area.Right - thumb_size; + + if (thumb_edge != thumb_pos.X) { + Rectangle thumb_rect = thumb_pos; + + UpdateThumbPos (thumb_edge, false, true); + + MoveThumb (thumb_rect, thumb_pos.X); + + OnScroll (new ScrollEventArgs (ScrollEventType.ThumbTrack, position)); + } + SendWMScroll(ScrollBarCommands.SB_THUMBTRACK); + } + + } + + } + + private void OnMouseDownSB (object sender, MouseEventArgs e) + { + ClearDirty (); + + if (Enabled == false || (e.Button & MouseButtons.Left) == 0) + return; + + if (firstbutton_state != ButtonState.Inactive && first_arrow_area.Contains (e.X, e.Y)) { + SendWMScroll(ScrollBarCommands.SB_LINEUP); + firstbutton_state = ButtonState.Pushed; + firstbutton_pressed = true; + Invalidate (first_arrow_area); + Update(); + if (!timer.Enabled) { + SetHoldButtonClickTimer (); + timer.Enabled = true; + } + } + + if (secondbutton_state != ButtonState.Inactive && second_arrow_area.Contains (e.X, e.Y)) { + SendWMScroll(ScrollBarCommands.SB_LINEDOWN); + secondbutton_state = ButtonState.Pushed; + secondbutton_pressed = true; + Invalidate (second_arrow_area); + Update(); + if (!timer.Enabled) { + SetHoldButtonClickTimer (); + timer.Enabled = true; + } + } + + if (thumb_size > 0 && thumb_pos.Contains (e.X, e.Y)) { + ThumbPressed = true; + SendWMScroll(ScrollBarCommands.SB_THUMBTRACK); + if (vert) { + thumbclick_offset = e.Y - thumb_pos.Y; + lastclick_pos = e.Y; + } + else { + thumbclick_offset = e.X - thumb_pos.X; + lastclick_pos = e.X; + } + } else { + if (thumb_size > 0 && thumb_area.Contains (e.X, e.Y)) { + + if (vert) { + lastclick_pos = e.Y; + + if (e.Y > thumb_pos.Y + thumb_pos.Height) { + SendWMScroll(ScrollBarCommands.SB_PAGEDOWN); + LargeIncrement (); + thumb_moving = ThumbMoving.Forward; + Dirty (new Rectangle (0, thumb_pos.Y + thumb_pos.Height, + ClientRectangle.Width, + ClientRectangle.Height - (thumb_pos.Y + thumb_pos.Height) - + scrollbutton_height)); + } else { + SendWMScroll(ScrollBarCommands.SB_PAGEUP); + LargeDecrement (); + thumb_moving = ThumbMoving.Backwards; + Dirty (new Rectangle (0, scrollbutton_height, + ClientRectangle.Width, + thumb_pos.Y - scrollbutton_height)); + } + } else { + + lastclick_pos = e.X; + + if (e.X > thumb_pos.X + thumb_pos.Width) { + SendWMScroll(ScrollBarCommands.SB_PAGEDOWN); + thumb_moving = ThumbMoving.Forward; + LargeIncrement (); + Dirty (new Rectangle (thumb_pos.X + thumb_pos.Width, 0, + ClientRectangle.Width - (thumb_pos.X + thumb_pos.Width) - + scrollbutton_width, + ClientRectangle.Height)); + } else { + SendWMScroll(ScrollBarCommands.SB_PAGEUP); + thumb_moving = ThumbMoving.Backwards; + LargeDecrement (); + Dirty (new Rectangle (scrollbutton_width, 0, + thumb_pos.X - scrollbutton_width, + ClientRectangle.Height)); + } + } + + SetHoldThumbAreaTimer (); + timer.Enabled = true; + InvalidateDirty (); + } + } + } + + private void OnMouseUpSB (object sender, MouseEventArgs e) + { + ClearDirty (); + + if (Enabled == false) + return; + + timer.Enabled = false; + if (thumb_moving != ThumbMoving.None) { + DirtyThumbArea (); + thumb_moving = ThumbMoving.None; + } + + if (firstbutton_pressed) { + firstbutton_state = ButtonState.Normal; + if (first_arrow_area.Contains (e.X, e.Y)) { + SmallDecrement (); + } + SendWMScroll(ScrollBarCommands.SB_LINEUP); + firstbutton_pressed = false; + Dirty (first_arrow_area); + } else if (secondbutton_pressed) { + secondbutton_state = ButtonState.Normal; + if (second_arrow_area.Contains (e.X, e.Y)) { + SmallIncrement (); + } + SendWMScroll(ScrollBarCommands.SB_LINEDOWN); + Dirty (second_arrow_area); + secondbutton_pressed = false; + } else if (thumb_pressed == true) { + OnScroll (new ScrollEventArgs (ScrollEventType.ThumbPosition, position)); + OnScroll (new ScrollEventArgs (ScrollEventType.EndScroll, position)); + SendWMScroll(ScrollBarCommands.SB_THUMBPOSITION); + ThumbPressed = false; + return; + } + + InvalidateDirty (); + } + + private void OnKeyDownSB (Object o, KeyEventArgs key) + { + if (Enabled == false) + return; + + ClearDirty (); + + switch (key.KeyCode){ + case Keys.Up: + { + SmallDecrement (); + break; + } + case Keys.Down: + { + SmallIncrement (); + break; + } + case Keys.PageUp: + { + LargeDecrement (); + break; + } + case Keys.PageDown: + { + LargeIncrement (); + break; + } + case Keys.Home: + { + SetHomePosition (); + break; + } + case Keys.End: + { + SetEndPosition (); + break; + } + default: + break; + } + + InvalidateDirty (); + } + + // I hate to do this, but we don't have the resources to track + // down everything internal that is setting a value outside the + // correct range, so we'll clamp it to the acceptable values. + internal void SafeValueSet (int value) + { + value = Math.Min (value, maximum); + value = Math.Max (value, minimum); + + Value = value; + } + + private void SetEndPosition () + { + ScrollEventArgs event_args; + int pos = MaximumAllowed; + + event_args = new ScrollEventArgs (ScrollEventType.Last, pos); + OnScroll (event_args); + pos = event_args.NewValue; + + event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos); + OnScroll (event_args); + pos = event_args.NewValue; + + SetValue (pos); + } + + private void SetHomePosition () + { + ScrollEventArgs event_args; + int pos = Minimum; + + event_args = new ScrollEventArgs (ScrollEventType.First, pos); + OnScroll (event_args); + pos = event_args.NewValue; + + event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos); + OnScroll (event_args); + pos = event_args.NewValue; + + SetValue (pos); + } + + private void SmallIncrement () + { + ScrollEventArgs event_args; + int pos = Math.Min (MaximumAllowed, position + SmallChange); + + event_args = new ScrollEventArgs (ScrollEventType.SmallIncrement, pos); + OnScroll (event_args); + Value = event_args.NewValue; + + event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value); + OnScroll (event_args); + Value = event_args.NewValue; + + // UIA Framework event invoked when the "SmallIncrement + // Button" (a.k.a bottom/right button) is "clicked" either + // by using the Invoke Pattern or the button itself + OnUIAScroll (new ScrollEventArgs (ScrollEventType.SmallIncrement, Value)); + } + + private void SmallDecrement () + { + ScrollEventArgs event_args; + int pos = Math.Max (Minimum, position - SmallChange); + + event_args = new ScrollEventArgs (ScrollEventType.SmallDecrement, pos); + OnScroll (event_args); + Value = event_args.NewValue; + + event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value); + OnScroll (event_args); + Value = event_args.NewValue; + + // UIA Framework event invoked when the "SmallDecrement + // Button" (a.k.a top/left button) is "clicked" either + // by using the Invoke Pattern or the button itself + OnUIAScroll (new ScrollEventArgs (ScrollEventType.SmallDecrement, Value)); + } + + private void SetHoldButtonClickTimer () + { + timer.Enabled = false; + timer.Interval = 200; + timer_type = TimerType.HoldButton; + timer.Enabled = true; + } + + private void SetRepeatButtonTimer () + { + timer.Enabled = false; + timer.Interval = 50; + timer_type = TimerType.RepeatButton; + timer.Enabled = true; + } + + private void SetHoldThumbAreaTimer () + { + timer.Enabled = false; + timer.Interval = 200; + timer_type = TimerType.HoldThumbArea; + timer.Enabled = true; + } + + private void SetRepeatThumbAreaTimer () + { + timer.Enabled = false; + timer.Interval = 50; + timer_type = TimerType.RepeatThumbArea; + timer.Enabled = true; + } + + private void UpdatePos (int newPos, bool update_thumbpos) + { + int pos; + + if (newPos < minimum) + pos = minimum; + else + if (newPos > MaximumAllowed) + pos = MaximumAllowed; + else + pos = newPos; + + // pos can't be less than minimum or greater than maximum + if (pos < minimum) + pos = minimum; + if (pos > maximum) + pos = maximum; + + if (update_thumbpos) { + if (vert) + UpdateThumbPos (thumb_area.Y + (int)(((float)(pos - minimum)) * pixel_per_pos), true, false); + else + UpdateThumbPos (thumb_area.X + (int)(((float)(pos - minimum)) * pixel_per_pos), true, false); + SetValue (pos); + } + else { + position = pos; // Updates directly the value to avoid thumb pos update + + + // XXX some reason we don't call OnValueChanged? + EventHandler eh = (EventHandler)(Events [ValueChangedEvent]); + if (eh != null) + eh (this, EventArgs.Empty); + } + } + + private void UpdateThumbPos (int pixel, bool dirty, bool update_value) + { + float new_pos = 0; + + if (vert) { + if (dirty) + Dirty (thumb_pos); + if (pixel < thumb_area.Y) + thumb_pos.Y = thumb_area.Y; + else if (pixel > thumb_area.Bottom - thumb_size) + thumb_pos.Y = thumb_area.Bottom - thumb_size; + else + thumb_pos.Y = pixel; + + thumb_pos.X = 0; + thumb_pos.Width = ThemeEngine.Current.ScrollBarButtonSize; + thumb_pos.Height = thumb_size; + new_pos = (float) (thumb_pos.Y - thumb_area.Y); + new_pos = new_pos / pixel_per_pos; + if (dirty) + Dirty (thumb_pos); + } else { + if (dirty) + Dirty (thumb_pos); + if (pixel < thumb_area.X) + thumb_pos.X = thumb_area.X; + else if (pixel > thumb_area.Right - thumb_size) + thumb_pos.X = thumb_area.Right - thumb_size; + else + thumb_pos.X = pixel; + + thumb_pos.Y = 0; + thumb_pos.Width = thumb_size; + thumb_pos.Height = ThemeEngine.Current.ScrollBarButtonSize; + new_pos = (float) (thumb_pos.X - thumb_area.X); + new_pos = new_pos / pixel_per_pos; + + if (dirty) + Dirty (thumb_pos); + } + + if (update_value) + UpdatePos ((int) new_pos + minimum, false); + } + + private void SetValue (int value) + { + if ( value < minimum || value > maximum ) + throw new ArgumentException( + String.Format("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value)); + + if (position != value){ + position = value; + + OnValueChanged (EventArgs.Empty); + UpdatePos (value, true); + } + } + + private void ClearDirty () + { + dirty = Rectangle.Empty; + } + + private void Dirty (Rectangle r) + { + if (dirty == Rectangle.Empty) { + dirty = r; + return; + } + dirty = Rectangle.Union (dirty, r); + } + + private void DirtyThumbArea () + { + if (thumb_moving == ThumbMoving.Forward) { + if (vert) { + Dirty (new Rectangle (0, thumb_pos.Y + thumb_pos.Height, + ClientRectangle.Width, + ClientRectangle.Height - (thumb_pos.Y + thumb_pos.Height) - + scrollbutton_height)); + } else { + Dirty (new Rectangle (thumb_pos.X + thumb_pos.Width, 0, + ClientRectangle.Width - (thumb_pos.X + thumb_pos.Width) - + scrollbutton_width, + ClientRectangle.Height)); + } + } else if (thumb_moving == ThumbMoving.Backwards) { + if (vert) { + Dirty(new Rectangle (0, scrollbutton_height, + ClientRectangle.Width, + thumb_pos.Y - scrollbutton_height)); + } else { + Dirty (new Rectangle (scrollbutton_width, 0, + thumb_pos.X - scrollbutton_width, + ClientRectangle.Height)); + } + } + } + + private void InvalidateDirty () + { + Invalidate (dirty); + Update(); + dirty = Rectangle.Empty; + } + + void OnMouseEnter (object sender, EventArgs e) + { + if (ThemeEngine.Current.ScrollBarHasHoverArrowButtonStyle) { + Region region_to_invalidate = new Region (first_arrow_area); + region_to_invalidate.Union (second_arrow_area); + Invalidate (region_to_invalidate); + } + } + + void OnMouseLeave (object sender, EventArgs e) + { + Region region_to_invalidate = new Region (); + region_to_invalidate.MakeEmpty (); + bool dirty = false; + if (ThemeEngine.Current.ScrollBarHasHoverArrowButtonStyle) { + region_to_invalidate.Union (first_arrow_area); + region_to_invalidate.Union (second_arrow_area); + dirty = true; + } else + if (ThemeEngine.Current.ScrollBarHasHotElementStyles) + if (first_button_entered) { + region_to_invalidate.Union (first_arrow_area); + dirty = true; + } else if (second_button_entered) { + region_to_invalidate.Union (second_arrow_area); + dirty = true; + } + if (ThemeEngine.Current.ScrollBarHasHotElementStyles) + if (thumb_entered) { + region_to_invalidate.Union (thumb_pos); + dirty = true; + } + first_button_entered = false; + second_button_entered = false; + thumb_entered = false; + if (dirty) + Invalidate (region_to_invalidate); + region_to_invalidate.Dispose (); + } + #endregion //Private Methods + protected override void OnMouseWheel (MouseEventArgs e) + { + base.OnMouseWheel (e); + } + + #region UIA Framework Section: Events, Methods and Properties. + + //NOTE: + // We are using Reflection to add/remove internal events. + // Class ScrollBarButtonInvokePatternInvokeEvent uses the events. + // + // Types used to generate UIA InvokedEvent + // * args.Type = ScrollEventType.LargeIncrement. Space between Thumb and bottom/right Button + // * args.Type = ScrollEventType.LargeDecrement. Space between Thumb and top/left Button + // * args.Type = ScrollEventType.SmallIncrement. Small increment UIA Button (bottom/right Button) + // * args.Type = ScrollEventType.SmallDecrement. Small decrement UIA Button (top/left Button) + // Types used to generate RangeValue-related events + // * args.Type = ScrollEventType.LargeIncrement. LargeChange event + // * args.Type = ScrollEventType.Last. Maximum event + // * args.Type = ScrollEventType.First. Minimum event + // * args.Type = ScrollEventType.SmallIncrement. SmallChange event + static object UIAScrollEvent = new object (); + static object UIAValueChangeEvent = new object (); + + internal event ScrollEventHandler UIAScroll { + add { Events.AddHandler (UIAScrollEvent, value); } + remove { Events.RemoveHandler (UIAScrollEvent, value); } + } + + internal event ScrollEventHandler UIAValueChanged { + add { Events.AddHandler (UIAValueChangeEvent, value); } + remove { Events.RemoveHandler (UIAValueChangeEvent, value); } + } + + internal void OnUIAScroll (ScrollEventArgs args) + { + ScrollEventHandler eh = (ScrollEventHandler) Events [UIAScrollEvent]; + if (eh != null) + eh (this, args); + } + + internal void OnUIAValueChanged (ScrollEventArgs args) + { + ScrollEventHandler eh = (ScrollEventHandler) Events [UIAValueChangeEvent]; + if (eh != null) + eh (this, args); + } + + //NOTE: + // Wrapper methods used by the Reflection. + // Class ScrollBarButtonInvokeProviderBehavior uses the events. + // + internal void UIALargeIncrement () + { + LargeIncrement (); + } + + internal void UIALargeDecrement () + { + LargeDecrement (); + } + + internal void UIASmallIncrement () + { + SmallIncrement (); + } + + internal void UIASmallDecrement () + { + SmallDecrement (); + } + + internal Rectangle UIAThumbArea { + get { return thumb_area; } + } + + internal Rectangle UIAThumbPosition { + get { return thumb_pos; } + } + + #endregion UIA Framework Section: Events, Methods and Properties. + + } +} + + + diff --git a/source/ShiftUI/Widgets/ScrollBarRenderer.cs b/source/ShiftUI/Widgets/ScrollBarRenderer.cs new file mode 100644 index 0000000..3030c72 --- /dev/null +++ b/source/ShiftUI/Widgets/ScrollBarRenderer.cs @@ -0,0 +1,326 @@ +// +// ScrollBarRenderer.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Novell, Inc. +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System.Drawing; +using System.Windows.Forms.VisualStyles; + +namespace ShiftUI +{ + public sealed class ScrollBarRenderer + { + #region Private Constructor + private ScrollBarRenderer () { } + #endregion + + #region Public Static Methods + public static void DrawArrowButton (Graphics g, Rectangle bounds, ScrollBarArrowButtonState state) + { + if (!IsSupported) + throw new InvalidOperationException (); + + VisualStyleRenderer vsr; + + switch (state) { + case ScrollBarArrowButtonState.DownDisabled: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ArrowButton.DownDisabled); + break; + case ScrollBarArrowButtonState.DownHot: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ArrowButton.DownHot); + break; + case ScrollBarArrowButtonState.DownNormal: + default: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ArrowButton.DownNormal); + break; + case ScrollBarArrowButtonState.DownPressed: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ArrowButton.DownPressed); + break; + case ScrollBarArrowButtonState.LeftDisabled: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ArrowButton.LeftDisabled); + break; + case ScrollBarArrowButtonState.LeftHot: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ArrowButton.LeftHot); + break; + case ScrollBarArrowButtonState.LeftNormal: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ArrowButton.LeftNormal); + break; + case ScrollBarArrowButtonState.LeftPressed: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ArrowButton.LeftPressed); + break; + case ScrollBarArrowButtonState.RightDisabled: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ArrowButton.RightDisabled); + break; + case ScrollBarArrowButtonState.RightHot: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ArrowButton.RightHot); + break; + case ScrollBarArrowButtonState.RightNormal: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ArrowButton.RightNormal); + break; + case ScrollBarArrowButtonState.RightPressed: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ArrowButton.RightPressed); + break; + case ScrollBarArrowButtonState.UpDisabled: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ArrowButton.UpDisabled); + break; + case ScrollBarArrowButtonState.UpHot: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ArrowButton.UpHot); + break; + case ScrollBarArrowButtonState.UpNormal: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ArrowButton.UpNormal); + break; + case ScrollBarArrowButtonState.UpPressed: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ArrowButton.UpPressed); + break; + } + + vsr.DrawBackground(g, bounds); + } + + public static void DrawHorizontalThumb (Graphics g, Rectangle bounds, ScrollBarState state) + { + if (!IsSupported) + throw new InvalidOperationException (); + + VisualStyleRenderer vsr; + + switch (state) { + case ScrollBarState.Disabled: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ThumbButtonHorizontal.Disabled); + break; + case ScrollBarState.Hot: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ThumbButtonHorizontal.Hot); + break; + case ScrollBarState.Normal: + default: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ThumbButtonHorizontal.Normal); + break; + case ScrollBarState.Pressed: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ThumbButtonHorizontal.Pressed); + break; + } + + vsr.DrawBackground (g, bounds); + } + + public static void DrawHorizontalThumbGrip (Graphics g, Rectangle bounds, ScrollBarState state) + { + if (!IsSupported) + throw new InvalidOperationException (); + + VisualStyleRenderer vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.GripperHorizontal.Normal); + + vsr.DrawBackground (g, bounds); + } + + public static void DrawLeftHorizontalTrack (Graphics g, Rectangle bounds, ScrollBarState state) + { + if (!IsSupported) + throw new InvalidOperationException (); + + VisualStyleRenderer vsr; + + switch (state) { + case ScrollBarState.Disabled: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.LeftTrackHorizontal.Disabled); + break; + case ScrollBarState.Hot: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.LeftTrackHorizontal.Hot); + break; + case ScrollBarState.Normal: + default: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.LeftTrackHorizontal.Normal); + break; + case ScrollBarState.Pressed: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.LeftTrackHorizontal.Pressed); + break; + } + + vsr.DrawBackground (g, bounds); + } + + public static void DrawLowerVerticalTrack (Graphics g, Rectangle bounds, ScrollBarState state) + { + if (!IsSupported) + throw new InvalidOperationException (); + + VisualStyleRenderer vsr; + + switch (state) { + case ScrollBarState.Disabled: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.LowerTrackVertical.Disabled); + break; + case ScrollBarState.Hot: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.LowerTrackVertical.Hot); + break; + case ScrollBarState.Normal: + default: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.LowerTrackVertical.Normal); + break; + case ScrollBarState.Pressed: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.LowerTrackVertical.Pressed); + break; + } + + vsr.DrawBackground (g, bounds); + } + + public static void DrawRightHorizontalTrack (Graphics g, Rectangle bounds, ScrollBarState state) + { + if (!IsSupported) + throw new InvalidOperationException (); + + VisualStyleRenderer vsr; + + switch (state) { + case ScrollBarState.Disabled: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.RightTrackHorizontal.Disabled); + break; + case ScrollBarState.Hot: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.RightTrackHorizontal.Hot); + break; + case ScrollBarState.Normal: + default: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.RightTrackHorizontal.Normal); + break; + case ScrollBarState.Pressed: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.RightTrackHorizontal.Pressed); + break; + } + + vsr.DrawBackground (g, bounds); + } + + public static void DrawSizeBox (Graphics g, Rectangle bounds, ScrollBarSizeBoxState state) + { + if (!IsSupported) + throw new InvalidOperationException (); + + VisualStyleRenderer vsr; + + switch (state) { + case ScrollBarSizeBoxState.LeftAlign: + default: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.SizeBox.LeftAlign); + break; + case ScrollBarSizeBoxState.RightAlign: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.SizeBox.RightAlign); + break; + } + + vsr.DrawBackground (g, bounds); + } + + public static void DrawUpperVerticalTrack (Graphics g, Rectangle bounds, ScrollBarState state) + { + if (!IsSupported) + throw new InvalidOperationException (); + + VisualStyleRenderer vsr; + + switch (state) { + case ScrollBarState.Disabled: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.UpperTrackVertical.Disabled); + break; + case ScrollBarState.Hot: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.UpperTrackVertical.Hot); + break; + case ScrollBarState.Normal: + default: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.UpperTrackVertical.Normal); + break; + case ScrollBarState.Pressed: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.UpperTrackVertical.Pressed); + break; + } + + vsr.DrawBackground (g, bounds); + } + + public static void DrawVerticalThumb (Graphics g, Rectangle bounds, ScrollBarState state) + { + if (!IsSupported) + throw new InvalidOperationException (); + + VisualStyleRenderer vsr; + + switch (state) { + case ScrollBarState.Disabled: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ThumbButtonVertical.Disabled); + break; + case ScrollBarState.Hot: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ThumbButtonVertical.Hot); + break; + case ScrollBarState.Normal: + default: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ThumbButtonVertical.Normal); + break; + case ScrollBarState.Pressed: + vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.ThumbButtonVertical.Pressed); + break; + } + + vsr.DrawBackground (g, bounds); + } + + public static void DrawVerticalThumbGrip (Graphics g, Rectangle bounds, ScrollBarState state) + { + if (!IsSupported) + throw new InvalidOperationException (); + + VisualStyleRenderer vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.GripperVertical.Normal); ; + + vsr.DrawBackground (g, bounds); + } + + public static Size GetSizeBoxSize (Graphics g, ScrollBarState state) + { + if (!IsSupported) + throw new InvalidOperationException (); + + VisualStyleRenderer vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.SizeBox.LeftAlign); + + return vsr.GetPartSize(g, ThemeSizeType.Draw); + } + + public static Size GetThumbGripSize (Graphics g, ScrollBarState state) + { + if (!IsSupported) + throw new InvalidOperationException (); + + VisualStyleRenderer vsr = new VisualStyleRenderer (VisualStyleElement.ScrollBar.GripperVertical.Normal); + + return vsr.GetPartSize (g, ThemeSizeType.Draw); + } + #endregion + + #region Public Static Properties + public static bool IsSupported { + get { return VisualStyleInformation.IsEnabledByUser && (Application.VisualStyleState == VisualStyleState.ClientAndNonClientAreasEnabled || Application.VisualStyleState == VisualStyleState.ClientAreaEnabled); } + } + #endregion + } +} diff --git a/source/ShiftUI/Widgets/ScrollButton.cs b/source/ShiftUI/Widgets/ScrollButton.cs new file mode 100644 index 0000000..2c95da8 --- /dev/null +++ b/source/ShiftUI/Widgets/ScrollButton.cs @@ -0,0 +1,39 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + + +// COMPLETE + +namespace ShiftUI { + public enum ScrollButton { + Min = 0, + Up = 0, + Down = 1, + Left = 2, + Right = 3, + Max = 3 + } +} diff --git a/source/ShiftUI/Widgets/SizeGrip.cs b/source/ShiftUI/Widgets/SizeGrip.cs new file mode 100644 index 0000000..3e33462 --- /dev/null +++ b/source/ShiftUI/Widgets/SizeGrip.cs @@ -0,0 +1,293 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2005 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + +using System; +using System.Drawing; + +namespace ShiftUI { + + internal class SizeGrip : Widget { + #region Local Variables + private Point capture_point; + private Widget captured_Widget; + private int window_w; + private int window_h; + private bool hide_pending; + private bool captured; + private bool is_virtual; // If virtual the size grip is painted directly on the captured Widgets' surface. + private bool enabled; + private bool fill_background; + private Rectangle last_painted_area; // The last area that was painted (to know which area to invalidate when resizing). + #endregion // Local Variables + + #region Constructors + public SizeGrip (Widget CapturedWidget) + { + this.Cursor = Cursors.SizeNWSE; + enabled = true; + fill_background = true; + this.Size = GetDefaultSize (); + this.CapturedWidget = CapturedWidget; + } + #endregion // Constructors + + #region Properties + public bool FillBackground { + get { + return fill_background; + } + set { + fill_background = value; + } + } + + public bool Virtual { + get { + return is_virtual; + } + set { + if (is_virtual == value) + return; + + is_virtual = value; + if (is_virtual) { + CapturedWidget.MouseMove += new MouseEventHandler(HandleMouseMove); + CapturedWidget.MouseUp += new MouseEventHandler(HandleMouseUp); + CapturedWidget.MouseDown += new MouseEventHandler(HandleMouseDown); + CapturedWidget.EnabledChanged += new EventHandler(HandleEnabledChanged); + CapturedWidget.Resize += new EventHandler(HandleResize); + } else { + CapturedWidget.MouseMove -= new MouseEventHandler (HandleMouseMove); + CapturedWidget.MouseUp -= new MouseEventHandler (HandleMouseUp); + CapturedWidget.MouseDown -= new MouseEventHandler (HandleMouseDown); + CapturedWidget.EnabledChanged -= new EventHandler (HandleEnabledChanged); + CapturedWidget.Resize -= new EventHandler (HandleResize); + } + } + } + + public Widget CapturedWidget { + get { + return captured_Widget; + } + set { + captured_Widget = value; + } + } + + #endregion // Properties + + #region Methods + static internal Size GetDefaultSize () { + return new Size (SystemInformation.VerticalScrollBarWidth, SystemInformation.HorizontalScrollBarHeight); + } + + static internal Rectangle GetDefaultRectangle (Widget Parent) + { + Size size = GetDefaultSize (); + return new Rectangle (Parent.ClientSize.Width - size.Width, Parent.ClientSize.Height - size.Height, size.Width, size.Height); + } + + private void HandleResize (object sender, EventArgs e) + { + Widget ctrl = (Widget) sender; + ctrl.Invalidate (last_painted_area); + } + + private void HandleEnabledChanged (object sender, EventArgs e) + { + Widget ctrl = (Widget) sender; + enabled = ctrl.Enabled; + Cursor cursor; + if (enabled) { + cursor = Cursors.SizeNWSE; + } else { + cursor = Cursors.Default; + } + if (is_virtual) { + if (CapturedWidget != null) + CapturedWidget.Cursor = cursor; + } else { + this.Cursor = cursor; + } + ctrl.Invalidate (GetDefaultRectangle (ctrl)); + + } + + // This method needs to be internal, since the captured Widget must be able to call + // it. We can't use events to hook it up, since then the paint ordering won't be correct + internal void HandlePaint (object sender, PaintEventArgs e) + { + if (Visible) { + Widget destination = (Widget) sender; + Graphics gr = e.Graphics; + Rectangle rect = GetDefaultRectangle (destination); + + if (!is_virtual || fill_background) { + gr.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorControl), rect); + } + if (enabled) { + WidgetPaint.DrawSizeGrip (gr, BackColor, rect); + } + last_painted_area = rect; + } + } + + private void HandleMouseCaptureChanged (object sender, EventArgs e) + { + Widget ctrl = (Widget) sender; + if (captured && !ctrl.Capture) { + captured = false; + CapturedWidget.Size = new Size (window_w, window_h); + } + } + + internal void HandleMouseDown (object sender, MouseEventArgs e) + { + if (enabled) { + Widget ctrl = (Widget)sender; + if (!GetDefaultRectangle (ctrl).Contains (e.X, e.Y)) { + return; + } + + ctrl.Capture = true; + captured = true; + capture_point = Widget.MousePosition; + + window_w = CapturedWidget.Width; + window_h = CapturedWidget.Height; + } + } + + internal void HandleMouseMove (object sender, MouseEventArgs e) + { + Widget ctrl = (Widget) sender; + Rectangle rect = GetDefaultRectangle (ctrl); + + if (rect.Contains (e.X, e.Y)) { + ctrl.Cursor = Cursors.SizeNWSE; + } else { + ctrl.Cursor = Cursors.Default; + } + + if (captured) { + int delta_x; + int delta_y; + Point current_point; + + current_point = Widget.MousePosition; + + delta_x = current_point.X - capture_point.X; + delta_y = current_point.Y - capture_point.Y; + + Widget parent = CapturedWidget; + Form form_parent = parent as Form; + Size new_size = new Size (window_w + delta_x, window_h + delta_y); + Size max_size = form_parent != null ? form_parent.MaximumSize : Size.Empty; + Size min_size = form_parent != null ? form_parent.MinimumSize : Size.Empty; + + if (new_size.Width > max_size.Width && max_size.Width > 0) + new_size.Width = max_size.Width; + else if (new_size.Width < min_size.Width) + new_size.Width = min_size.Width; + + if (new_size.Height > max_size.Height && max_size.Height > 0) + new_size.Height = max_size.Height; + else if (new_size.Height < min_size.Height) + new_size.Height = min_size.Height; + + if (new_size != parent.Size) { + parent.Size = new_size; + } + } + } + + internal void HandleMouseUp (object sender, MouseEventArgs e) + { + if (captured) { + Widget ctrl = (Widget) sender; + captured = false; + ctrl.Capture = false; + ctrl.Invalidate (last_painted_area); + + if (Parent is ScrollableWidget) { + ((ScrollableWidget)Parent).UpdateSizeGripVisible (); + } + if (hide_pending) { + Hide(); + hide_pending = false; + } + } + } + + + protected override void SetVisibleCore(bool value) { + if (Capture) { + if (value == false) { + hide_pending = true; + } else { + hide_pending = false; + } + return; + } + base.SetVisibleCore (value); + } + + protected override void OnPaint (PaintEventArgs pe) + { + HandlePaint (this, pe); + base.OnPaint (pe); + } + + protected override void OnMouseCaptureChanged (EventArgs e) + { + base.OnMouseCaptureChanged (e); + HandleMouseCaptureChanged (this, e); + } + + protected override void OnEnabledChanged (EventArgs e) + { + base.OnEnabledChanged (e); + HandleEnabledChanged (this, e); + } + + protected override void OnMouseDown (MouseEventArgs e) + { + HandleMouseDown (this, e); + } + + protected override void OnMouseMove(MouseEventArgs e) + { + HandleMouseMove (this, e); + } + + protected override void OnMouseUp (MouseEventArgs e) + { + HandleMouseUp (this, e); + } + #endregion // Methods + } +} + + diff --git a/source/ShiftUI/Widgets/SizeGripStyle.cs b/source/ShiftUI/Widgets/SizeGripStyle.cs new file mode 100644 index 0000000..cdfc82c --- /dev/null +++ b/source/ShiftUI/Widgets/SizeGripStyle.cs @@ -0,0 +1,37 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004 Novell, Inc. (http://www.novell.com) +// +// Author: +// Ravindra (rkumar@novell.com) +// + +// COMPLETE + + +namespace ShiftUI +{ + public enum SizeGripStyle + { + Auto = 0, + Show = 1, + Hide = 2 + } +} diff --git a/source/ShiftUI/Widgets/StatusBar.cs b/source/ShiftUI/Widgets/StatusBar.cs new file mode 100644 index 0000000..2e99958 --- /dev/null +++ b/source/ShiftUI/Widgets/StatusBar.cs @@ -0,0 +1,806 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + +// +// TODO: +// - Change cursor when mouse is over grip +// + +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Drawing.Text; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI { + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [DefaultEvent("PanelClick")] + //[Designer("ShiftUI.Design.StatusBarDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [DefaultProperty("Text")] + public class StatusBar : Widget { + #region Fields + private StatusBarPanelCollection panels; + + private bool show_panels = false; + private bool sizing_grip = true; + + // Stuff for panel Tooltips + private Timer tooltip_timer; + private ToolTip tooltip_window; + private StatusBarPanel tooltip_currently_showing; + #endregion // Fields + + #region Public Constructors + public StatusBar () + { + Dock = DockStyle.Bottom; + this.TabStop = false; + this.SetStyle(Widgetstyles.UserPaint | Widgetstyles.Selectable, false); + + // For displaying/hiding tooltips + MouseMove += new MouseEventHandler (StatusBar_MouseMove); + MouseLeave += new EventHandler (StatusBar_MouseLeave); + } + #endregion // Public Constructors + + #region Public Instance Properties + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override Color BackColor { + get { return base.BackColor; } + set { base.BackColor = value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override Image BackgroundImage { + get { return base.BackgroundImage; } + set { base.BackgroundImage = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override ImageLayout BackgroundImageLayout { + get { + return base.BackgroundImageLayout; + } + set { + base.BackgroundImageLayout = value; + } + } + + [Localizable(true)] + [DefaultValue(DockStyle.Bottom)] + public override DockStyle Dock { + get { return base.Dock; } + set { base.Dock = value; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + protected override bool DoubleBuffered { + get { + return base.DoubleBuffered; + } + set { + base.DoubleBuffered = value; + } + } + + [Localizable(true)] + public override Font Font { + get { return base.Font; } + set { + if (value == Font) + return; + base.Font = value; + UpdateStatusBar (); + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override Color ForeColor { + get { return base.ForeColor; } + set { base.ForeColor = value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new ImeMode ImeMode { + get { return base.ImeMode; } + set { base.ImeMode = value; } + } + + [MergableProperty(false)] + [Localizable(true)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public StatusBarPanelCollection Panels { + get { + if (panels == null) + panels = new StatusBarPanelCollection (this); + return panels; + } + } + + [DefaultValue(false)] + public bool ShowPanels { + get { return show_panels; } + set { + if (show_panels == value) + return; + show_panels = value; + UpdateStatusBar (); + } + } + + [DefaultValue(true)] + public bool SizingGrip { + get { return sizing_grip; } + set { + if (sizing_grip == value) + return; + sizing_grip = value; + UpdateStatusBar (); + } + } + + [DefaultValue(false)] + public new bool TabStop { + get { return base.TabStop; } + set { base.TabStop = value; } + } + + [Localizable(true)] + public override string Text { + get { return base.Text; } + set { + if (value == Text) + return; + base.Text = value; + UpdateStatusBar (); + } + + } + + #endregion Public Instance Properties + + #region Protected Instance Properties + protected override CreateParams CreateParams { + get { + return base.CreateParams; + } + } + + protected override ImeMode DefaultImeMode { + get { return ImeMode.Disable; } + } + + protected override Size DefaultSize { + get { return ThemeEngine.Current.StatusBarDefaultSize; } + } + + #endregion // Protected Instance Properties + + #region Public Instance Methods + public override string ToString () { + return base.ToString () + ", Panels.Count: " + Panels.Count + + (Panels.Count > 0 ? ", Panels[0]: " + Panels [0] : String.Empty); + } + + #endregion // Public Instance Methods + + #region Protected Instance Methods + protected override void CreateHandle () + { + base.CreateHandle (); + } + + protected override void Dispose (bool disposing) { + base.Dispose (disposing); + } + + protected virtual void OnDrawItem (StatusBarDrawItemEventArgs sbdievent) { + StatusBarDrawItemEventHandler eh = (StatusBarDrawItemEventHandler)(Events [DrawItemEvent]); + if (eh != null) + eh (this, sbdievent); + } + + protected override void OnHandleCreated (EventArgs e) { + base.OnHandleCreated (e); + CalcPanelSizes (); + } + + protected override void OnHandleDestroyed (EventArgs e) { + base.OnHandleDestroyed (e); + } + + protected override void OnLayout (LayoutEventArgs levent) { + base.OnLayout (levent); + } + + protected override void OnMouseDown (MouseEventArgs e) { + if (panels == null) + return; + + float prev_x = 0; + float gap = ThemeEngine.Current.StatusBarHorzGapWidth; + for (int i = 0; i < panels.Count; i++) { + float x = panels [i].Width + prev_x + (i == panels.Count - 1 ? gap : gap / 2); + if (e.X >= prev_x && e.X <= x) { + OnPanelClick (new StatusBarPanelClickEventArgs (panels [i], + e.Button, e.Clicks, e.X, e.Y)); + break; + } + prev_x = x; + } + + base.OnMouseDown (e); + } + + protected virtual void OnPanelClick (StatusBarPanelClickEventArgs e) { + StatusBarPanelClickEventHandler eh = (StatusBarPanelClickEventHandler)(Events [PanelClickEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnResize (EventArgs e) + { + base.OnResize (e); + + if (Width <= 0 || Height <= 0) + return; + + UpdateStatusBar (); + } + + protected override void WndProc(ref Message m) { + base.WndProc (ref m); + } + + #endregion // Methods + + + #region Internal Methods + internal void OnDrawItemInternal (StatusBarDrawItemEventArgs e) + { + OnDrawItem (e); + } + + internal void UpdatePanel (StatusBarPanel panel) + { + if (panel.AutoSize == StatusBarPanelAutoSize.Contents) { + UpdateStatusBar (); + return; + } + + UpdateStatusBar (); + } + + internal void UpdatePanelContents (StatusBarPanel panel) + { + if (panel.AutoSize == StatusBarPanelAutoSize.Contents) { + UpdateStatusBar (); + Invalidate (); + return; + } + + Invalidate (new Rectangle (panel.X + 2, 2, panel.Width - 4, bounds.Height - 4)); + } + + void UpdateStatusBar () + { + CalcPanelSizes (); + Refresh (); + } + + internal override void OnPaintInternal (PaintEventArgs pevent) + { + Draw (pevent.Graphics, pevent.ClipRectangle); + } + + private void CalcPanelSizes () + { + if (panels == null || !show_panels) + return; + + if (Width == 0 || Height == 0) + return; + + int border = 2; + int gap = ThemeEngine.Current.StatusBarHorzGapWidth; + int taken = 0; + ArrayList springs = null; + + taken = border; + for (int i = 0; i < panels.Count; i++) { + StatusBarPanel p = panels [i]; + + if (p.AutoSize == StatusBarPanelAutoSize.None) { + taken += p.Width; + taken += gap; + continue; + } + if (p.AutoSize == StatusBarPanelAutoSize.Contents) { + int len = (int)(TextRenderer.MeasureString (p.Text, Font).Width + 0.5F); + if (p.Icon != null) { + len += 21; + } + p.SetWidth (len + 8); + taken += p.Width; + taken += gap; + continue; + } + if (p.AutoSize == StatusBarPanelAutoSize.Spring) { + if (springs == null) + springs = new ArrayList (); + springs.Add (p); + taken += gap; + continue; + } + } + + if (springs != null) { + int spring_total = springs.Count; + int total_width = Width - taken - (SizingGrip ? ThemeEngine.Current.StatusBarSizeGripWidth : 0); + for (int i = 0; i < spring_total; i++) { + StatusBarPanel p = (StatusBarPanel)springs[i]; + int width = total_width / spring_total; + p.SetWidth(width >= p.MinWidth ? width : p.MinWidth); + } + } + + taken = border; + for (int i = 0; i < panels.Count; i++) { + StatusBarPanel p = panels [i]; + p.X = taken; + taken += p.Width + gap; + } + } + + private void Draw (Graphics dc, Rectangle clip) + { + ThemeEngine.Current.DrawStatusBar (dc, clip, this); + + } + #endregion // Internal Methods + + #region Stuff for ToolTips + private void StatusBar_MouseMove (object sender, MouseEventArgs e) + { + if (!show_panels) + return; + + StatusBarPanel p = GetPanelAtPoint (e.Location); + + if (p != tooltip_currently_showing) + MouseLeftPanel (tooltip_currently_showing); + + if (p != null && tooltip_currently_showing == null) + MouseEnteredPanel (p); + } + + private void StatusBar_MouseLeave (object sender, EventArgs e) + { + if (tooltip_currently_showing != null) + MouseLeftPanel (tooltip_currently_showing); + } + + private StatusBarPanel GetPanelAtPoint (Point point) + { + foreach (StatusBarPanel p in Panels) + if (point.X >= p.X && point.X <= (p.X + p.Width)) + return p; + + return null; + } + + private void MouseEnteredPanel (StatusBarPanel item) + { + tooltip_currently_showing = item; + ToolTipTimer.Start (); + } + + private void MouseLeftPanel (StatusBarPanel item) + { + ToolTipTimer.Stop (); + ToolTipWindow.Hide (this); + tooltip_currently_showing = null; + } + + private Timer ToolTipTimer { + get { + if (tooltip_timer == null) { + tooltip_timer = new Timer (); + tooltip_timer.Enabled = false; + tooltip_timer.Interval = 500; + tooltip_timer.Tick += new EventHandler (ToolTipTimer_Tick); + } + + return tooltip_timer; + } + } + + private ToolTip ToolTipWindow { + get { + if (tooltip_window == null) + tooltip_window = new ToolTip (); + + return tooltip_window; + } + } + + private void ToolTipTimer_Tick (object o, EventArgs args) + { + string tooltip = tooltip_currently_showing.ToolTipText; + + if (tooltip != null && tooltip.Length > 0) + ToolTipWindow.Present (this, tooltip); + + ToolTipTimer.Stop (); + } + #endregion + + #region Events + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler BackColorChanged { + add { base.BackColorChanged += value; } + remove { base.BackColorChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageChanged { + add { base.BackgroundImageChanged += value; } + remove { base.BackgroundImageChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageLayoutChanged + { + add { base.BackgroundImageLayoutChanged += value; } + remove { base.BackgroundImageLayoutChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler ForeColorChanged { + add { base.ForeColorChanged += value; } + remove { base.ForeColorChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler ImeModeChanged { + add { base.ImeModeChanged += value; } + remove { base.ImeModeChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event PaintEventHandler Paint { + add { base.Paint += value; } + remove { base.Paint -= value; } + } + + static object DrawItemEvent = new object (); + static object PanelClickEvent = new object (); + + public event StatusBarDrawItemEventHandler DrawItem { + add { Events.AddHandler (DrawItemEvent, value); } + remove { Events.RemoveHandler (DrawItemEvent, value); } + } + + public event StatusBarPanelClickEventHandler PanelClick { + add { Events.AddHandler (PanelClickEvent, value); } + remove { Events.RemoveHandler (PanelClickEvent, value); } + } + #endregion // Events + + + #region Subclass StatusBarPanelCollection + [ListBindable (false)] + public class StatusBarPanelCollection : IList, ICollection, IEnumerable { + #region Fields + private StatusBar owner; + private ArrayList panels = new ArrayList (); + private int last_index_by_key; + #endregion // Fields + + #region UIA Framework Events + static object UIACollectionChangedEvent = new object (); + + internal event CollectionChangeEventHandler UIACollectionChanged { + add { owner.Events.AddHandler (UIACollectionChangedEvent, value); } + remove { owner.Events.RemoveHandler (UIACollectionChangedEvent, value); } + } + + internal void OnUIACollectionChanged (CollectionChangeEventArgs e) + { + CollectionChangeEventHandler eh + = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent]; + if (eh != null) + eh (owner, e); + } + #endregion + + #region Public Constructors + public StatusBarPanelCollection (StatusBar owner) + { + this.owner = owner; + } + + #endregion // Public Constructors + + #region Private & Internal Methods + private int AddInternal (StatusBarPanel p, bool refresh) { + if (p == null) + throw new ArgumentNullException ("value"); + + p.SetParent (owner); + int res = panels.Add (p); + + if (refresh) { + owner.CalcPanelSizes (); + owner.Refresh (); + } + + // UIA Framework Event: Panel Added + OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, res)); + + return res; + } + + #endregion // Private & Internal Methods + + #region Public Instance Properties + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public int Count { + get { return panels.Count; } + } + + public bool IsReadOnly { + get { return false; } + } + + public virtual StatusBarPanel this [int index] { + get { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("index"); + return (StatusBarPanel) panels [index]; + } + set { + if (value == null) + throw new ArgumentNullException ("index"); + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException ("index"); + + // UIA Framework Event: Panel Removed + OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, index)); + + value.SetParent (owner); + + panels [index] = value; + + // UIA Framework Event: Panel Added + OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, index)); + } + } + + public virtual StatusBarPanel this [string key] { + get { + int index = IndexOfKey (key); + if (index >= 0 && index < Count) { + return (StatusBarPanel) panels [index]; + } + return null; + } + } + + #endregion // Public Instance Properties + + #region Public Instance Methods + public virtual int Add (StatusBarPanel value) { + return AddInternal (value, true); + } + + public virtual StatusBarPanel Add (string text) { + StatusBarPanel res = new StatusBarPanel (); + res.Text = text; + Add (res); + return res; + } + + public virtual void AddRange (StatusBarPanel [] panels) { + if (panels == null) + throw new ArgumentNullException ("panels"); + if (panels.Length == 0) + return; + + for (int i = 0; i < panels.Length; i++) + AddInternal (panels [i], false); + owner.Refresh (); + } + + public virtual void Clear () { + panels.Clear (); + + owner.Refresh (); + + // UIA Framework Event: Panel Cleared + OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, -1)); + } + + public bool Contains (StatusBarPanel panel) { + return panels.Contains (panel); + } + + public virtual bool ContainsKey (string key) + { + int index = IndexOfKey (key); + return index >= 0 && index < Count; + } + + public IEnumerator GetEnumerator () { + return panels.GetEnumerator (); + } + + public int IndexOf (StatusBarPanel panel) { + return panels.IndexOf (panel); + } + + public virtual int IndexOfKey (string key) + { + if (key == null || key == string.Empty) + return -1; + + if (last_index_by_key >= 0 && last_index_by_key < Count && + String.Compare (((StatusBarPanel)panels [last_index_by_key]).Name, key, StringComparison.OrdinalIgnoreCase) == 0) { + return last_index_by_key; + } + + for (int i = 0; i < Count; i++) { + StatusBarPanel item; + item = panels [i] as StatusBarPanel; + if (item != null && String.Compare (item.Name, key, StringComparison.OrdinalIgnoreCase) == 0) { + last_index_by_key = i; + return i; + } + } + + return -1; + } + + public virtual void Insert (int index, StatusBarPanel value) { + if (value == null) + throw new ArgumentNullException ("value"); + if (index > Count) + throw new ArgumentOutOfRangeException ("index"); + // TODO: InvalidArgumentException for bad AutoSize values + // although it seems impossible to set it to a bad value + value.SetParent (owner); + + panels.Insert(index, value); + owner.Refresh (); + + // UIA Framework Event: Panel Added + OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, index)); + } + + public virtual void Remove (StatusBarPanel value) { + int index = IndexOf (value); + panels.Remove (value); + + // UIA Framework Event: Panel Removed + if (index >= 0) + OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, index)); + } + + public virtual void RemoveAt (int index) { + panels.RemoveAt (index); + + // UIA Framework Event: Panel Removed + OnUIACollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, index)); + } + + public virtual void RemoveByKey (string key) + { + int index = IndexOfKey (key); + if (index >= 0 && index < Count) + RemoveAt (index); + } + + #endregion // Public Instance Methods + + #region IList & ICollection Interfaces + bool ICollection.IsSynchronized { + get { return panels.IsSynchronized; } + } + + object ICollection.SyncRoot { + get { return panels.SyncRoot; } + } + + void ICollection.CopyTo (Array dest, int index) + { + panels.CopyTo (dest, index); + } + + + object IList.this [int index] { + get { return this[index]; } + set { + if (!(value is StatusBarPanel)) + throw new ArgumentException ("Value must be of type StatusBarPanel.", "value"); + + this[index] = (StatusBarPanel)value; + } + } + + int IList.Add (object value) { + if (!(value is StatusBarPanel)) + throw new ArgumentException ("Value must be of type StatusBarPanel.", "value"); + + return AddInternal ((StatusBarPanel)value, true); + } + + bool IList.Contains (object panel) { + return panels.Contains (panel); + } + + int IList.IndexOf (object panel) + { + return panels.IndexOf (panel); + } + + void IList.Insert (int index, object value) + { + if (!(value is StatusBarPanel)) + throw new ArgumentException ("Value must be of type StatusBarPanel.", "value"); + + Insert (index, (StatusBarPanel)value); + } + + bool IList.IsFixedSize { + get { return false; } + } + + void IList.Remove (object value) + { + StatusBarPanel s = value as StatusBarPanel; + Remove (s); + } + #endregion // IList & ICollection Interfaces + } + #endregion // Subclass StatusBarPanelCollection + } + +} + diff --git a/source/ShiftUI/Widgets/StatusBarPanel.cs b/source/ShiftUI/Widgets/StatusBarPanel.cs new file mode 100644 index 0000000..bdbfa64 --- /dev/null +++ b/source/ShiftUI/Widgets/StatusBarPanel.cs @@ -0,0 +1,272 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + +// COMPLETE + +using System; +using System.Drawing; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Runtime.InteropServices; + +namespace ShiftUI { + [ToolboxItem (false)] + [DefaultProperty("Text")] + [DesignTimeVisible(false)] + public class StatusBarPanel : Component, ISupportInitialize { + #region Local Variables + private StatusBar parent; + + private bool initializing; + private string text = String.Empty; + private string tool_tip_text = String.Empty; + + private Icon icon; + private HorizontalAlignment alignment = HorizontalAlignment.Left; + private StatusBarPanelAutoSize auto_size = StatusBarPanelAutoSize.None; + private StatusBarPanelBorderStyle border_style = StatusBarPanelBorderStyle.Sunken; + private StatusBarPanelStyle style = StatusBarPanelStyle.Text; + private int width = 100; + private int min_width = 10; + internal int X; + + private string name; + private object tag; + #endregion // Local Variables + + #region UIA Framework Events + static object UIATextChangedEvent = new object (); + + internal event EventHandler UIATextChanged { + add { Events.AddHandler (UIATextChangedEvent, value); } + remove { Events.RemoveHandler (UIATextChangedEvent, value); } + } + + internal void OnUIATextChanged (EventArgs e) + { + EventHandler eh = (EventHandler) Events [UIATextChangedEvent]; + if (eh != null) + eh (this, e); + } + #endregion + + #region Constructors + public StatusBarPanel () + { + } + #endregion // Constructors + + [DefaultValue(HorizontalAlignment.Left)] + [Localizable(true)] + public HorizontalAlignment Alignment { + get { return alignment; } + set { + alignment = value; + InvalidateContents (); + } + } + + [RefreshProperties (RefreshProperties.All)] + [DefaultValue(StatusBarPanelAutoSize.None)] + public StatusBarPanelAutoSize AutoSize { + get { return auto_size; } + set { + auto_size = value; + Invalidate (); + } + } + + [DefaultValue(StatusBarPanelBorderStyle.Sunken)] + [DispId(-504)] + public StatusBarPanelBorderStyle BorderStyle { + get { return border_style; } + set { + border_style = value; + Invalidate (); + } + } + + [DefaultValue(null)] + [Localizable(true)] + public Icon Icon { + get { return icon; } + set { + icon = value; + InvalidateContents (); + } + } + + [DefaultValue(10)] + [Localizable(true)] + [RefreshProperties(RefreshProperties.All)] + public int MinWidth { + get { + /* + MSDN says that when AutoSize = None then MinWidth is automatically + set to Width, but neither v1.1 nor v2.0 behave that way. + */ + return min_width; + } + set { + if (value < 0) + throw new ArgumentOutOfRangeException ("value"); + + min_width = value; + if (min_width > width) + width = min_width; + + Invalidate (); + } + } + + [Localizable (true)] + public string Name { + get { + if (name == null) + return string.Empty; + return name; + } + set { + name = value; + } + } + + [DefaultValue(100)] + [Localizable(true)] + public int Width { + get { return width; } + set { + if (value < 0) + throw new ArgumentException ("value"); + + if (initializing) + width = value; + else + SetWidth(value); + + Invalidate (); + } + } + + [DefaultValue(StatusBarPanelStyle.Text)] + public StatusBarPanelStyle Style { + get { return style; } + set { + style = value; + Invalidate (); + } + } + + [TypeConverter (typeof (StringConverter))] + [Localizable (false)] + [Bindable (true)] + [DefaultValue (null)] + public object Tag { + get { + return tag; + } + set { + tag = value; + } + } + + [DefaultValue("")] + [Localizable(true)] + public string Text { + get { return text; } + set { + text = value; + InvalidateContents (); + + // UIA Framework Event: Text Changed + OnUIATextChanged (EventArgs.Empty); + } + } + + [DefaultValue("")] + [Localizable(true)] + public string ToolTipText { + get { return tool_tip_text; } + set { tool_tip_text = value; } + } + + [Browsable(false)] + public StatusBar Parent { + get { return parent; } + } + + private void Invalidate () + { + if (parent == null) + return; + parent.UpdatePanel (this); + } + + private void InvalidateContents () + { + if (parent == null) + return; + parent.UpdatePanelContents (this); + } + + internal void SetParent (StatusBar parent) + { + this.parent = parent; + } + + internal void SetWidth (int width) + { + this.width = width; + if (min_width > this.width) + this.width = min_width; + } + + public override string ToString () + { + return "StatusBarPanel: {" + Text +"}"; + } + + protected override void Dispose (bool disposing) + { + } + + public void BeginInit () + { + initializing = true; + } + + public void EndInit () + { + if (!initializing) + return; + + if (min_width > width) + width = min_width; + + initializing = false; + } + } +} + + diff --git a/source/ShiftUI/Widgets/StatusStrip.cs b/source/ShiftUI/Widgets/StatusStrip.cs new file mode 100644 index 0000000..3ac3600 --- /dev/null +++ b/source/ShiftUI/Widgets/StatusStrip.cs @@ -0,0 +1,313 @@ +// +// StatusStrip.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Drawing; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace ShiftUI +{ + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + public class StatusStrip : ToolStrip + { + private bool sizing_grip; + + public StatusStrip () + { + SetStyle (Widgetstyles.ResizeRedraw, true); + + base.CanOverflow = false; + this.GripStyle = ToolStripGripStyle.Hidden; + base.LayoutStyle = ToolStripLayoutStyle.Table; + base.RenderMode = ToolStripRenderMode.System; + this.sizing_grip = true; + base.Stretch = true; + } + + #region Public Properties + [DefaultValue (DockStyle.Bottom)] + public override DockStyle Dock { + get { return base.Dock; } + set { base.Dock = value; } + } + + [Browsable (false)] + [DefaultValue (false)] + public new bool CanOverflow { + get { return base.CanOverflow; } + set { base.CanOverflow = value; } + } + + [DefaultValue (ToolStripGripStyle.Hidden)] + public new ToolStripGripStyle GripStyle { + get { return base.GripStyle; } + set { base.GripStyle = value; } + } + + [DefaultValue (ToolStripLayoutStyle.Table)] + public new ToolStripLayoutStyle LayoutStyle { + get { return base.LayoutStyle; } + set { base.LayoutStyle = value; } + } + + [Browsable (false)] + public new Padding Padding { + get { return base.Padding; } + set { base.Padding = value; } + } + + [DefaultValue (false)] + public new bool ShowItemToolTips { + get { return base.ShowItemToolTips; } + set { base.ShowItemToolTips = value; } + } + + [Browsable (false)] + public Rectangle SizeGripBounds { + get { return new Rectangle (this.Width - 12, 0, 12, this.Height); } + } + + [DefaultValue (true)] + public bool SizingGrip { + get { return this.sizing_grip; } + set { this.sizing_grip = value; } + } + + [DefaultValue (true)] + public new bool Stretch { + get { return base.Stretch; } + set { base.Stretch = value; } + } + #endregion + + #region Protected Properties + protected override DockStyle DefaultDock { + get { return DockStyle.Bottom; } + } + + protected override Padding DefaultPadding { + get { return new Padding (1, 0, 14, 0); } + } + + protected override bool DefaultShowItemToolTips { + get { return false; } + } + + protected override Size DefaultSize { + get { return new Size (200, 22); } + } + #endregion + + #region Protected Methods + protected override AccessibleObject CreateAccessibilityInstance () + { + return new StatusStripAccessibleObject (); + } + + protected internal override ToolStripItem CreateDefaultItem (string text, Image image, EventHandler onClick) + { + if (text == "-") + return new ToolStripSeparator (); + + return new ToolStripLabel (text, image, false, onClick); + } + + protected override void Dispose (bool disposing) + { + base.Dispose (disposing); + } + + protected override void OnLayout (LayoutEventArgs levent) + { + this.OnSpringTableLayoutCore (); + this.Invalidate (); + } + + protected override void OnPaintBackground (PaintEventArgs e) + { + base.OnPaintBackground (e); + + if (this.sizing_grip) + this.Renderer.DrawStatusStripSizingGrip (new ToolStripRenderEventArgs (e.Graphics, this, Bounds, SystemColors.Control)); + } + + protected virtual void OnSpringTableLayoutCore () + { + if (!this.Created) + return; + + ToolStripItemOverflow[] overflow = new ToolStripItemOverflow[this.Items.Count]; + ToolStripItemPlacement[] placement = new ToolStripItemPlacement[this.Items.Count]; + Size proposedSize = new Size (0, Bounds.Height); + int[] widths = new int[this.Items.Count]; + int total_width = 0; + int toolstrip_width = DisplayRectangle.Width; + int i = 0; + int spring_count = 0; + + foreach (ToolStripItem tsi in this.Items) { + overflow[i] = tsi.Overflow; + widths[i] = tsi.GetPreferredSize (proposedSize).Width + tsi.Margin.Horizontal; + placement[i] = tsi.Overflow == ToolStripItemOverflow.Always ? ToolStripItemPlacement.None : ToolStripItemPlacement.Main; + placement[i] = tsi.Available && tsi.InternalVisible ? placement[i] : ToolStripItemPlacement.None; + total_width += placement[i] == ToolStripItemPlacement.Main ? widths[i] : 0; + if (tsi is ToolStripStatusLabel && (tsi as ToolStripStatusLabel).Spring) + spring_count++; + + i++; + } + + while (total_width > toolstrip_width) { + bool removed_one = false; + + // Start at the right, removing Overflow.AsNeeded first + for (int j = widths.Length - 1; j >= 0; j--) + if (overflow[j] == ToolStripItemOverflow.AsNeeded && placement[j] == ToolStripItemPlacement.Main) { + placement[j] = ToolStripItemPlacement.None; + total_width -= widths[j]; + removed_one = true; + break; + } + + // If we didn't remove any AsNeeded ones, we have to start removing Never ones + // These are not put on the Overflow, they are simply not shown + if (!removed_one) + for (int j = widths.Length - 1; j >= 0; j--) + if (overflow[j] == ToolStripItemOverflow.Never && placement[j] == ToolStripItemPlacement.Main) { + placement[j] = ToolStripItemPlacement.None; + total_width -= widths[j]; + removed_one = true; + break; + } + + // There's nothing left to remove, break or we will loop forever + if (!removed_one) + break; + } + + if (spring_count > 0) { + int per_item = (toolstrip_width - total_width) / spring_count; + i = 0; + + foreach (ToolStripItem tsi in this.Items) { + if (tsi is ToolStripStatusLabel && (tsi as ToolStripStatusLabel).Spring) + widths[i] += per_item; + + i++; + } + } + + i = 0; + Point layout_pointer = new Point (this.DisplayRectangle.Left, this.DisplayRectangle.Top); + int button_height = this.DisplayRectangle.Height; + + // Now we should know where everything goes, so lay everything out + foreach (ToolStripItem tsi in this.Items) { + tsi.SetPlacement (placement[i]); + + if (placement[i] == ToolStripItemPlacement.Main) { + tsi.SetBounds (new Rectangle (layout_pointer.X + tsi.Margin.Left, layout_pointer.Y + tsi.Margin.Top, widths[i] - tsi.Margin.Horizontal, button_height - tsi.Margin.Vertical)); + layout_pointer.X += widths[i]; + } + + i++; + } + + this.SetDisplayedItems (); + } + + protected override void SetDisplayedItems () + { + // Only clean the internal collection, without modifying Owner/Parent on items. + this.displayed_items.ClearInternal (); + + foreach (ToolStripItem tsi in this.Items) + if (tsi.Placement == ToolStripItemPlacement.Main && tsi.Available) { + this.displayed_items.AddNoOwnerOrLayout (tsi); + tsi.Parent = this; + } + } + + protected override void WndProc (ref Message m) + { + switch ((Msg)m.Msg) { + // If the mouse is over the size grip, change the cursor + case Msg.WM_MOUSEMOVE: { + if (FromParamToMouseButtons ((int) m.WParam.ToInt32()) == MouseButtons.None) { + Point p = new Point (LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ())); + + if (this.SizingGrip && this.SizeGripBounds.Contains (p)) { + this.Cursor = Cursors.SizeNWSE; + return; + } else + this.Cursor = Cursors.Default; + } + + break; + } + // If the left mouse button is pushed over the size grip, + // send the WM a message to begin a window resize operation + case Msg.WM_LBUTTONDOWN: { + Point p = new Point (LowOrder ((int)m.LParam.ToInt32 ()), HighOrder ((int)m.LParam.ToInt32 ())); + Form form = FindForm (); + + if (this.SizingGrip && this.SizeGripBounds.Contains (p)) { + // For top level forms it's not enoug to send a NCLBUTTONDOWN message, so + // we make a direct call to our XplatUI engine. + if (!form.IsMdiChild) + XplatUI.BeginMoveResize (form.Handle); + + XplatUI.SendMessage (form.Handle, Msg.WM_NCLBUTTONDOWN, (IntPtr) HitTest.HTBOTTOMRIGHT, IntPtr.Zero); + return; + } + + break; + } + } + + base.WndProc (ref m); + } + #endregion + + #region Public Events + [Browsable (false)] + public new event EventHandler PaddingChanged { + add { base.PaddingChanged += value; } + remove { base.PaddingChanged -= value; } + } + #endregion + + #region StatusStripAccessibleObject + private class StatusStripAccessibleObject : AccessibleObject + { + } + #endregion + } +} diff --git a/source/ShiftUI/Widgets/TabControl.cs b/source/ShiftUI/Widgets/TabControl.cs new file mode 100644 index 0000000..0404510 --- /dev/null +++ b/source/ShiftUI/Widgets/TabControl.cs @@ -0,0 +1,2008 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +using System; +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Runtime.InteropServices; +using ShiftUI.Theming; +using ShiftUI.VisualStyles; + +namespace ShiftUI { + [ComVisibleAttribute (true)] + [ClassInterfaceAttribute (ClassInterfaceType.AutoDispatch)] + [DefaultEvent("SelectedIndexChanged")] + [DefaultProperty("TabPages")] + //[Designer("ShiftUI.Design.TabControlDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [ToolboxWidget] + public class TabWidget : Widget { + #region Fields + private int selected_index = -1; + private TabAlignment alignment; + private TabAppearance appearance; + private TabDrawMode draw_mode; + private bool multiline; + private ImageList image_list; + private Size item_size = Size.Empty; + private bool item_size_manual; + private Point padding; + private int row_count = 0; + private bool hottrack; + private TabPageCollection tab_pages; + private bool show_tool_tips; + private TabSizeMode size_mode; + private bool show_slider = false; + private PushButtonState right_slider_state = PushButtonState.Normal; + private PushButtonState left_slider_state = PushButtonState.Normal; + private int slider_pos = 0; + TabPage entered_tab_page; + bool mouse_down_on_a_tab_page; + ToolTip tooltip; + ToolTip.TipState tooltip_state = ToolTip.TipState.Down; + Timer tooltip_timer; + + private bool rightToLeftLayout; + #endregion // Fields + + #region UIA Framework Events + static object UIAHorizontallyScrollableChangedEvent = new object (); + + internal event EventHandler UIAHorizontallyScrollableChanged { + add { Events.AddHandler (UIAHorizontallyScrollableChangedEvent, value); } + remove { Events.RemoveHandler (UIAHorizontallyScrollableChangedEvent, value); } + } + + internal void OnUIAHorizontallyScrollableChanged (EventArgs e) + { + EventHandler eh + = (EventHandler) Events [UIAHorizontallyScrollableChangedEvent]; + if (eh != null) + eh (this, e); + } + + static object UIAHorizontallyScrolledEvent = new object (); + + internal event EventHandler UIAHorizontallyScrolled { + add { Events.AddHandler (UIAHorizontallyScrolledEvent, value); } + remove { Events.RemoveHandler (UIAHorizontallyScrolledEvent, value); } + } + + internal void OnUIAHorizontallyScrolled (EventArgs e) + { + EventHandler eh + = (EventHandler) Events [UIAHorizontallyScrolledEvent]; + if (eh != null) + eh (this, e); + } + #endregion + + #region UIA Framework Property + internal double UIAHorizontalViewSize { + get { return LeftScrollButtonArea.Left * 100 / TabPages [TabCount - 1].TabBounds.Right; } + } + #endregion + + #region Public Constructors + public TabWidget () + { + tab_pages = new TabPageCollection (this); + SetStyle (Widgetstyles.UserPaint, false); + padding = ThemeEngine.Current.TabControlDefaultPadding; + + MouseDown += new MouseEventHandler (MouseDownHandler); + MouseLeave += new EventHandler (OnMouseLeave); + MouseMove += new MouseEventHandler (OnMouseMove); + MouseUp += new MouseEventHandler (MouseUpHandler); + SizeChanged += new EventHandler (SizeChangedHandler); + } + + #endregion // Public Constructors + + #region Public Instance Properties + [DefaultValue(TabAlignment.Top)] + [Localizable(true)] + [RefreshProperties(RefreshProperties.All)] + public TabAlignment Alignment { + get { return alignment; } + set { + if (alignment == value) + return; + alignment = value; + if (alignment == TabAlignment.Left || alignment == TabAlignment.Right) + multiline = true; + Redraw (); + } + } + + [DefaultValue(TabAppearance.Normal)] + [Localizable(true)] + public TabAppearance Appearance { + get { return appearance; } + set { + if (appearance == value) + return; + appearance = value; + Redraw (); + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override Color BackColor { + get { return ThemeEngine.Current.ColorControl; } + set { /* nothing happens on set on MS */ } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override Image BackgroundImage { + get { return base.BackgroundImage; } + set { base.BackgroundImage = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + public override Rectangle DisplayRectangle { + get { + return ThemeEngine.Current.TabControlGetDisplayRectangle (this); + } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + protected override bool DoubleBuffered { + get { return base.DoubleBuffered; } + set { base.DoubleBuffered = value; } + } + + [DefaultValue(TabDrawMode.Normal)] + public TabDrawMode DrawMode { + get { return draw_mode; } + set { + if (draw_mode == value) + return; + draw_mode = value; + Redraw (); + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override Color ForeColor { + get { return base.ForeColor; } + set { base.ForeColor = value; } + } + + [DefaultValue(false)] + public bool HotTrack { + get { return hottrack; } + set { + if (hottrack == value) + return; + hottrack = value; + Redraw (); + } + } + + [RefreshProperties (RefreshProperties.Repaint)] + [DefaultValue(null)] + public ImageList ImageList { + get { return image_list; } + set { + image_list = value; + Redraw (); + } + } + + [Localizable(true)] + public Size ItemSize { + get { + if (item_size_manual) + return item_size; + + if (!IsHandleCreated) + return Size.Empty; + + Size size = item_size; + if (SizeMode != TabSizeMode.Fixed) { + size.Width += padding.X * 2; + size.Height += padding.Y * 2; + } + + if (tab_pages.Count == 0) + size.Width = 0; + + return size; + } + set { + if (value.Height < 0 || value.Width < 0) + throw new ArgumentException ("'" + value + "' is not a valid value for 'ItemSize'."); + item_size = value; + item_size_manual = true; + Redraw (); + } + } + + [DefaultValue(false)] + public bool Multiline { + get { return multiline; } + set { + if (multiline == value) + return; + multiline = value; + if (!multiline && alignment == TabAlignment.Left || alignment == TabAlignment.Right) + alignment = TabAlignment.Top; + Redraw (); + } + } + + [Localizable(true)] + public + new + Point Padding { + get { return padding; } + set { + if (value.X < 0 || value.Y < 0) + throw new ArgumentException ("'" + value + "' is not a valid value for 'Padding'."); + if (padding == value) + return; + padding = value; + Redraw (); + } + + } + + [MonoTODO ("RTL not supported")] + [Localizable (true)] + [DefaultValue (false)] + public virtual bool RightToLeftLayout { + get { return this.rightToLeftLayout; } + set { + if (value != this.rightToLeftLayout) { + this.rightToLeftLayout = value; + this.OnRightToLeftLayoutChanged (EventArgs.Empty); + } + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int RowCount { + get { return row_count; } + } + + [DefaultValue(-1)] + [Browsable(false)] + public int SelectedIndex { + get { return selected_index; } + set { + + if (value < -1) { + throw new ArgumentOutOfRangeException ("SelectedIndex", "Value of '" + value + "' is valid for 'SelectedIndex'. " + + "'SelectedIndex' must be greater than or equal to -1."); + } + if (!this.IsHandleCreated) { + if (selected_index != value) { + selected_index = value; + } + return; + } + + if (value >= TabCount) { + if (value != selected_index) + OnSelectedIndexChanged (EventArgs.Empty); + return; + } + + if (value == selected_index) { + if (selected_index > -1) + Invalidate(GetTabRect (selected_index)); + return; + } + + TabControlCancelEventArgs ret = new TabControlCancelEventArgs (SelectedTab, selected_index, false, TabControlAction.Deselecting); + OnDeselecting (ret); + if (ret.Cancel) + return; + + Focus (); + int old_index = selected_index; + int new_index = value; + + selected_index = new_index; + + ret = new TabControlCancelEventArgs (SelectedTab, selected_index, false, TabControlAction.Selecting); + OnSelecting (ret); + if (ret.Cancel) { + selected_index = old_index; + return; + } + + SuspendLayout (); + + Rectangle invalid = Rectangle.Empty; + bool refresh = false; + + if (new_index != -1 && show_slider && new_index < slider_pos) { + slider_pos = new_index; + refresh = true; + } + + if (new_index != -1) { + int le = TabPages[new_index].TabBounds.Right; + int re = LeftScrollButtonArea.Left; + if (show_slider && le > re) { + int i = 0; + for (i = 0; i < new_index; i++) { + if (TabPages [i].TabBounds.Left < 0) // tab scrolled off the visible area, ignore + continue; + + if (TabPages [new_index].TabBounds.Right - TabPages[i].TabBounds.Right < re) { + i++; + break; + } + } + slider_pos = i; + refresh = true; + } + } + + if (old_index != -1 && new_index != -1) { + if (!refresh) + invalid = GetTabRect (old_index); + ((TabPage) Widgets[old_index]).SetVisible (false); + } + + TabPage selected = null; + + if (new_index != -1) { + selected = (TabPage) Widgets[new_index]; + invalid = Rectangle.Union (invalid, GetTabRect (new_index)); + selected.SetVisible (true); + } + + OnSelectedIndexChanged (EventArgs.Empty); + + ResumeLayout (); + + if (refresh) { + SizeTabs (); + Refresh (); + } else if (new_index != -1 && selected.Row != BottomRow) { + DropRow (TabPages[new_index].Row); + // calculating what to invalidate here seems to be slower then just + // refreshing the whole thing + SizeTabs (); + Refresh (); + } else { + SizeTabs (); + // The lines are drawn on the edges of the tabs so the invalid area should + // needs to include the extra pixels of line width (but should not + // overflow the control bounds). + if (appearance == TabAppearance.Normal) { + invalid.Inflate (6, 4); + invalid.Intersect (ClientRectangle); + } + Invalidate (invalid); + } + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public TabPage SelectedTab { + get { + if (selected_index == -1) + return null; + return tab_pages [selected_index]; + } + set { + int index = IndexForTabPage (value); + if (index == selected_index) + return; + SelectedIndex = index; + } + } + + [DefaultValue(false)] + [Localizable(true)] + public bool ShowToolTips { + get { return show_tool_tips; } + set { + if (show_tool_tips == value) + return; + show_tool_tips = value; + } + } + + [DefaultValue(TabSizeMode.Normal)] + [RefreshProperties(RefreshProperties.Repaint)] + public TabSizeMode SizeMode { + get { return size_mode; } + set { + if (size_mode == value) + return; + size_mode = value; + Redraw (); + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int TabCount { + get { + return tab_pages.Count; + } + } + + //[Editor ("ShiftUI.Design.TabPageCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [MergableProperty(false)] + public TabPageCollection TabPages { + get { return tab_pages; } + } + + [Browsable(false)] + [Bindable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override string Text { + get { return base.Text; } + set { base.Text = value; } + } + #endregion // Public Instance Properties + + #region Internal Properties + internal bool ShowSlider { + get { return show_slider; } + set { + show_slider = value; + + // UIA Framework Event: HorizontallyScrollable Changed + OnUIAHorizontallyScrollableChanged (EventArgs.Empty); + } + } + + internal int SliderPos { + get { return slider_pos; } + } + + internal PushButtonState RightSliderState { + get { return right_slider_state; } + private set { + if (right_slider_state == value) + return; + PushButtonState old_value = right_slider_state; + right_slider_state = value; + if (NeedsToInvalidateScrollButton (old_value, value)) + Invalidate (RightScrollButtonArea); + } + } + + internal PushButtonState LeftSliderState { + get { return left_slider_state; } + set { + if (left_slider_state == value) + return; + PushButtonState old_value = left_slider_state; + left_slider_state = value; + if (NeedsToInvalidateScrollButton (old_value, value)) + Invalidate (LeftScrollButtonArea); + } + } + + bool NeedsToInvalidateScrollButton (PushButtonState oldState, PushButtonState newState) + { + if ((oldState == PushButtonState.Hot && newState == PushButtonState.Normal) || + (oldState == PushButtonState.Normal && newState == PushButtonState.Hot)) + return HasHotElementStyles; + return true; + } + + internal TabPage EnteredTabPage { + get { return entered_tab_page; } + private set { + if (entered_tab_page == value) + return; + if (HasHotElementStyles) { + Region area_to_invalidate = new Region (); + area_to_invalidate.MakeEmpty (); + if (entered_tab_page != null) + area_to_invalidate.Union (entered_tab_page.TabBounds); + entered_tab_page = value; + if (entered_tab_page != null) + area_to_invalidate.Union (entered_tab_page.TabBounds); + Invalidate (area_to_invalidate); + area_to_invalidate.Dispose (); + } else + entered_tab_page = value; + + if (value == null) + CloseToolTip (); + else + SetToolTip (GetToolTipText (value)); + } + } + #endregion // Internal Properties + + #region Protected Instance Properties + protected override CreateParams CreateParams { + get { + CreateParams c = base.CreateParams; + return c; + } + } + + protected override Size DefaultSize { + get { return new Size (200, 100); } + } + + #endregion // Protected Instance Properties + + #region Public Instance Methods + public Rectangle GetTabRect (int index) + { + TabPage page = GetTab (index); + return page.TabBounds; + } + + public Widget GetControl (int index) + { + return GetTab (index); + } + + public void SelectTab (TabPage tabPage) + { + if (tabPage == null) + throw new ArgumentNullException ("tabPage"); + + SelectTab (this.tab_pages [tabPage]); + } + + public void SelectTab (string tabPageName) + { + if (tabPageName == null) + throw new ArgumentNullException ("tabPageName"); + + SelectTab (this.tab_pages [tabPageName]); + } + + public void SelectTab (int index) + { + if (index < 0 || index > this.tab_pages.Count - 1) + throw new ArgumentOutOfRangeException ("index"); + + SelectedIndex = index; + } + + public void DeselectTab (TabPage tabPage) + { + if (tabPage == null) + throw new ArgumentNullException ("tabPage"); + + DeselectTab (this.tab_pages [tabPage]); + } + + public void DeselectTab (string tabPageName) + { + if (tabPageName == null) + throw new ArgumentNullException ("tabPageName"); + + DeselectTab (this.tab_pages [tabPageName]); + } + + public void DeselectTab (int index) + { + if (index == SelectedIndex) { + if (index >= 0 && index < this.tab_pages.Count - 1) + SelectedIndex = ++index; + else + SelectedIndex = 0; + } + } + + + public override string ToString () + { + string res = String.Concat (base.ToString (), + ", TabPages.Count: ", + TabCount); + if (TabCount > 0) + res = String.Concat (res, ", TabPages[0]: ", + TabPages [0]); + return res; + } + + #endregion // Public Instance Methods + + #region Protected Instance Methods + + #region Handles + protected override Widget.WidgetCollection CreateWidgetsInstance () + { + return new TabWidget.WidgetCollection (this); + } + + protected override void CreateHandle () + { + base.CreateHandle (); + selected_index = (selected_index >= TabCount ? (TabCount > 0 ? 0 : -1) : selected_index); + + if (TabCount > 0) { + if (selected_index > -1) + this.SelectedTab.SetVisible(true); + else + tab_pages[0].SetVisible(true); + } + ResizeTabPages (); + } + + protected override void OnHandleCreated (EventArgs e) + { + base.OnHandleCreated (e); + } + + protected override void OnHandleDestroyed (EventArgs e) + { + base.OnHandleDestroyed (e); + } + + protected override void Dispose (bool disposing) + { + CloseToolTip (); + base.Dispose (disposing); + } + + #endregion + + #region Events + protected virtual void OnDrawItem (DrawItemEventArgs e) + { + if (DrawMode != TabDrawMode.OwnerDrawFixed) + return; + + DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]); + if (eh != null) + eh (this, e); + } + + internal void OnDrawItemInternal (DrawItemEventArgs e) + { + OnDrawItem (e); + } + + protected override void OnFontChanged (EventArgs e) + { + base.OnFontChanged (e); + ResizeTabPages (); + } + + protected override void OnResize (EventArgs e) + { + base.OnResize (e); + } + + protected override void OnStyleChanged (EventArgs e) + { + base.OnStyleChanged (e); + } + + protected virtual void OnSelectedIndexChanged (EventArgs e) + { + EventHandler eh = (EventHandler) (Events[SelectedIndexChangedEvent]); + if (eh != null) + eh (this, e); + } + + internal override void OnPaintInternal (PaintEventArgs pe) + { + if (GetStyle (Widgetstyles.UserPaint)) + return; + + Draw (pe.Graphics, pe.ClipRectangle); + pe.Handled = true; + } + + protected override void OnEnter (EventArgs e) + { + base.OnEnter (e); + if (SelectedTab != null) + SelectedTab.FireEnter (); + } + + protected override void OnLeave (EventArgs e) + { + if (SelectedTab != null) + SelectedTab.FireLeave (); + base.OnLeave (e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnRightToLeftLayoutChanged (EventArgs e) + { + EventHandler eh = (EventHandler) (Events[RightToLeftLayoutChangedEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + protected override void ScaleCore (float dx, float dy) + { + base.ScaleCore (dx, dy); + } + + protected virtual void OnDeselecting (TabControlCancelEventArgs e) + { + TabControlCancelEventHandler eh = (TabControlCancelEventHandler) (Events[DeselectingEvent]); + if (eh != null) + eh (this, e); + + if (!e.Cancel) + OnDeselected (new TabControlEventArgs (SelectedTab, selected_index, TabControlAction.Deselected)); + } + + protected virtual void OnDeselected (TabControlEventArgs e) + { + TabControlEventHandler eh = (TabControlEventHandler) (Events[DeselectedEvent]); + if (eh != null) + eh (this, e); + + if (this.SelectedTab != null) + this.SelectedTab.FireLeave (); + } + + protected virtual void OnSelecting (TabControlCancelEventArgs e) + { + TabControlCancelEventHandler eh = (TabControlCancelEventHandler) (Events[SelectingEvent]); + if (eh != null) + eh (this, e); + + if (!e.Cancel) + OnSelected (new TabControlEventArgs (SelectedTab, selected_index, TabControlAction.Selected)); + } + + protected virtual void OnSelected (TabControlEventArgs e) + { + TabControlEventHandler eh = (TabControlEventHandler) (Events[SelectedEvent]); + if (eh != null) + eh (this, e); + + if (this.SelectedTab != null) + this.SelectedTab.FireEnter (); + } + + #endregion + + #region Keys + protected override bool ProcessKeyPreview (ref Message m) + { + return base.ProcessKeyPreview (ref m); + } + + protected override void OnKeyDown (KeyEventArgs ke) + { + base.OnKeyDown (ke); + if (ke.Handled) + return; + + if (ke.KeyCode == Keys.Tab && (ke.KeyData & Keys.Widget) != 0) { + if ((ke.KeyData & Keys.Shift) == 0) + SelectedIndex = (SelectedIndex + 1) % TabCount; + else + SelectedIndex = (SelectedIndex + TabCount - 1) % TabCount; + ke.Handled = true; + } else if (ke.KeyCode == Keys.PageUp && (ke.KeyData & Keys.Widget) != 0) { + SelectedIndex = (SelectedIndex + TabCount - 1) % TabCount; + ke.Handled = true; + } else if (ke.KeyCode == Keys.PageDown && (ke.KeyData & Keys.Widget) != 0) { + SelectedIndex = (SelectedIndex + 1) % TabCount; + ke.Handled = true; + } else if (ke.KeyCode == Keys.Home) { + SelectedIndex = 0; + ke.Handled = true; + } else if (ke.KeyCode == Keys.End) { + SelectedIndex = TabCount - 1; + ke.Handled = true; + } else if (NavigateTabs (ke.KeyCode)) + ke.Handled = true; + } + + protected override bool IsInputKey (Keys keyData) + { + switch (keyData & Keys.KeyCode) { + case Keys.Home: + case Keys.End: + case Keys.Left: + case Keys.Right: + case Keys.Up: + case Keys.Down: + return true; + } + return base.IsInputKey (keyData); + } + + private bool NavigateTabs (Keys keycode) + { + bool move_left = false; + bool move_right = false; + + if (alignment == TabAlignment.Bottom || alignment == TabAlignment.Top) { + if (keycode == Keys.Left) + move_left = true; + else if (keycode == Keys.Right) + move_right = true; + } else { + if (keycode == Keys.Up) + move_left = true; + else if (keycode == Keys.Down) + move_right = true; + } + + if (move_left) { + if (SelectedIndex > 0) { + SelectedIndex--; + return true; + } + } + + if (move_right) { + if (SelectedIndex < TabCount - 1) { + SelectedIndex++; + return true; + } + } + + return false; + } + #endregion + + #region Pages Collection + protected void RemoveAll () + { + Widgets.Clear (); + } + + protected virtual object [] GetItems () + { + TabPage [] pages = new TabPage [Widgets.Count]; + Widgets.CopyTo (pages, 0); + return pages; + } + + protected virtual object [] GetItems (Type baseType) + { + object[] pages = (object[])Array.CreateInstance (baseType, Widgets.Count); + Widgets.CopyTo (pages, 0); + return pages; + } + #endregion + + protected void UpdateTabSelection (bool updateFocus) + { + ResizeTabPages (); + } + + protected string GetToolTipText (object item) + { + TabPage page = (TabPage) item; + return page.ToolTipText; + } + + protected override void WndProc (ref Message m) + { + switch ((Msg)m.Msg) { + case Msg.WM_SETFOCUS: + if (selected_index != -1) + Invalidate(GetTabRect(selected_index)); + base.WndProc (ref m); + break; + case Msg.WM_KILLFOCUS: + if (selected_index != -1) + Invalidate(GetTabRect(selected_index)); + base.WndProc (ref m); + break; + default: + base.WndProc (ref m); + break; + } + } + + #endregion // Protected Instance Methods + + #region Internal & Private Methods + private bool CanScrollRight { + get { + return (slider_pos < TabCount - 1); + } + } + + private bool CanScrollLeft { + get { return slider_pos > 0; } + } + + private void MouseDownHandler (object sender, MouseEventArgs e) + { + if ((e.Button & MouseButtons.Left) == 0) + return; + + if (ShowSlider) { + Rectangle right = RightScrollButtonArea; + Rectangle left = LeftScrollButtonArea; + if (right.Contains (e.X, e.Y)) { + right_slider_state = PushButtonState.Pressed; + if (CanScrollRight) { + slider_pos++; + SizeTabs (); + + // UIA Framework Event: Horizontally Scrolled + OnUIAHorizontallyScrolled (EventArgs.Empty); + + switch (this.Alignment) { + case TabAlignment.Top: + Invalidate (new Rectangle (0, 0, Width, ItemSize.Height)); + break; + case TabAlignment.Bottom: + Invalidate (new Rectangle (0, DisplayRectangle.Bottom, Width, Height - DisplayRectangle.Bottom)); + break; + case TabAlignment.Left: + Invalidate (new Rectangle (0, 0, DisplayRectangle.Left, Height)); + break; + case TabAlignment.Right: + Invalidate (new Rectangle (DisplayRectangle.Right, 0, Width - DisplayRectangle.Right, Height)); + break; + } + + } else { + Invalidate (right); + } + return; + } else if (left.Contains (e.X, e.Y)) { + left_slider_state = PushButtonState.Pressed; + if (CanScrollLeft) { + slider_pos--; + SizeTabs (); + + // UIA Framework Event: Horizontally Scrolled + OnUIAHorizontallyScrolled (EventArgs.Empty); + + switch (this.Alignment) { + case TabAlignment.Top: + Invalidate (new Rectangle (0, 0, Width, ItemSize.Height)); + break; + case TabAlignment.Bottom: + Invalidate (new Rectangle (0, DisplayRectangle.Bottom, Width, Height - DisplayRectangle.Bottom)); + break; + case TabAlignment.Left: + Invalidate (new Rectangle (0, 0, DisplayRectangle.Left, Height)); + break; + case TabAlignment.Right: + Invalidate (new Rectangle (DisplayRectangle.Right, 0, Width - DisplayRectangle.Right, Height)); + break; + } + } else { + Invalidate (left); + } + return; + } + } + + int count = Widgets.Count; + for (int i = SliderPos; i < count; i++) { + if (!GetTabRect (i).Contains (e.X, e.Y)) + continue; + SelectedIndex = i; + mouse_down_on_a_tab_page = true; + break; + } + } + + private void MouseUpHandler (object sender, MouseEventArgs e) + { + mouse_down_on_a_tab_page = false; + if (ShowSlider && (left_slider_state == PushButtonState.Pressed || right_slider_state == PushButtonState.Pressed)) { + Rectangle invalid; + if (left_slider_state == PushButtonState.Pressed) { + invalid = LeftScrollButtonArea; + left_slider_state = GetScrollButtonState (invalid, e.Location); + } else { + invalid = RightScrollButtonArea; + right_slider_state = GetScrollButtonState (invalid, e.Location); + } + Invalidate (invalid); + } + } + + bool HasHotElementStyles { + get { + return ThemeElements.CurrentTheme.TabWidgetPainter.HasHotElementStyles (this); + } + } + + Rectangle LeftScrollButtonArea { + get { + return ThemeElements.CurrentTheme.TabWidgetPainter.GetLeftScrollRect (this); + } + } + + Rectangle RightScrollButtonArea { + get { + return ThemeElements.CurrentTheme.TabWidgetPainter.GetRightScrollRect (this); + } + } + + static PushButtonState GetScrollButtonState (Rectangle scrollButtonArea, Point cursorLocation) + { + return scrollButtonArea.Contains (cursorLocation) ? PushButtonState.Hot : PushButtonState.Normal; + } + + private void SizeChangedHandler (object sender, EventArgs e) + { + Redraw (); + } + + internal int IndexForTabPage (TabPage page) + { + for (int i = 0; i < tab_pages.Count; i++) { + if (page == tab_pages [i]) + return i; + } + return -1; + } + + private void ResizeTabPages () + { + CalcTabRows (); + SizeTabs (); + Rectangle r = DisplayRectangle; + foreach (TabPage page in Widgets) { + page.Bounds = r; + } + } + + private int MinimumTabWidth { + get { + return ThemeEngine.Current.TabControlMinimumTabWidth; + } + } + + private Size TabSpacing { + get { + return ThemeEngine.Current.TabControlGetSpacing (this); + } + } + + private void CalcTabRows () + { + switch (Alignment) { + case TabAlignment.Right: + case TabAlignment.Left: + CalcTabRows (Height); + break; + default: + CalcTabRows (Width); + break; + } + } + + private void CalcTabRows (int row_width) + { + int xpos = 0; + int ypos = 0; + Size spacing = TabSpacing; + + if (TabPages.Count > 0) + row_count = 1; + show_slider = false; + + CalculateItemSize (); + + for (int i = 0; i < TabPages.Count; i++) { + TabPage page = TabPages [i]; + int aux = 0; + SizeTab (page, i, row_width, ref xpos, ref ypos, spacing, 0, ref aux, true); + } + + if (SelectedIndex != -1 && TabPages.Count > SelectedIndex && TabPages[SelectedIndex].Row != BottomRow) + DropRow (TabPages [SelectedIndex].Row); + } + + // ItemSize per-se is used mostly only to retrieve the Height, + // since the actual Width of the tabs is computed individually, + // except when SizeMode is TabSizeMode.Fixed, where Width is used as well. + private void CalculateItemSize () + { + if (item_size_manual) + return; + + SizeF size; + if (tab_pages.Count > 0) { + // .Net uses the first tab page if available. + size = TextRenderer.MeasureString (tab_pages [0].Text, Font); + + } else { + size = TextRenderer.MeasureString ("a", Font); + size.Width = 0; + } + + if (size_mode == TabSizeMode.Fixed) + size.Width = 96; + if (size.Width < MinimumTabWidth) + size.Width = MinimumTabWidth; + if (image_list != null && image_list.ImageSize.Height > size.Height) + size.Height = image_list.ImageSize.Height; + + item_size = size.ToSize (); + } + + private int BottomRow { + get { return 1; } + } + + private int Direction + { + get { + return 1; + } + } + + private void DropRow (int row) + { + if (Appearance != TabAppearance.Normal) + return; + + int bottom = BottomRow; + int direction = Direction; + + foreach (TabPage page in TabPages) { + if (page.Row == row) { + page.Row = bottom; + } else if (direction == 1 && page.Row < row) { + page.Row += direction; + } else if (direction == -1 && page.Row > row) { + page.Row += direction; + } + } + } + + private int CalcYPos () + { + if (Alignment == TabAlignment.Bottom || Alignment == TabAlignment.Left) + return ThemeEngine.Current.TabControlGetPanelRect (this).Bottom; + + if (Appearance == TabAppearance.Normal) + return this.ClientRectangle.Y + ThemeEngine.Current.TabWidgetselectedDelta.Y; + + return this.ClientRectangle.Y; + + } + + private int CalcXPos () + { + if (Alignment == TabAlignment.Right) + return ThemeEngine.Current.TabControlGetPanelRect (this).Right; + + if (Appearance == TabAppearance.Normal) + return this.ClientRectangle.X + ThemeEngine.Current.TabWidgetselectedDelta.X; + + return this.ClientRectangle.X; + } + + private void SizeTabs () + { + switch (Alignment) { + case TabAlignment.Right: + case TabAlignment.Left: + SizeTabs (Height, true); + break; + default: + SizeTabs (Width, false); + break; + } + } + + private void SizeTabs (int row_width, bool vertical) + { + int ypos = 0; + int xpos = 0; + int prev_row = 1; + Size spacing = TabSpacing; + int begin_prev = 0; + + if (TabPages.Count == 0) + return; + + prev_row = TabPages [0].Row; + + // Reset the slider position if the slider isn't needed + // anymore (ie window size was increased so all tabs are visible) + if (!show_slider) + slider_pos = 0; + else { + // set X = -1 for marking tabs that are not visible due to scrolling + for (int i = 0; i < slider_pos; i++) { + TabPage page = TabPages[i]; + Rectangle x = page.TabBounds; + x.X = -1; + page.TabBounds = x; + } + } + + for (int i = slider_pos; i < TabPages.Count; i++) { + TabPage page = TabPages[i]; + SizeTab (page, i, row_width, ref xpos, ref ypos, spacing, prev_row, ref begin_prev, false); + prev_row = page.Row; + } + + if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) { + FillRow (begin_prev, TabPages.Count - 1, + ((row_width - TabPages [TabPages.Count - 1].TabBounds.Right) / (TabPages.Count - begin_prev)), + spacing, vertical); + } + + if (SelectedIndex != -1) { + ExpandSelected (TabPages [SelectedIndex], 0, row_width - 1); + } + } + + private void SizeTab (TabPage page, int i, int row_width, ref int xpos, ref int ypos, + Size spacing, int prev_row, ref int begin_prev, bool widthOnly) + { + int width, height = 0; + + if (SizeMode == TabSizeMode.Fixed) { + width = item_size.Width; + } else { + width = MeasureStringWidth (DeviceContext, page.Text, Font); + width += (Padding.X * 2) + 2; + + if (ImageList != null && page.ImageIndex >= 0) { + width += ImageList.ImageSize.Width + ThemeEngine.Current.TabControlImagePadding.X; + + int image_size = ImageList.ImageSize.Height + ThemeEngine.Current.TabControlImagePadding.Y; + if (item_size.Height < image_size) + item_size.Height = image_size; + } + + if (width < MinimumTabWidth) + width = MinimumTabWidth; + } + + // Use ItemSize property to recover the padding info as well. + height = ItemSize.Height - ThemeEngine.Current.TabWidgetselectedDelta.Height; // full height only for selected tab + + if (i == SelectedIndex) + width += ThemeEngine.Current.TabWidgetselectedSpacing; + + if (widthOnly) { + page.TabBounds = new Rectangle (xpos, 0, width, 0); + page.Row = row_count; + if (xpos + width > row_width && multiline) { + xpos = 0; + row_count++; + } else if (xpos + width > row_width) { + show_slider = true; + } + if (i == selected_index && show_slider) { + for (int j = i-1; j >= 0; j--) { + if (TabPages [j].TabBounds.Left < xpos + width - row_width) { + slider_pos = j+1; + break; + } + } + } + } else { + if (page.Row != prev_row) { + xpos = 0; + } + + switch (Alignment) { + case TabAlignment.Top: + case TabAlignment.Bottom: + page.TabBounds = new Rectangle ( + xpos + CalcXPos (), + ypos + (height + spacing.Height) * (row_count - page.Row) + CalcYPos (), + width, + height); + break; + case TabAlignment.Left: + if (Appearance == TabAppearance.Normal) { + // tab rows are positioned right to left + page.TabBounds = new Rectangle ( + ypos + (height + spacing.Height) * (row_count - page.Row) + CalcXPos (), + xpos, + height, + width); + } else { + // tab rows are positioned left to right + page.TabBounds = new Rectangle ( + ypos + (height + spacing.Height) * (page.Row - 1) + CalcXPos (), + xpos, + height, + width); + } + + break; + case TabAlignment.Right: + if (Appearance == TabAppearance.Normal) { + // tab rows are positioned left to right + page.TabBounds = new Rectangle ( + ypos + (height + spacing.Height) * (page.Row - 1) + CalcXPos (), + xpos, + height, + width); + } else { + // tab rows are positioned right to left + page.TabBounds = new Rectangle ( + ypos + (height + spacing.Height) * (row_count - page.Row) + CalcXPos (), + xpos, + height, + width); + } + + break; + } + + if (page.Row != prev_row) { + if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) { + bool vertical = alignment == TabAlignment.Right || alignment == TabAlignment.Left; + int offset = vertical ? TabPages [i - 1].TabBounds.Bottom : TabPages [i - 1].TabBounds.Right; + FillRow (begin_prev, i - 1, ((row_width - offset) / (i - begin_prev)), spacing, + vertical); + } + begin_prev = i; + } + } + + xpos += width + spacing.Width + ThemeEngine.Current.TabControlColSpacing; + } + + private void FillRow (int start, int end, int amount, Size spacing, bool vertical) + { + if (vertical) + FillRowV (start, end, amount, spacing); + else + FillRow (start, end, amount, spacing); + } + + private void FillRow (int start, int end, int amount, Size spacing) + { + int xpos = TabPages [start].TabBounds.Left; + for (int i = start; i <= end; i++) { + TabPage page = TabPages [i]; + int left = xpos; + int width = (i == end ? Width - left - 3 : page.TabBounds.Width + amount); + + page.TabBounds = new Rectangle (left, page.TabBounds.Top, + width, page.TabBounds.Height); + xpos = page.TabBounds.Right + 1 + spacing.Width; + } + } + + private void FillRowV (int start, int end, int amount, Size spacing) + { + int ypos = TabPages [start].TabBounds.Top; + for (int i = start; i <= end; i++) { + TabPage page = TabPages [i]; + int top = ypos; + int height = (i == end ? Height - top - 5 : page.TabBounds.Height + amount); + + page.TabBounds = new Rectangle (page.TabBounds.Left, top, + page.TabBounds.Width, height); + ypos = page.TabBounds.Bottom + 1; + } + } + + private void ExpandSelected (TabPage page, int left_edge, int right_edge) + { + if (Appearance != TabAppearance.Normal) + return; + + Rectangle r = page.TabBounds; + r.Y -= ThemeEngine.Current.TabWidgetselectedDelta.Y; + r.X -= ThemeEngine.Current.TabWidgetselectedDelta.X; + + r.Width += ThemeEngine.Current.TabWidgetselectedDelta.Width; + r.Height += ThemeEngine.Current.TabWidgetselectedDelta.Height; + if (r.Left < left_edge) + r.X = left_edge; + // Adjustment can't be used for right alignment, since it is + // the only one that has a different X origin than 0 + if (r.Right > right_edge && SizeMode != TabSizeMode.Normal && + alignment != TabAlignment.Right) + r.Width = right_edge - r.X; + page.TabBounds = r; + } + + private void Draw (Graphics dc, Rectangle clip) + { + ThemeEngine.Current.DrawTabControl (dc, clip, this); + } + + private TabPage GetTab (int index) + { + return Widgets [index] as TabPage; + } + + private void SetTab (int index, TabPage value) + { + if (!tab_pages.Contains (value)) { + this.Widgets.Add (value); + } + this.Widgets.RemoveAt (index); + this.Widgets.SetChildIndex (value, index); + Redraw (); + } + private void InsertTab (int index, TabPage value) + { + if (!tab_pages.Contains (value)) { + this.Widgets.Add (value); + } + this.Widgets.SetChildIndex (value, index); + Redraw (); + } + internal void Redraw () + { + if (!IsHandleCreated) + return; + + ResizeTabPages (); + Refresh (); + } + + private int MeasureStringWidth (Graphics graphics, string text, Font font) + { + if (text == String.Empty) + return 0; + StringFormat format = new StringFormat(); + RectangleF rect = new RectangleF(0, 0, 1000, 1000); + CharacterRange[] ranges = { new CharacterRange(0, text.Length) }; + Region[] regions = new Region[1]; + + format.SetMeasurableCharacterRanges(ranges); + format.FormatFlags = StringFormatFlags.NoClip; + format.FormatFlags |= StringFormatFlags.NoWrap; + regions = graphics.MeasureCharacterRanges(text + "I", font, rect, format); + rect = regions[0].GetBounds(graphics); + + return (int)(rect.Width); + } + + void SetToolTip (string text) + { + if (!show_tool_tips) + return; + + if (text == null || text.Length == 0) { + CloseToolTip (); + return; + } + + if (tooltip == null) { + tooltip = new ToolTip (); + tooltip_timer = new Timer (); + tooltip_timer.Tick += new EventHandler (ToolTipTimerTick); + } + + CloseToolTip (); + + tooltip_state = ToolTip.TipState.Initial; + tooltip_timer.Interval = 500; + tooltip_timer.Start (); + } + + void CloseToolTip () + { + if (tooltip == null) + return; + + tooltip.Hide (this); + tooltip_timer.Stop (); + tooltip_state = ToolTip.TipState.Down; + } + + void ToolTipTimerTick (object o, EventArgs args) + { + switch (tooltip_state) { + case ToolTip.TipState.Initial: + tooltip_timer.Stop (); + tooltip_timer.Interval = 5000; + tooltip_timer.Start (); + tooltip_state = ToolTip.TipState.Show; + tooltip.Present (this, GetToolTipText (EnteredTabPage)); + break; + case ToolTip.TipState.Show: + CloseToolTip (); + break; + } + } + + void OnMouseMove (object sender, MouseEventArgs e) + { + if (!mouse_down_on_a_tab_page && ShowSlider) { + if (LeftSliderState == PushButtonState.Pressed || + RightSliderState == PushButtonState.Pressed) + return; + if (LeftScrollButtonArea.Contains (e.Location)) { + LeftSliderState = PushButtonState.Hot; + RightSliderState = PushButtonState.Normal; + EnteredTabPage = null; + return; + } + if (RightScrollButtonArea.Contains (e.Location)) { + RightSliderState = PushButtonState.Hot; + LeftSliderState = PushButtonState.Normal; + EnteredTabPage = null; + return; + } + LeftSliderState = PushButtonState.Normal; + RightSliderState = PushButtonState.Normal; + } + if (EnteredTabPage != null && EnteredTabPage.TabBounds.Contains (e.Location)) + return; + for (int index = 0; index < TabCount; index++) { + TabPage tab_page = TabPages[index]; + if (tab_page.TabBounds.Contains (e.Location)) { + EnteredTabPage = tab_page; + return; + } + } + EnteredTabPage = null; + } + + void OnMouseLeave (object sender, EventArgs e) + { + if (ShowSlider) { + LeftSliderState = PushButtonState.Normal; + RightSliderState = PushButtonState.Normal; + } + EnteredTabPage = null; + } + #endregion // Internal & Private Methods + + #region Events + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler BackColorChanged { + add { base.BackColorChanged += value; } + remove { base.BackColorChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageChanged { + add { base.BackgroundImageChanged += value; } + remove { base.BackgroundImageChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageLayoutChanged + { + add { base.BackgroundImageLayoutChanged += value; } + remove { base.BackgroundImageLayoutChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler ForeColorChanged { + add { base.ForeColorChanged += value; } + remove { base.ForeColorChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event PaintEventHandler Paint { + add { base.Paint += value; } + remove { base.Paint -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + + static object DrawItemEvent = new object (); + static object SelectedIndexChangedEvent = new object (); + + public event DrawItemEventHandler DrawItem { + add { Events.AddHandler (DrawItemEvent, value); } + remove { Events.RemoveHandler (DrawItemEvent, value); } + } + + public event EventHandler SelectedIndexChanged { + add { Events.AddHandler (SelectedIndexChangedEvent, value); } + remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); } + } + + static object SelectedEvent = new object (); + + public event TabControlEventHandler Selected { + add { Events.AddHandler (SelectedEvent, value); } + remove { Events.RemoveHandler (SelectedEvent, value); } + } + + static object DeselectedEvent = new object (); + + public event TabControlEventHandler Deselected + { + add { Events.AddHandler (DeselectedEvent, value); } + remove { Events.RemoveHandler (DeselectedEvent, value); } + } + + static object SelectingEvent = new object (); + + public event TabControlCancelEventHandler Selecting + { + add { Events.AddHandler (SelectingEvent, value); } + remove { Events.RemoveHandler (SelectingEvent, value); } + } + + static object DeselectingEvent = new object (); + + public event TabControlCancelEventHandler Deselecting + { + add { Events.AddHandler (DeselectingEvent, value); } + remove { Events.RemoveHandler (DeselectingEvent, value); } + } + + static object RightToLeftLayoutChangedEvent = new object (); + public event EventHandler RightToLeftLayoutChanged + { + add { Events.AddHandler (RightToLeftLayoutChangedEvent, value); } + remove { Events.RemoveHandler (RightToLeftLayoutChangedEvent, value); } + } + #endregion // Events + + + #region Class TaControl.ControlCollection + [ComVisible (false)] + public new class ControlCollection : Widget.WidgetCollection { + + private TabWidget owner; + + public ControlCollection (TabWidget owner) : base (owner) + { + this.owner = owner; + } + + public override void Add (Widget value) + { + TabPage page = value as TabPage; + if (page == null) + throw new ArgumentException ("Cannot add " + + value.GetType ().Name + " to TabControl. " + + "Only TabPages can be directly added to TabWidgets."); + + page.SetVisible (false); + base.Add (value); + if (owner.TabCount == 1 && owner.selected_index < 0) + owner.SelectedIndex = 0; + owner.Redraw (); + } + + public override void Remove (Widget value) + { + bool change_index = false; + + TabPage page = value as TabPage; + if (page != null && owner.Widgets.Contains (page)) { + int index = owner.IndexForTabPage (page); + if (index < owner.SelectedIndex || owner.SelectedIndex == Count - 1) + change_index = true; + } + + base.Remove (value); + + // We don't want to raise SelectedIndexChanged until after we + // have removed from the collection, so TabCount will be + // correct for the user. + if (change_index && Count > 0) { + // Clear the selected index internally, to avoid trying to access the previous + // selected tab when setting the new one - this is what .net seems to do + int prev_selected_index = owner.SelectedIndex; + owner.selected_index = -1; + + owner.SelectedIndex = --prev_selected_index; + owner.Invalidate (); + } else if (change_index) { + owner.selected_index = -1; + owner.OnSelectedIndexChanged (EventArgs.Empty); + owner.Invalidate (); + } else + owner.Redraw (); + } + } + #endregion // Class TabControl.ControlCollection + + #region Class TabPage.TabPageCollection + public class TabPageCollection : IList, ICollection, IEnumerable { + + private TabWidget owner; + + public TabPageCollection (TabWidget owner) + { + if (owner == null) + throw new ArgumentNullException ("Value cannot be null."); + this.owner = owner; + } + + [Browsable(false)] + public int Count { + get { return owner.Widgets.Count; } + } + + public bool IsReadOnly { + get { return false; } + } + + public virtual TabPage this [int index] { + get { + return owner.GetTab (index); + } + set { + owner.SetTab (index, value); + } + } + public virtual TabPage this [string key] { + get { + if (string.IsNullOrEmpty (key)) + return null; + + int index = this.IndexOfKey (key); + if (index < 0 || index >= this.Count) + return null; + + return this[index]; + } + } + + internal int this[TabPage tabPage] { + get { + if (tabPage == null) + return -1; + + for (int i = 0; i < this.Count; i++) + if (this[i].Equals (tabPage)) + return i; + + return -1; + } + } + + bool ICollection.IsSynchronized { + get { return false; } + } + + object ICollection.SyncRoot { + get { return this; } + } + + bool IList.IsFixedSize { + get { return false; } + } + + object IList.this [int index] { + get { + return owner.GetTab (index); + } + set { + owner.SetTab (index, (TabPage) value); + } + } + + public void Add (TabPage value) + { + if (value == null) + throw new ArgumentNullException ("Value cannot be null."); + owner.Widgets.Add (value); + } + + public void Add (string text) + { + TabPage page = new TabPage (text); + this.Add (page); + } + + public void Add (string key, string text) + { + TabPage page = new TabPage (text); + page.Name = key; + this.Add (page); + } + + public void Add (string key, string text, int imageIndex) + { + TabPage page = new TabPage (text); + page.Name = key; + page.ImageIndex = imageIndex; + this.Add (page); + } + + // .Net sets the ImageKey, but does not show the image when this is used + public void Add (string key, string text, string imageKey) + { + TabPage page = new TabPage (text); + page.Name = key; + page.ImageKey = imageKey; + this.Add (page); + } + + public void AddRange (TabPage [] pages) + { + if (pages == null) + throw new ArgumentNullException ("Value cannot be null."); + owner.Widgets.AddRange (pages); + } + + public virtual void Clear () + { + owner.Widgets.Clear (); + owner.Invalidate (); + } + + public bool Contains (TabPage page) + { + if (page == null) + throw new ArgumentNullException ("Value cannot be null."); + return owner.Widgets.Contains (page); + } + + public virtual bool ContainsKey (string key) + { + int index = this.IndexOfKey (key); + return (index >= 0 && index < this.Count); + } + + public IEnumerator GetEnumerator () + { + return owner.Widgets.GetEnumerator (); + } + + public int IndexOf (TabPage page) + { + return owner.Widgets.IndexOf (page); + } + + public virtual int IndexOfKey(string key) + { + if (string.IsNullOrEmpty (key)) + return -1; + + for (int i = 0; i < this.Count; i++) { + if (string.Compare (this[i].Name, key, true, + System.Globalization.CultureInfo.InvariantCulture) == 0) { + return i; + } + } + + return -1; + } + + public void Remove (TabPage value) + { + owner.Widgets.Remove (value); + owner.Invalidate (); + } + + public void RemoveAt (int index) + { + owner.Widgets.RemoveAt (index); + owner.Invalidate (); + } + + public virtual void RemoveByKey (string key) + { + int index = this.IndexOfKey (key); + if (index >= 0 && index < this.Count) + this.RemoveAt (index); + } + + void ICollection.CopyTo (Array dest, int index) + { + owner.Widgets.CopyTo (dest, index); + } + + int IList.Add (object value) + { + TabPage page = value as TabPage; + if (value == null) + throw new ArgumentException ("value"); + owner.Widgets.Add (page); + return owner.Widgets.IndexOf (page); + } + + bool IList.Contains (object page) + { + TabPage tabPage = page as TabPage; + if (tabPage == null) + return false; + return Contains (tabPage); + } + + int IList.IndexOf (object page) + { + TabPage tabPage = page as TabPage; + if (tabPage == null) + return -1; + return IndexOf (tabPage); + } + + void IList.Insert (int index, object tabPage) + { + throw new NotSupportedException (); + } + + public void Insert (int index, string text) + { + owner.InsertTab (index, new TabPage (text)); + } + + public void Insert (int index, TabPage tabPage) + { + owner.InsertTab (index, tabPage); + } + + public void Insert (int index, string key, string text) + { + TabPage page = new TabPage(text); + page.Name = key; + owner.InsertTab (index, page); + } + + public void Insert (int index, string key, string text, int imageIndex) + { + TabPage page = new TabPage(text); + page.Name = key; + owner.InsertTab (index, page); + page.ImageIndex = imageIndex; + } + + public void Insert (int index, string key, string text, string imageKey) + { + TabPage page = new TabPage(text); + page.Name = key; + owner.InsertTab (index, page); + page.ImageKey = imageKey; + } + void IList.Remove (object value) + { + TabPage page = value as TabPage; + if (page == null) + return; + Remove ((TabPage) value); + } + } + #endregion // Class TabPage.TabPageCollection + } +} + + diff --git a/source/ShiftUI/Widgets/TabPage.cs b/source/ShiftUI/Widgets/TabPage.cs new file mode 100644 index 0000000..7ae0165 --- /dev/null +++ b/source/ShiftUI/Widgets/TabPage.cs @@ -0,0 +1,399 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) + + +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace ShiftUI { + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [DefaultEvent("Click")] + [DesignTimeVisible(false)] + [DefaultProperty("Text")] + //[Designer("ShiftUI.Design.TabPageDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [ToolboxItem(false)] + public class TabPage : Panel { + #region Fields + private int imageIndex = -1; + private string imageKey; + private string tooltip_text = String.Empty; + private Rectangle tab_bounds; + private int row; + private bool use_visual_style_back_color; + #endregion // Fields + + #region Public Constructors + public TabPage () + { + Visible = true; + + SetStyle (Widgetstyles.CacheText, true); + } + + public TabPage (string text) : base () + { + base.Text = text; + } + + #endregion // Public Constructors + + #region .NET 2.0 Public Instance Properties + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override bool AutoSize { + get { return base.AutoSize; } + set { base.AutoSize = value; } + } + + [Browsable (false)] + [Localizable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public override AutoSizeMode AutoSizeMode { + get { return base.AutoSizeMode; } + set { base.AutoSizeMode = value; } + } + + [Browsable (false)] + [DefaultValue ("{Width=0, Height=0}")] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override Size MaximumSize { + get { return base.MaximumSize; } + set { base.MaximumSize = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override Size MinimumSize { + get { return base.MinimumSize; } + set { base.MinimumSize = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new Size PreferredSize { + get { return base.PreferredSize; } + } + + [DefaultValue (false)] + public bool UseVisualStyleBackColor { + get { return use_visual_style_back_color; } + set { use_visual_style_back_color = value; } + } + + public override Color BackColor { + get { return base.BackColor; } + set { use_visual_style_back_color = false; base.BackColor = value; } + } + #endregion + + #region Public Instance Properties + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override AnchorStyles Anchor { + get { return base.Anchor; } + set { base.Anchor = value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override DockStyle Dock { + get { return base.Dock; } + set { base.Dock = value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new bool Enabled { + get { return base.Enabled; } + set { base.Enabled = value; } + } + + [RefreshProperties (RefreshProperties.Repaint)] + [DefaultValue(-1)] + //[Editor("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))] + [Localizable(true)] + [TypeConverter(typeof(ImageIndexConverter))] + public int ImageIndex { + get { return imageIndex; } + set { + if (imageIndex == value) + return; + imageIndex = value; + UpdateOwner (); + } + } + + [Localizable (true)] + [RefreshProperties (RefreshProperties.Repaint)] + [DefaultValue ("")] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, + //"System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)] + [TypeConverter (typeof (ImageKeyConverter))] + public string ImageKey + { + get { return imageKey; } + set { + imageKey = value; + TabWidget control = this.Parent as TabWidget; + if (control != null) { + ImageIndex = control.ImageList.Images.IndexOfKey (imageKey); + } + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new int TabIndex { + get { return base.TabIndex; } + set { base.TabIndex = value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new bool TabStop { + get { return base.TabStop; } + set { base.TabStop = value; } + } + + //[EditorBrowsable (EditorBrowsableState.Always)] + [Browsable(true)] + [Localizable(true)] + public override string Text { + get { return base.Text; } + set { + if (value == base.Text) + return; + base.Text = value; + UpdateOwner (); + } + } + + [Localizable(true)] + [DefaultValue("")] + public string ToolTipText { + get { return tooltip_text; } + set { + if (value == null) + value = String.Empty; + tooltip_text = value; + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new bool Visible { + get { return base.Visible; } + set { /* according to MS docs we can ignore this */ } + } + + #endregion // Public Instance Properties + + #region Public Static Methods + public static TabPage GetTabPageOfComponent (object comp) + { + Widget control = comp as Widget; + if (control == null) + return null; + control = control.Parent; + while (control != null) { + if (control is TabPage) + break; + control = control.Parent; + } + return control as TabPage; + } + + #endregion // Public Static Methods + + #region Public Instance Methods + public override string ToString () + { + return "TabPage: {" + Text + "}"; + } + + #endregion // Public Instance Methods + + #region Internal & Private Methods and Properties + internal Rectangle TabBounds { + get { return tab_bounds; } + set { tab_bounds = value; } + } + + internal int Row { + get { return row; } + set { row = value; } + } + + private void UpdateOwner () + { + if (Owner != null) { + Owner.Redraw (); + } + } + + private TabWidget Owner { + get { return base.Parent as TabWidget; } + } + + internal void SetVisible (bool value) + { + base.Visible = value; + } + + #endregion // Internal & Private Methods and Properties + + #region Protected Instance Methods + protected override WidgetCollection CreateWidgetsInstance () + { + return new TabPageControlCollection (this); + } + + protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified) + { + if (Owner != null && Owner.IsHandleCreated) { + Rectangle display = Owner.DisplayRectangle; + + base.SetBoundsCore (display.X, display.Y, + display.Width, display.Height, + BoundsSpecified.All); + } else { + base.SetBoundsCore (x, y, width, height, specified); + } + } + + protected override void OnEnter (EventArgs e) + { + base.OnEnter (e); + } + + protected override void OnLeave (EventArgs e) + { + base.OnLeave (e); + } + + protected override void OnPaintBackground (PaintEventArgs e) + { + base.OnPaintBackground (e); + } + #endregion // Protected Instance Methods + + #region Events + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler AutoSizeChanged { + add { base.AutoSizeChanged += value; } + remove { base.AutoSizeChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler DockChanged { + add { base.DockChanged += value; } + remove { base.DockChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler EnabledChanged { + add { base.EnabledChanged += value; } + remove { base.EnabledChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler LocationChanged { + add { base.LocationChanged += value; } + remove { base.LocationChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler TabIndexChanged { + add { base.TabIndexChanged += value; } + remove { base.TabIndexChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler TabStopChanged { + add { base.TabStopChanged += value; } + remove { base.TabStopChanged -= value; } + } + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler VisibleChanged { + add { base.VisibleChanged += value; } + remove { base.VisibleChanged -= value; } + } + + #endregion // Events + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new Point Location { + get { + return base.Location; + } + + set { + base.Location = value; + } + } + + #region Class TabPageControlCollection + [ComVisible (false)] + public class TabPageControlCollection : WidgetCollection { + + //private TabPage owner; + + public TabPageControlCollection (TabPage owner) : base (owner) + { + //this.owner = owner; + } + + public override void Add (Widget value) + { + base.Add (value); + } + } + #endregion // Class TabPageControlCollection + + } + + +} diff --git a/source/ShiftUI/Widgets/TableLayoutPanel.cs b/source/ShiftUI/Widgets/TableLayoutPanel.cs new file mode 100644 index 0000000..e327795 --- /dev/null +++ b/source/ShiftUI/Widgets/TableLayoutPanel.cs @@ -0,0 +1,788 @@ +// +// TableLayoutPanel.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst (monkey@jpobst.com) +// + +using System; +using System.Drawing; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.InteropServices; +using ShiftUI.Layout; +using System.ComponentModel.Design.Serialization; + +namespace ShiftUI +{ + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ProvideProperty ("CellPosition", typeof (Widget))] + [ProvideProperty ("Column", typeof (Widget))] + [ProvideProperty ("ColumnSpan", typeof (Widget))] + [ProvideProperty ("Row", typeof (Widget))] + [ProvideProperty ("RowSpan", typeof (Widget))] + [DefaultProperty ("ColumnCount")] + [Docking (DockingBehavior.Never)] + //[Designer ("ShiftUI.Design.TableLayoutPanelDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + //[DesignerSerializer ("ShiftUI.Design.TableLayoutPanelCodeDomSerializer, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)] + [ToolboxWidget] + public class TableLayoutPanel : Panel, IExtenderProvider + { + private TableLayoutSettings settings; + private static TableLayout layout_engine = new TableLayout (); + private TableLayoutPanelCellBorderStyle cell_border_style; + + // This is the row/column the Widget actually got placed + internal Widget[,] actual_positions; + + // Widths and heights of each column/row + internal int[] column_widths; + internal int[] row_heights; + + #region Public Constructor + public TableLayoutPanel () + { + settings = new TableLayoutSettings(this); + cell_border_style = TableLayoutPanelCellBorderStyle.None; + column_widths = new int[0]; + row_heights = new int[0]; + CreateDockPadding (); + } + #endregion + + #region Public Properties + [Localizable (true)] + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + new public BorderStyle BorderStyle { + get { return base.BorderStyle; } + set { base.BorderStyle = value; } + } + + [Localizable (true)] + [DefaultValue (TableLayoutPanelCellBorderStyle.None)] + public TableLayoutPanelCellBorderStyle CellBorderStyle { + get { return this.cell_border_style; } + set { + if (this.cell_border_style != value) { + this.cell_border_style = value; + this.PerformLayout (this, "CellBorderStyle"); + this.Invalidate (); + } + } + } + + [Localizable (true)] + [DefaultValue (0)] + public int ColumnCount { + get { return settings.ColumnCount; } + set { settings.ColumnCount = value; } + } + + [Browsable (false)] + [DisplayName ("Columns")] + [MergableProperty (false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public TableLayoutColumnStyleCollection ColumnStyles { + get { return settings.ColumnStyles; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + new public TableLayoutControlCollection Widgets { + get { return (TableLayoutControlCollection) base.Widgets; } + } + + [DefaultValue (TableLayoutPanelGrowStyle.AddRows)] + public TableLayoutPanelGrowStyle GrowStyle { + get { return settings.GrowStyle; } + set { settings.GrowStyle = value; } + } + + public override ShiftUI.Layout.LayoutEngine LayoutEngine { + get { return TableLayoutPanel.layout_engine; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public TableLayoutSettings LayoutSettings { + get { return this.settings; } + set { + if (value.isSerialized) { + // Serialized version doesn't calculate these. + value.ColumnCount = value.ColumnStyles.Count; + value.RowCount = value.RowStyles.Count; + value.panel = this; + + this.settings = value; + } else + throw new NotSupportedException ("LayoutSettings value cannot be set directly."); + } + } + + [Localizable (true)] + [DefaultValue (0)] + public int RowCount { + get { return settings.RowCount; } + set { settings.RowCount = value; } + } + + [Browsable (false)] + [DisplayName ("Rows")] + [MergableProperty (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + public TableLayoutRowStyleCollection RowStyles { + get { return settings.RowStyles; } + } + #endregion + + #region Public Methods + [DefaultValue (-1)] + [DisplayName ("Cell")] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public TableLayoutPanelCellPosition GetCellPosition (Widget control) + { + return settings.GetCellPosition (control); + } + + [DisplayName ("Column")] + [DefaultValue (-1)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public int GetColumn (Widget control) + { + return settings.GetColumn (control); + } + + [DisplayName ("ColumnSpan")] + [DefaultValue (1)] + public int GetColumnSpan (Widget control) + { + return settings.GetColumnSpan (control); + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public int[] GetColumnWidths () + { + return this.column_widths; + } + + public Widget GetControlFromPosition (int column, int row) + { + if (column < 0 || row < 0) + throw new ArgumentException (); + + TableLayoutPanelCellPosition pos = new TableLayoutPanelCellPosition (column, row); + + foreach (Widget c in this.Widgets) + if (settings.GetCellPosition (c) == pos) + return c; + + return null; + } + + public TableLayoutPanelCellPosition GetPositionFromControl (Widget control) + { + for (int x = 0; x < this.actual_positions.GetLength (0); x++) + for (int y = 0; y < this.actual_positions.GetLength (1); y++) + if (this.actual_positions[x, y] == control) + return new TableLayoutPanelCellPosition (x, y); + + return new TableLayoutPanelCellPosition (-1, -1); + } + + [DisplayName ("Row")] + [DefaultValue ("-1")] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public int GetRow (Widget control) + { + return settings.GetRow (control); + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public int[] GetRowHeights () + { + return this.row_heights; + } + + [DisplayName ("RowSpan")] + [DefaultValue (1)] + public int GetRowSpan (Widget control) + { + return settings.GetRowSpan (control); + } + + public void SetCellPosition (Widget control, TableLayoutPanelCellPosition position) + { + settings.SetCellPosition (control, position); + } + + public void SetColumn (Widget control, int column) + { + settings.SetColumn (control, column); + } + + public void SetColumnSpan (Widget control, int value) + { + settings.SetColumnSpan (control, value); + } + + public void SetRow (Widget control, int row) + { + settings.SetRow (control, row); + } + + public void SetRowSpan (Widget control, int value) + { + settings.SetRowSpan (control, value); + } + #endregion + + #region Protected Methods + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override WidgetCollection CreateWidgetsInstance () + { + return new TableLayoutControlCollection (this); + } + + protected virtual void OnCellPaint (TableLayoutCellPaintEventArgs e) + { + TableLayoutCellPaintEventHandler eh = (TableLayoutCellPaintEventHandler)(Events [CellPaintEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void OnLayout (LayoutEventArgs levent) + { + base.OnLayout (levent); + Invalidate (); + } + + protected override void OnPaintBackground (PaintEventArgs e) + { + base.OnPaintBackground (e); + + DrawCellBorders (e); + + int border_width = GetCellBorderWidth (CellBorderStyle); + + int x = border_width; + int y = border_width; + + for (int i = 0; i < column_widths.Length; i++) { + for (int j = 0; j < row_heights.Length; j++) { + this.OnCellPaint (new TableLayoutCellPaintEventArgs (e.Graphics, e.ClipRectangle, new Rectangle (x, y, column_widths[i] + border_width, row_heights[j] + border_width), i, j)); + y += row_heights[j] + border_width; + } + + x += column_widths[i] + border_width; + y = border_width; + } + } + + protected override void ScaleWidget (SizeF factor, BoundsSpecified specified) + { + base.ScaleWidget (factor, specified); + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + protected override void ScaleCore (float dx, float dy) + { + base.ScaleCore (dx, dy); + } + #endregion + + #region Internal Methods + internal static int GetCellBorderWidth (TableLayoutPanelCellBorderStyle style) + { + switch (style) { + case TableLayoutPanelCellBorderStyle.Single: + return 1; + case TableLayoutPanelCellBorderStyle.Inset: + case TableLayoutPanelCellBorderStyle.Outset: + return 2; + case TableLayoutPanelCellBorderStyle.InsetDouble: + case TableLayoutPanelCellBorderStyle.OutsetPartial: + case TableLayoutPanelCellBorderStyle.OutsetDouble: + return 3; + } + + return 0; + } + + private void DrawCellBorders (PaintEventArgs e) + { + Rectangle paint_here = new Rectangle (Point.Empty, this.Size); + + switch (CellBorderStyle) { + case TableLayoutPanelCellBorderStyle.Single: + DrawSingleBorder (e.Graphics, paint_here); + break; + case TableLayoutPanelCellBorderStyle.Inset: + DrawInsetBorder (e.Graphics, paint_here); + break; + case TableLayoutPanelCellBorderStyle.InsetDouble: + DrawInsetDoubleBorder (e.Graphics, paint_here); + break; + case TableLayoutPanelCellBorderStyle.Outset: + DrawOutsetBorder (e.Graphics, paint_here); + break; + case TableLayoutPanelCellBorderStyle.OutsetDouble: + case TableLayoutPanelCellBorderStyle.OutsetPartial: + DrawOutsetDoubleBorder (e.Graphics, paint_here); + break; + } + } + + private void DrawSingleBorder (Graphics g, Rectangle rect) + { + WidgetPaint.DrawBorder (g, rect, SystemColors.ControlDark, ButtonBorderStyle.Solid); + + int x = DisplayRectangle.X; + int y = DisplayRectangle.Y; + + for (int i = 0; i < column_widths.Length - 1; i++) { + x += column_widths[i] + 1; + + g.DrawLine (SystemPens.ControlDark, new Point (x, 1), new Point (x, Bottom - 2)); + } + + for (int j = 0; j < row_heights.Length - 1; j++) { + y += row_heights[j] + 1; + + g.DrawLine (SystemPens.ControlDark, new Point (1, y), new Point (Right - 2, y)); + } + } + + private void DrawInsetBorder (Graphics g, Rectangle rect) + { + WidgetPaint.DrawBorder3D (g, rect, Border3DStyle.Etched); + + int x = DisplayRectangle.X; + int y = DisplayRectangle.Y; + + for (int i = 0; i < column_widths.Length - 1; i++) { + x += column_widths[i] + 2; + + g.DrawLine (SystemPens.ControlDark, new Point (x, 1), new Point (x, Bottom - 3)); + g.DrawLine (Pens.White, new Point (x + 1, 1), new Point (x + 1, Bottom - 3)); + } + + for (int j = 0; j < row_heights.Length - 1; j++) { + y += row_heights[j] + 2; + + g.DrawLine (SystemPens.ControlDark, new Point (1, y), new Point (Right - 3, y)); + g.DrawLine (Pens.White, new Point (1, y + 1), new Point (Right - 3, y + 1)); + } + } + + private void DrawOutsetBorder (Graphics g, Rectangle rect) + { + g.DrawRectangle (SystemPens.ControlDark, new Rectangle (rect.Left + 1, rect.Top + 1, rect.Width - 2, rect.Height - 2)); + g.DrawRectangle (Pens.White, new Rectangle (rect.Left, rect.Top, rect.Width - 2, rect.Height - 2)); + + int x = DisplayRectangle.X; + int y = DisplayRectangle.Y; + + for (int i = 0; i < column_widths.Length - 1; i++) { + x += column_widths[i] + 2; + + g.DrawLine (Pens.White, new Point (x, 1), new Point (x, Bottom - 3)); + g.DrawLine (SystemPens.ControlDark, new Point (x + 1, 1), new Point (x + 1, Bottom - 3)); + } + + for (int j = 0; j < row_heights.Length - 1; j++) { + y += row_heights[j] + 2; + + g.DrawLine (Pens.White, new Point (1, y), new Point (Right - 3, y)); + g.DrawLine (SystemPens.ControlDark, new Point (1, y + 1), new Point (Right - 3, y + 1)); + } + } + + private void DrawOutsetDoubleBorder (Graphics g, Rectangle rect) + { + rect.Width -= 1; + rect.Height -= 1; + + g.DrawRectangle (SystemPens.ControlDark, new Rectangle (rect.Left + 2, rect.Top + 2, rect.Width - 2, rect.Height - 2)); + g.DrawRectangle (Pens.White, new Rectangle (rect.Left, rect.Top, rect.Width - 2, rect.Height - 2)); + + int x = DisplayRectangle.X; + int y = DisplayRectangle.Y; + + for (int i = 0; i < column_widths.Length - 1; i++) { + x += column_widths[i] + 3; + + g.DrawLine (Pens.White, new Point (x, 3), new Point (x, Bottom - 5)); + g.DrawLine (SystemPens.ControlDark, new Point (x + 2, 3), new Point (x + 2, Bottom - 5)); + } + + for (int j = 0; j < row_heights.Length - 1; j++) { + y += row_heights[j] + 3; + + g.DrawLine (Pens.White, new Point (3, y), new Point (Right - 4, y)); + g.DrawLine (SystemPens.ControlDark, new Point (3, y + 2), new Point (Right - 4, y + 2)); + } + + x = DisplayRectangle.X; + y = DisplayRectangle.Y; + + for (int i = 0; i < column_widths.Length - 1; i++) { + x += column_widths[i] + 3; + + g.DrawLine (ThemeEngine.Current.ResPool.GetPen (BackColor), new Point (x + 1, 3), new Point (x + 1, Bottom - 5)); + } + + for (int j = 0; j < row_heights.Length - 1; j++) { + y += row_heights[j] + 3; + + g.DrawLine (ThemeEngine.Current.ResPool.GetPen (BackColor), new Point (3, y + 1), new Point (Right - 4, y + 1)); + } + } + + private void DrawInsetDoubleBorder (Graphics g, Rectangle rect) + { + rect.Width -= 1; + rect.Height -= 1; + + g.DrawRectangle (Pens.White, new Rectangle (rect.Left + 2, rect.Top + 2, rect.Width - 2, rect.Height - 2)); + g.DrawRectangle (SystemPens.ControlDark, new Rectangle (rect.Left, rect.Top, rect.Width - 2, rect.Height - 2)); + + int x = DisplayRectangle.X; + int y = DisplayRectangle.Y; + + for (int i = 0; i < column_widths.Length - 1; i++) { + x += column_widths[i] + 3; + + g.DrawLine (SystemPens.ControlDark, new Point (x, 3), new Point (x, Bottom - 5)); + g.DrawLine (Pens.White, new Point (x + 2, 3), new Point (x + 2, Bottom - 5)); + } + + for (int j = 0; j < row_heights.Length - 1; j++) { + y += row_heights[j] + 3; + + g.DrawLine (SystemPens.ControlDark, new Point (3, y), new Point (Right - 4, y)); + g.DrawLine (Pens.White, new Point (3, y + 2), new Point (Right - 4, y + 2)); + } + + x = DisplayRectangle.X; + y = DisplayRectangle.Y; + + for (int i = 0; i < column_widths.Length - 1; i++) { + x += column_widths[i] + 3; + + g.DrawLine (ThemeEngine.Current.ResPool.GetPen (BackColor), new Point (x + 1, 3), new Point (x + 1, Bottom - 5)); + } + + for (int j = 0; j < row_heights.Length - 1; j++) { + y += row_heights[j] + 3; + + g.DrawLine (ThemeEngine.Current.ResPool.GetPen (BackColor), new Point (3, y + 1), new Point (Right - 4, y + 1)); + } + } + + internal override Size GetPreferredSizeCore (Size proposedSize) + { + // If the tablelayoutowner is autosize, we have to make sure it is big enough + // to hold every non-autosize control + actual_positions = (LayoutEngine as TableLayout).CalculateWidgetPositions (this, Math.Max (ColumnCount, 1), Math.Max (RowCount, 1)); + + // Use actual row/column counts, not user set ones + int actual_cols = actual_positions.GetLength (0); + int actual_rows = actual_positions.GetLength (1); + + // Find the largest column-span/row-span values. A table entry that spans more than one + // column (row) should not be treated as though it's width (height) all belongs to the + // first column (row), but should be spread out across all the columns (rows) that are + // spanned. So we need to keep track of the widths (heights) of spans as well as + // individual columns (rows). + int max_colspan = 1, max_rowspan = 1; + foreach (Widget c in Widgets) + { + max_colspan = Math.Max(max_colspan, GetColumnSpan(c)); + max_rowspan = Math.Max(max_rowspan, GetRowSpan(c)); + } + + // Figure out how wide the owner needs to be + int[] column_widths = new int[actual_cols]; + // Keep track of widths for spans as well as columns. column_span_widths[i,j] stores + // the maximum width for items column i than have a span of j+1 (ie, covers columns + // i through i+j). + int[,] column_span_widths = new int[actual_cols, max_colspan]; + int[] biggest = new int[max_colspan]; + float total_column_percentage = 0f; + + // Figure out how wide each column wants to be + for (int i = 0; i < actual_cols; i++) { + if (i < ColumnStyles.Count && ColumnStyles[i].SizeType == SizeType.Percent) + total_column_percentage += ColumnStyles[i].Width; + int absolute_width = -1; + if (i < ColumnStyles.Count && ColumnStyles[i].SizeType == SizeType.Absolute) + absolute_width = (int)ColumnStyles[i].Width; // use the absolute width if it's absolute! + + for (int s = 0; s < max_colspan; ++s) + biggest[s] = 0; + + for (int j = 0; j < actual_rows; j++) { + Widget c = actual_positions[i, j]; + + if (c != null) { + int colspan = GetColumnSpan (c); + if (colspan == 0) + continue; + if (colspan == 1 && absolute_width > -1) + biggest[0] = absolute_width; // use the absolute width if the column has absolute width assigned! + else if (!c.AutoSize) + biggest[colspan-1] = Math.Max (biggest[colspan-1], c.ExplicitBounds.Width + c.Margin.Horizontal + Padding.Horizontal); + else + biggest[colspan-1] = Math.Max (biggest[colspan-1], c.PreferredSize.Width + c.Margin.Horizontal + Padding.Horizontal); + } + else if (absolute_width > -1) { + biggest[0] = absolute_width; + } + } + + for (int s = 0; s < max_colspan; ++s) + column_span_widths[i,s] = biggest[s]; + } + + for (int i = 0; i < actual_cols; ++i) { + for (int s = 1; s < max_colspan; ++s) { + if (column_span_widths[i,s] > 0) + AdjustWidthsForSpans (column_span_widths, i, s); + } + column_widths[i] = column_span_widths[i,0]; + } + + // Because percentage based rows divy up the remaining space, + // we have to make the owner big enough so that all the rows + // get bigger, even if we only need one to be bigger. + int non_percent_total_width = 0; + int percent_total_width = 0; + + for (int i = 0; i < actual_cols; i++) { + if (i < ColumnStyles.Count && ColumnStyles[i].SizeType == SizeType.Percent) + percent_total_width = Math.Max (percent_total_width, (int)(column_widths[i] / ((ColumnStyles[i].Width) / total_column_percentage))); + else + non_percent_total_width += column_widths[i]; + } + + int border_width = GetCellBorderWidth (CellBorderStyle); + int needed_width = non_percent_total_width + percent_total_width + (border_width * (actual_cols + 1)); + + // Figure out how tall the owner needs to be + int[] row_heights = new int[actual_rows]; + int[,] row_span_heights = new int[actual_rows, max_rowspan]; + biggest = new int[max_rowspan]; + float total_row_percentage = 0f; + + // Figure out how tall each row wants to be + for (int j = 0; j < actual_rows; j++) { + if (j < RowStyles.Count && RowStyles[j].SizeType == SizeType.Percent) + total_row_percentage += RowStyles[j].Height; + int absolute_height = -1; + if (j < RowStyles.Count && RowStyles[j].SizeType == SizeType.Absolute) + absolute_height = (int)RowStyles[j].Height; // use the absolute height if it's absolute! + + for (int s = 0; s < max_rowspan; ++s) + biggest[s] = 0; + + for (int i = 0; i < actual_cols; i++) { + Widget c = actual_positions[i, j]; + + if (c != null) { + int rowspan = GetRowSpan (c); + if (rowspan == 0) + continue; + if (rowspan == 1 && absolute_height > -1) + biggest[0] = absolute_height; // use the absolute height if the row has absolute height assigned! + else if (!c.AutoSize) + biggest[rowspan-1] = Math.Max (biggest[rowspan-1], c.ExplicitBounds.Height + c.Margin.Vertical + Padding.Vertical); + else + biggest[rowspan-1] = Math.Max (biggest[rowspan-1], c.PreferredSize.Height + c.Margin.Vertical + Padding.Vertical); + } + else if (absolute_height > -1) { + biggest[0] = absolute_height; + } + } + + for (int s = 0; s < max_rowspan; ++s) + row_span_heights[j,s] = biggest[s]; + } + + for (int j = 0; j < actual_rows; ++j) { + for (int s = 1; s < max_rowspan; ++s) { + if (row_span_heights[j,s] > 0) + AdjustHeightsForSpans (row_span_heights, j, s); + } + row_heights[j] = row_span_heights[j,0]; + } + + // Because percentage based rows divy up the remaining space, + // we have to make the owner big enough so that all the rows + // get bigger, even if we only need one to be bigger. + int non_percent_total_height = 0; + int percent_total_height = 0; + + for (int j = 0; j < actual_rows; j++) { + if (j < RowStyles.Count && RowStyles[j].SizeType == SizeType.Percent) + percent_total_height = Math.Max (percent_total_height, (int)(row_heights[j] / ((RowStyles[j].Height) / total_row_percentage))); + else + non_percent_total_height += row_heights[j]; + } + + int needed_height = non_percent_total_height + percent_total_height + (border_width * (actual_rows + 1)); + + return new Size (needed_width, needed_height); + } + + /// + /// Adjust the widths of the columns underlying a span if necessary. + /// + private void AdjustWidthsForSpans (int[,] widths, int col, int span) + { + // Get the combined width of the columns underlying the span. + int existing_width = 0; + for (int i = col; i <= col+span; ++i) + existing_width += widths[i,0]; + if (widths[col,span] > existing_width) + { + // We need to expand one or more of the underlying columns to fit the span, + // preferably ones that are not Absolute style. + int excess = widths[col,span] - existing_width; + int remaining = excess; + List adjusting = new List(); + List adjusting_widths = new List(); + for (int i = col; i <= col+span; ++i) { + if (i < ColumnStyles.Count && ColumnStyles[i].SizeType != SizeType.Absolute) { + adjusting.Add(i); + adjusting_widths.Add((float)widths[i,0]); + } + } + if (adjusting.Count == 0) { + // if every column is Absolute, spread the gain across every column + for (int i = col; i <= col+span; ++i) { + adjusting.Add(i); + adjusting_widths.Add((float)widths[i,0]); + } + } + float original_total = 0f; + foreach (var w in adjusting_widths) + original_total += w; + // Divide up the needed additional width proportionally. + for (int i = 0; i < adjusting.Count; ++i) { + var idx = adjusting[i]; + var percent = adjusting_widths[i] / original_total; + var adjust = (int)(percent * excess); + widths[idx,0] += adjust; + remaining -= adjust; + } + // Any remaining fragment (1 or 2 pixels?) is divided evenly. + while (remaining > 0) { + for (int i = 0; i < adjusting.Count && remaining > 0; ++i) { + ++widths[adjusting[i],0]; + --remaining; + } + } + } + } + + /// + /// Adjust the heights of the rows underlying a span if necessary. + /// + private void AdjustHeightsForSpans (int[,] heights, int row, int span) + { + // Get the combined height of the rows underlying the span. + int existing_height = 0; + for (int i = row; i <= row+span; ++i) + existing_height += heights[i,0]; + if (heights[row,span] > existing_height) + { + // We need to expand one or more of the underlying rows to fit the span, + // preferably ones that are not Absolute style. + int excess = heights[row,span] - existing_height; + int remaining = excess; + List adjusting = new List(); + List adjusting_heights = new List(); + for (int i = row; i <= row+span; ++i) { + if (i < RowStyles.Count && RowStyles[i].SizeType != SizeType.Absolute) { + adjusting.Add(i); + adjusting_heights.Add((float)heights[i,0]); + } + } + if (adjusting.Count == 0) { + // if every row is Absolute, spread the gain across every row + for (int i = row; i <= row+span; ++i) { + adjusting.Add(i); + adjusting_heights.Add((float)heights[i,0]); + } + } + float original_total = 0f; + foreach (var w in adjusting_heights) + original_total += w; + // Divide up the needed additional height proportionally. + for (int i = 0; i < adjusting.Count; ++i) { + var idx = adjusting[i]; + var percent = adjusting_heights[i] / original_total; + var adjust = (int)(percent * excess); + heights[idx,0] += adjust; + remaining -= adjust; + } + // Any remaining fragment (1 or 2 pixels?) is divided evenly. + while (remaining > 0) { + for (int i = 0; i < adjusting.Count && remaining > 0; ++i) { + ++heights[adjusting[i],0]; + --remaining; + } + } + } + } + #endregion + + #region Public Events + static object CellPaintEvent = new object (); + + public event TableLayoutCellPaintEventHandler CellPaint { + add { Events.AddHandler (CellPaintEvent, value); } + remove { Events.RemoveHandler (CellPaintEvent, value); } + } + #endregion + + #region IExtenderProvider + bool IExtenderProvider.CanExtend (object obj) + { + if (obj is Widget) + if ((obj as Widget).Parent == this) + return true; + + return false; + } + #endregion + + } +} diff --git a/source/ShiftUI/Widgets/TextBox.cs b/source/ShiftUI/Widgets/TextBox.cs new file mode 100644 index 0000000..1ef880d --- /dev/null +++ b/source/ShiftUI/Widgets/TextBox.cs @@ -0,0 +1,1025 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok pbartok@novell.com +// Daniel Nauck (dna(at)mono-project(dot)de) +// + +// NOT COMPLETE + +using System; +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace ShiftUI { + + [ComVisible(true)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + //[Designer ("ShiftUI.Design.TextBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [ToolboxWidget] + public class TextBox : TextBoxBase { + #region Variables + private MenuItem undo; + private MenuItem cut; + private MenuItem copy; + private MenuItem paste; + private MenuItem delete; + private MenuItem select_all; + + private bool use_system_password_char; + private AutoCompleteStringCollection auto_complete_custom_source; + private AutoCompleteMode auto_complete_mode = AutoCompleteMode.None; + private AutoCompleteSource auto_complete_source = AutoCompleteSource.None; + private AutoCompleteListBox auto_complete_listbox; + private string auto_complete_original_text; + private int auto_complete_selected_index = -1; + private List auto_complete_matches; + private ComboBox auto_complete_cb_source; + #endregion // Variables + + #region Public Constructors + public TextBox() { + + scrollbars = RichTextBoxScrollBars.None; + alignment = HorizontalAlignment.Left; + this.LostFocus +=new EventHandler(TextBox_LostFocus); + this.RightToLeftChanged += new EventHandler (TextBox_RightToLeftChanged); + MouseWheel += new MouseEventHandler (TextBox_MouseWheel); + + BackColor = ThemeEngine.Current.ColorControl; + ForeColor = ThemeEngine.Current.ColorControlText; + backcolor_set = false; + + SetStyle (Widgetstyles.StandardClick | Widgetstyles.StandardDoubleClick, false); + SetStyle (Widgetstyles.FixedHeight, true); + + + document.multiline = false; + } + + #endregion // Public Constructors + + #region Private & Internal Methods + + void TextBox_RightToLeftChanged (object sender, EventArgs e) + { + UpdateAlignment (); + } + + private void TextBox_LostFocus (object sender, EventArgs e) { + if (hide_selection) + document.InvalidateSelectionArea (); + if (auto_complete_listbox != null && auto_complete_listbox.Visible) + auto_complete_listbox.HideListBox (false); + } + + private void TextBox_MouseWheel (object o, MouseEventArgs args) + { + if (auto_complete_listbox == null || !auto_complete_listbox.Visible) + return; + + int lines = args.Delta / 120; + auto_complete_listbox.Scroll (-lines); + } + + // Receives either WM_KEYDOWN or WM_CHAR that will likely need the generation/lookup + // of new matches + private void ProcessAutoCompleteInput (ref Message m, bool deleting_chars) + { + // Need to call base.WndProc before to have access to + // the updated Text property value + base.WndProc (ref m); + auto_complete_original_text = Text; + ShowAutoCompleteListBox (deleting_chars); + } + + private void ShowAutoCompleteListBox (bool deleting_chars) + { + // + // We only support CustomSource by now + // + + IList source = auto_complete_cb_source == null ? auto_complete_custom_source : (IList)auto_complete_cb_source.Items; + + bool append = auto_complete_mode == AutoCompleteMode.Append || auto_complete_mode == AutoCompleteMode.SuggestAppend; + bool suggest = auto_complete_mode == AutoCompleteMode.Suggest || auto_complete_mode == AutoCompleteMode.SuggestAppend; + + if (Text.Length == 0) { + if (auto_complete_listbox != null) + auto_complete_listbox.HideListBox (false); + return; + } + + if (auto_complete_matches == null) + auto_complete_matches = new List (); + + string text = Text; + auto_complete_matches.Clear (); + + for (int i = 0; i < source.Count; i++) { + string item_text = auto_complete_cb_source == null ? auto_complete_custom_source [i] : + auto_complete_cb_source.GetItemText (auto_complete_cb_source.Items [i]); + if (item_text.StartsWith (text, StringComparison.CurrentCultureIgnoreCase)) + auto_complete_matches.Add (item_text); + } + + auto_complete_matches.Sort (); + + // Return if we have a single exact match + if ((auto_complete_matches.Count == 0) || (auto_complete_matches.Count == 1 && + auto_complete_matches [0].Equals (text, StringComparison.CurrentCultureIgnoreCase))) { + + if (auto_complete_listbox != null && auto_complete_listbox.Visible) + auto_complete_listbox.HideListBox (false); + return; + } + + auto_complete_selected_index = suggest ? -1 : 0; + + if (suggest) { + if (auto_complete_listbox == null) + auto_complete_listbox = new AutoCompleteListBox (this); + + // Show or update auto complete listbox contents + auto_complete_listbox.Location = PointToScreen (new Point (0, Height)); + auto_complete_listbox.ShowListBox (); + } + + if (append && !deleting_chars) + AppendAutoCompleteMatch (0); + + document.MoveCaret (CaretDirection.End); + } + + internal void HideAutoCompleteList () + { + if (auto_complete_listbox != null) + auto_complete_listbox.HideListBox (false); + } + + internal bool IsAutoCompleteAvailable { + get { + if (auto_complete_source == AutoCompleteSource.None || auto_complete_mode == AutoCompleteMode.None) + return false; + + // We only support CustomSource by now, as well as an internal custom source used by ComboBox + if (auto_complete_source != AutoCompleteSource.CustomSource) + return false; + IList custom_source = auto_complete_cb_source == null ? auto_complete_custom_source : (IList)auto_complete_cb_source.Items; + if (custom_source == null || custom_source.Count == 0) + return false; + + return true; + } + } + + internal ComboBox AutoCompleteInternalSource { + get { + return auto_complete_cb_source; + } + set { + auto_complete_cb_source = value; + } + } + + internal bool CanNavigateAutoCompleteList { + get { + if (auto_complete_mode == AutoCompleteMode.None) + return false; + if (auto_complete_matches == null || auto_complete_matches.Count == 0) + return false; + + bool suggest_window_visible = auto_complete_listbox != null && auto_complete_listbox.Visible; + if (auto_complete_mode == AutoCompleteMode.Suggest && !suggest_window_visible) + return false; + + return true; + } + } + + bool NavigateAutoCompleteList (Keys key) + { + if (auto_complete_matches == null || auto_complete_matches.Count == 0) + return false; + + bool suggest_window_visible = auto_complete_listbox != null && auto_complete_listbox.Visible; + if (!suggest_window_visible && auto_complete_mode == AutoCompleteMode.Suggest) + return false; + + int index = auto_complete_selected_index; + + switch (key) { + case Keys.Up: + index -= 1; + if (index < -1) + index = auto_complete_matches.Count - 1; + break; + case Keys.Down: + index += 1; + if (index >= auto_complete_matches.Count) + index = -1; + break; + case Keys.PageUp: + if (auto_complete_mode == AutoCompleteMode.Append || !suggest_window_visible) + goto case Keys.Up; + + if (index == -1) + index = auto_complete_matches.Count - 1; + else if (index == 0) + index = -1; + else { + index -= auto_complete_listbox.page_size - 1; + if (index < 0) + index = 0; + } + break; + case Keys.PageDown: + if (auto_complete_mode == AutoCompleteMode.Append || !suggest_window_visible) + goto case Keys.Down; + + if (index == -1) + index = 0; + else if (index == auto_complete_matches.Count - 1) + index = -1; + else { + index += auto_complete_listbox.page_size - 1; + if (index >= auto_complete_matches.Count) + index = auto_complete_matches.Count - 1; + } + break; + default: + break; + } + + // In SuggestAppend mode the navigation mode depends on the visibility of the suggest lb. + bool suggest = auto_complete_mode == AutoCompleteMode.Suggest || auto_complete_mode == AutoCompleteMode.SuggestAppend; + if (suggest && suggest_window_visible) { + Text = index == -1 ? auto_complete_original_text : auto_complete_matches [index]; + auto_complete_listbox.HighlightedIndex = index; + } else + // Append only, not suggest at all + AppendAutoCompleteMatch (index < 0 ? 0 : index); + + auto_complete_selected_index = index; + document.MoveCaret (CaretDirection.End); + + return true; + } + + void AppendAutoCompleteMatch (int index) + { + Text = auto_complete_original_text + auto_complete_matches [index].Substring (auto_complete_original_text.Length); + SelectionStart = auto_complete_original_text.Length; + SelectionLength = auto_complete_matches [index].Length - auto_complete_original_text.Length; + } + + // this is called when the user selects a value from the autocomplete list + // *with* the mouse + internal virtual void OnAutoCompleteValueSelected (EventArgs args) + { + } + + private void UpdateAlignment () + { + HorizontalAlignment new_alignment = alignment; + RightToLeft rtol = GetInheritedRtoL (); + + if (rtol == RightToLeft.Yes) { + if (new_alignment == HorizontalAlignment.Left) + new_alignment = HorizontalAlignment.Right; + else if (new_alignment == HorizontalAlignment.Right) + new_alignment = HorizontalAlignment.Left; + } + + document.alignment = new_alignment; + + // MS word-wraps if alignment isn't left + if (Multiline) { + if (alignment != HorizontalAlignment.Left) { + document.Wrap = true; + } else { + document.Wrap = word_wrap; + } + } + + for (int i = 1; i <= document.Lines; i++) { + document.GetLine (i).Alignment = new_alignment; + } + + document.RecalculateDocument (CreateGraphicsInternal ()); + + Invalidate (); // Make sure we refresh + } + + internal override Color ChangeBackColor (Color backColor) + { + if (backColor == Color.Empty) { + if (!ReadOnly) + backColor = SystemColors.Window; + + backcolor_set = false; + } + + return backColor; + } + + void OnAutoCompleteCustomSourceChanged(object sender, CollectionChangeEventArgs e) { + if(auto_complete_source == AutoCompleteSource.CustomSource) { + //FIXME: handle add, remove and refresh events in AutoComplete algorithm. + } + } + #endregion // Private & Internal Methods + + #region Public Instance Properties + [MonoTODO("AutoCompletion algorithm is currently not implemented.")] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + [Localizable (true)] + //[Editor ("ShiftUI.Design.ListWidgetStringCollectionEditor, " + Consts.AssemblySystem_Design, + //"System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)] + public AutoCompleteStringCollection AutoCompleteCustomSource { + get { + if(auto_complete_custom_source == null) { + auto_complete_custom_source = new AutoCompleteStringCollection (); + auto_complete_custom_source.CollectionChanged += new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged); + } + return auto_complete_custom_source; + } + set { + if(auto_complete_custom_source == value) + return; + + if(auto_complete_custom_source != null) //remove eventhandler from old collection + auto_complete_custom_source.CollectionChanged -= new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged); + + auto_complete_custom_source = value; + + if(auto_complete_custom_source != null) + auto_complete_custom_source.CollectionChanged += new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged); + } + } + + [MonoTODO("AutoCompletion algorithm is currently not implemented.")] + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + [DefaultValue (AutoCompleteMode.None)] + public AutoCompleteMode AutoCompleteMode { + get { return auto_complete_mode; } + set { + if(auto_complete_mode == value) + return; + + if((value < AutoCompleteMode.None) || (value > AutoCompleteMode.SuggestAppend)) + throw new InvalidEnumArgumentException (String.Format ("Enum argument value '{0}' is not valid for AutoCompleteMode", value)); + + auto_complete_mode = value; + } + } + + [MonoTODO("AutoCompletion algorithm is currently not implemented.")] + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + [DefaultValue (AutoCompleteSource.None)] + [TypeConverter (typeof (TextBoxAutoCompleteSourceConverter))] + public AutoCompleteSource AutoCompleteSource { + get { return auto_complete_source; } + set { + if(auto_complete_source == value) + return; + + if(!Enum.IsDefined (typeof (AutoCompleteSource), value)) + throw new InvalidEnumArgumentException (String.Format ("Enum argument value '{0}' is not valid for AutoCompleteSource", value)); + + auto_complete_source = value; + } + } + + [DefaultValue(false)] + [RefreshProperties (RefreshProperties.Repaint)] + public bool UseSystemPasswordChar { + get { + return use_system_password_char; + } + + set { + if (use_system_password_char != value) { + use_system_password_char = value; + + if (!Multiline) + document.PasswordChar = PasswordChar.ToString (); + else + document.PasswordChar = string.Empty; + Invalidate (); + } + } + } + + [DefaultValue(false)] + [MWFCategory("Behavior")] + public bool AcceptsReturn { + get { + return accepts_return; + } + + set { + if (value != accepts_return) { + accepts_return = value; + } + } + } + + [DefaultValue(CharacterCasing.Normal)] + [MWFCategory("Behavior")] + public CharacterCasing CharacterCasing { + get { + return character_casing; + } + + set { + if (value != character_casing) { + character_casing = value; + } + } + } + + [Localizable(true)] + [DefaultValue('\0')] + [MWFCategory("Behavior")] + [RefreshProperties (RefreshProperties.Repaint)] + public char PasswordChar { + get { + if (use_system_password_char) { + return '*'; + } + return password_char; + } + + set { + if (value != password_char) { + password_char = value; + if (!Multiline) { + document.PasswordChar = PasswordChar.ToString (); + } else { + document.PasswordChar = string.Empty; + } + this.CalculateDocument(); + } + } + } + + [DefaultValue(ScrollBars.None)] + [Localizable(true)] + [MWFCategory("Appearance")] + public ScrollBars ScrollBars { + get { + return (ScrollBars)scrollbars; + } + + set { + if (!Enum.IsDefined (typeof (ScrollBars), value)) + throw new InvalidEnumArgumentException ("value", (int) value, + typeof (ScrollBars)); + + if (value != (ScrollBars)scrollbars) { + scrollbars = (RichTextBoxScrollBars)value; + base.CalculateScrollBars(); + } + } + } + + public override string Text { + get { + return base.Text; + } + + set { + base.Text = value; + } + } + + [DefaultValue(HorizontalAlignment.Left)] + [Localizable(true)] + [MWFCategory("Appearance")] + public HorizontalAlignment TextAlign { + get { + return alignment; + } + + set { + if (value != alignment) { + alignment = value; + + UpdateAlignment (); + + OnTextAlignChanged(EventArgs.Empty); + } + } + } + #endregion // Public Instance Properties + + public void Paste (string text) + { + document.ReplaceSelection (CaseAdjust (text), false); + + ScrollToCaret(); + OnTextChanged(EventArgs.Empty); + } + #region Protected Instance Methods + protected override CreateParams CreateParams { + get { + return base.CreateParams; + } + } + + protected override void Dispose (bool disposing) + { + base.Dispose (disposing); + } + + protected override bool IsInputKey (Keys keyData) + { + return base.IsInputKey (keyData); + } + + protected override void OnGotFocus (EventArgs e) + { + base.OnGotFocus (e); + if (selection_length == -1 && !has_been_focused) + SelectAllNoScroll (); + has_been_focused = true; + } + + protected override void OnHandleCreated (EventArgs e) + { + base.OnHandleCreated (e); + } + + protected virtual void OnTextAlignChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [TextAlignChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void WndProc (ref Message m) + { + switch ((Msg)m.Msg) { + case Msg.WM_KEYDOWN: + if (!IsAutoCompleteAvailable) + break; + + Keys key_data = (Keys)m.WParam.ToInt32 (); + switch (key_data) { + case Keys.Down: + case Keys.Up: + case Keys.PageDown: + case Keys.PageUp: + if (NavigateAutoCompleteList (key_data)) { + m.Result = IntPtr.Zero; + return; + } + break; + case Keys.Enter: + if (auto_complete_listbox != null && auto_complete_listbox.Visible) + auto_complete_listbox.HideListBox (false); + SelectAll (); + break; + case Keys.Escape: + if (auto_complete_listbox != null && auto_complete_listbox.Visible) + auto_complete_listbox.HideListBox (false); + break; + case Keys.Delete: + ProcessAutoCompleteInput (ref m, true); + return; + default: + break; + } + break; + case Msg.WM_CHAR: + if (!IsAutoCompleteAvailable) + break; + + // Don't handle either Enter or Esc - they are handled in the WM_KEYDOWN case + int char_value = m.WParam.ToInt32 (); + if (char_value == 13 || char_value == 27) + break; + + ProcessAutoCompleteInput (ref m, char_value == 8); + return; + case Msg.WM_LBUTTONDOWN: + // When the textbox gets focus by LBUTTON (but not by middle or right) + // it does not do the select all / scroll thing. + has_been_focused = true; + FocusInternal (true); + break; + } + + base.WndProc(ref m); + } + #endregion // Protected Instance Methods + + #region Events + static object TextAlignChangedEvent = new object (); + + public event EventHandler TextAlignChanged { + add { Events.AddHandler (TextAlignChangedEvent, value); } + remove { Events.RemoveHandler (TextAlignChangedEvent, value); } + } + #endregion // Events + + #region Private Methods + + + + internal void RestoreContextMenu () + { + //ContextMenuInternal = menu; + } + + private void menu_Popup(object sender, EventArgs e) { + if (SelectionLength == 0) { + cut.Enabled = false; + copy.Enabled = false; + } else { + cut.Enabled = true; + copy.Enabled = true; + } + + if (SelectionLength == TextLength) { + select_all.Enabled = false; + } else { + select_all.Enabled = true; + } + + if (!CanUndo) { + undo.Enabled = false; + } else { + undo.Enabled = true; + } + + if (ReadOnly) { + undo.Enabled = cut.Enabled = paste.Enabled = delete.Enabled = false; + } + } + + private void undo_Click(object sender, EventArgs e) { + Undo(); + } + + private void cut_Click(object sender, EventArgs e) { + Cut(); + } + + private void copy_Click(object sender, EventArgs e) { + Copy(); + } + + private void paste_Click(object sender, EventArgs e) { + Paste(); + } + + private void delete_Click(object sender, EventArgs e) { + SelectedText = string.Empty; + } + + private void select_all_Click(object sender, EventArgs e) { + SelectAll(); + } + #endregion // Private Methods + + public override bool Multiline { + get { + return base.Multiline; + } + + set { + base.Multiline = value; + } + } + + protected override void OnBackColorChanged (EventArgs e) + { + base.OnBackColorChanged (e); + } + + protected override void OnFontChanged (EventArgs e) + { + base.OnFontChanged (e); + } + + protected override void OnHandleDestroyed (EventArgs e) + { + base.OnHandleDestroyed (e); + } + + class AutoCompleteListBox : Widget + { + TextBox owner; + VScrollBar vscroll; + int top_item; + int last_item; + internal int page_size; + int item_height; + int highlighted_index = -1; + bool user_defined_size; + bool resizing; + Rectangle resizer_bounds; + + const int DefaultDropDownItems = 7; + + public AutoCompleteListBox (TextBox tb) + { + owner = tb; + item_height = FontHeight + 2; + + vscroll = new VScrollBar (); + vscroll.ValueChanged += VScrollValueChanged; + Widgets.Add (vscroll); + + is_visible = false; + InternalBorderStyle = BorderStyle.FixedSingle; + } + + protected override CreateParams CreateParams { + get { + CreateParams cp = base.CreateParams; + + cp.Style ^= (int)WindowStyles.WS_CHILD; + cp.Style ^= (int)WindowStyles.WS_VISIBLE; + cp.Style |= (int)WindowStyles.WS_POPUP; + cp.ExStyle |= (int)WindowExStyles.WS_EX_TOPMOST | (int)WindowExStyles.WS_EX_TOOLWINDOW; + return cp; + } + } + + public int HighlightedIndex { + get { + return highlighted_index; + } + set { + if (value == highlighted_index) + return; + + if (highlighted_index != -1) + Invalidate (GetItemBounds (highlighted_index)); + highlighted_index = value; + if (highlighted_index != -1) + Invalidate (GetItemBounds (highlighted_index)); + + if (highlighted_index != -1) + EnsureVisible (highlighted_index); + } + } + + public void Scroll (int lines) + { + int max = vscroll.Maximum - page_size + 1; + int val = vscroll.Value + lines; + if (val > max) + val = max; + else if (val < vscroll.Minimum) + val = vscroll.Minimum; + + vscroll.Value = val; + } + + public void EnsureVisible (int index) + { + if (index < top_item) { + vscroll.Value = index; + } else { + int max = vscroll.Maximum - page_size + 1; + int rows = Height / item_height; + if (index > top_item + rows - 1) { + index = index - rows + 1; + vscroll.Value = index > max ? max : index; + } + } + } + + internal override bool ActivateOnShow { + get { + return false; + } + } + + void VScrollValueChanged (object o, EventArgs args) + { + if (top_item == vscroll.Value) + return; + + top_item = vscroll.Value; + last_item = GetLastVisibleItem (); + Invalidate (); + } + + int GetLastVisibleItem () + { + int top_y = Height; + + for (int i = top_item; i < owner.auto_complete_matches.Count; i++) { + int pos = i - top_item; // relative to visible area + if ((pos * item_height) + item_height >= top_y) + return i; + } + + return owner.auto_complete_matches.Count - 1; + } + + Rectangle GetItemBounds (int index) + { + int pos = index - top_item; + Rectangle bounds = new Rectangle (0, pos * item_height, Width, item_height); + if (vscroll.Visible) + bounds.Width -= vscroll.Width; + + return bounds; + } + + int GetItemAt (Point loc) + { + if (loc.Y > (last_item - top_item) * item_height + item_height) + return -1; + + int retval = loc.Y / item_height; + retval += top_item; + + return retval; + } + + void LayoutListBox () + { + int total_height = owner.auto_complete_matches.Count * item_height; + page_size = Math.Max (Height / item_height, 1); + last_item = GetLastVisibleItem (); + + if (Height < total_height) { + vscroll.Visible = true; + vscroll.Maximum = owner.auto_complete_matches.Count - 1; + vscroll.LargeChange = page_size; + vscroll.Location = new Point (Width - vscroll.Width, 0); + vscroll.Height = Height - item_height; + } else + vscroll.Visible = false; + + resizer_bounds = new Rectangle (Width - item_height, Height - item_height, + item_height, item_height); + } + + public void HideListBox (bool set_text) + { + if (set_text) + owner.Text = owner.auto_complete_matches [HighlightedIndex]; + + Capture = false; + Hide (); + } + + public void ShowListBox () + { + if (!user_defined_size) { + // This should call the Layout routine for us + int height = owner.auto_complete_matches.Count > DefaultDropDownItems ? + DefaultDropDownItems * item_height : (owner.auto_complete_matches.Count + 1) * item_height; + Size = new Size (owner.Width, height); + } else + LayoutListBox (); + + vscroll.Value = 0; + HighlightedIndex = -1; + + Show (); + // make sure we are on top - call the raw routine, since we are parentless + XplatUI.SetZOrder (Handle, IntPtr.Zero, true, false); + Invalidate (); + } + + protected override void OnResize (EventArgs args) + { + base.OnResize (args); + + LayoutListBox (); + Refresh (); + } + + protected override void OnMouseDown (MouseEventArgs args) + { + base.OnMouseDown (args); + + if (!resizer_bounds.Contains (args.Location)) + return; + + user_defined_size = true; + resizing = true; + Capture = true; + } + + protected override void OnMouseMove (MouseEventArgs args) + { + base.OnMouseMove (args); + + if (resizing) { + Point mouse_loc = Widget.MousePosition; + Point ctrl_loc = PointToScreen (Point.Empty); + + Size new_size = new Size (mouse_loc.X - ctrl_loc.X, mouse_loc.Y - ctrl_loc.Y); + if (new_size.Height < item_height) + new_size.Height = item_height; + if (new_size.Width < item_height) + new_size.Width = item_height; + + Size = new_size; + return; + } + + Cursor = resizer_bounds.Contains (args.Location) ? Cursors.SizeNWSE : Cursors.Default; + + int item_idx = GetItemAt (args.Location); + if (item_idx != -1) + HighlightedIndex = item_idx; + } + + protected override void OnMouseUp (MouseEventArgs args) + { + base.OnMouseUp (args); + + int item_idx = GetItemAt (args.Location); + if (item_idx != -1 && !resizing) + HideListBox (true); + + owner.OnAutoCompleteValueSelected (EventArgs.Empty); // internal + resizing = false; + Capture = false; + } + + internal override void OnPaintInternal (PaintEventArgs args) + { + Graphics g = args.Graphics; + Brush brush = ThemeEngine.Current.ResPool.GetSolidBrush (ForeColor); + + int highlighted_idx = HighlightedIndex; + + int y = 0; + int last = GetLastVisibleItem (); + for (int i = top_item; i <= last; i++) { + Rectangle item_bounds = GetItemBounds (i); + if (!item_bounds.IntersectsWith (args.ClipRectangle)) + continue; + + if (i == highlighted_idx) { + g.FillRectangle (SystemBrushes.Highlight, item_bounds); + g.DrawString (owner.auto_complete_matches [i], Font, SystemBrushes.HighlightText, item_bounds); + } else + g.DrawString (owner.auto_complete_matches [i], Font, brush, item_bounds); + + y += item_height; + } + + ThemeEngine.Current.CPDrawSizeGrip (g, SystemColors.Control, resizer_bounds); + } + } + } + + internal class TextBoxAutoCompleteSourceConverter : EnumConverter + { + public TextBoxAutoCompleteSourceConverter(Type type) + : base(type) + { } + + public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) + { + StandardValuesCollection stdv = base.GetStandardValues(context); + AutoCompleteSource[] arr = new AutoCompleteSource[stdv.Count]; + stdv.CopyTo(arr, 0); + AutoCompleteSource[] arr2 = Array.FindAll(arr, delegate (AutoCompleteSource value) { + // No "ListItems" in a TextBox. + return value != AutoCompleteSource.ListItems; + }); + return new StandardValuesCollection(arr2); + } + } +} diff --git a/source/ShiftUI/Widgets/TextBoxBase.cs b/source/ShiftUI/Widgets/TextBoxBase.cs new file mode 100644 index 0000000..aca2dee --- /dev/null +++ b/source/ShiftUI/Widgets/TextBoxBase.cs @@ -0,0 +1,2493 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions:c +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2006 Novell, Inc. (http://www.novell.com) +// +// Authors: +// Peter Bartok pbartok@novell.com +// +// + +// NOT COMPLETE + + +#undef Debug +#undef DebugClick + +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Drawing.Text; +using System.Text; +using System.Runtime.InteropServices; +using System.Collections; + +namespace ShiftUI +{ + [ComVisible (true)] + [DefaultBindingProperty ("Text")] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [DefaultEvent("TextChanged")] + //[Designer("ShiftUI.Design.TextBoxBaseDesigner, " + Consts.AssemblySystem_Design)] + public abstract class TextBoxBase : Widget + { + #region Local Variables + internal HorizontalAlignment alignment; + internal bool accepts_tab; + internal bool accepts_return; + internal bool auto_size; + internal bool backcolor_set; + internal CharacterCasing character_casing; + internal bool hide_selection; + int max_length; + internal bool modified; + internal char password_char; + internal bool read_only; + internal bool word_wrap; + internal Document document; + internal LineTag caret_tag; // tag our cursor is in + internal int caret_pos; // position on the line our cursor is in (can be 0 = beginning of line) + internal ImplicitHScrollBar hscroll; + internal ImplicitVScrollBar vscroll; + internal RichTextBoxScrollBars scrollbars; + internal Timer scroll_timer; + internal bool richtext; + internal bool show_selection; // set to true to always show selection, even if no focus is set + internal ArrayList list_links; // currently showing links + private LinkRectangle current_link; // currently hovering link + private bool enable_links; // whether links are enabled + + internal bool has_been_focused; + + internal int selection_length = -1; // set to the user-specified selection length, or -1 if none + internal bool show_caret_w_selection; // TextBox shows the caret when the selection is visible + internal int canvas_width; + internal int canvas_height; + static internal int track_width = 2; // + static internal int track_border = 5; // + internal DateTime click_last; + internal int click_point_x; + internal int click_point_y; + internal CaretSelection click_mode; + internal BorderStyle actual_border_style; + internal bool shortcuts_enabled = true; + #if Debug + internal static bool draw_lines = false; + #endif + + #endregion // Local Variables + + #region Internal Constructor + // Constructor will go when complete, only for testing - pdb + internal TextBoxBase () + { + alignment = HorizontalAlignment.Left; + accepts_return = false; + accepts_tab = false; + auto_size = true; + InternalBorderStyle = BorderStyle.Fixed3D; + actual_border_style = BorderStyle.Fixed3D; + character_casing = CharacterCasing.Normal; + hide_selection = true; + max_length = short.MaxValue; + password_char = '\0'; + read_only = false; + word_wrap = true; + richtext = false; + show_selection = false; + enable_links = false; + list_links = new ArrayList (); + current_link = null; + show_caret_w_selection = (this is TextBox); + document = new Document(this); + document.WidthChanged += new EventHandler(document_WidthChanged); + document.HeightChanged += new EventHandler(document_HeightChanged); + //document.CaretMoved += new EventHandler(CaretMoved); + document.Wrap = false; + click_last = DateTime.Now; + click_mode = CaretSelection.Position; + + MouseDown += new MouseEventHandler(TextBoxBase_MouseDown); + MouseUp += new MouseEventHandler(TextBoxBase_MouseUp); + MouseMove += new MouseEventHandler(TextBoxBase_MouseMove); + SizeChanged += new EventHandler(TextBoxBase_SizeChanged); + FontChanged += new EventHandler(TextBoxBase_FontOrColorChanged); + ForeColorChanged += new EventHandler(TextBoxBase_FontOrColorChanged); + MouseWheel += new MouseEventHandler(TextBoxBase_MouseWheel); + RightToLeftChanged += new EventHandler (TextBoxBase_RightToLeftChanged); + + scrollbars = RichTextBoxScrollBars.None; + + hscroll = new ImplicitHScrollBar(); + hscroll.ValueChanged += new EventHandler(hscroll_ValueChanged); + hscroll.SetStyle (Widgetstyles.Selectable, false); + hscroll.Enabled = false; + hscroll.Visible = false; + hscroll.Maximum = Int32.MaxValue; + + vscroll = new ImplicitVScrollBar(); + vscroll.ValueChanged += new EventHandler(vscroll_ValueChanged); + vscroll.SetStyle (Widgetstyles.Selectable, false); + vscroll.Enabled = false; + vscroll.Visible = false; + vscroll.Maximum = Int32.MaxValue; + + SuspendLayout (); + this.Widgets.AddImplicit (hscroll); + this.Widgets.AddImplicit (vscroll); + ResumeLayout (); + + SetStyle(Widgetstyles.UserPaint | Widgetstyles.StandardClick, false); + SetStyle(Widgetstyles.UseTextForAccessibility, false); + + base.SetAutoSizeMode (AutoSizeMode.GrowAndShrink); + + canvas_width = ClientSize.Width; + canvas_height = ClientSize.Height; + document.ViewPortWidth = canvas_width; + document.ViewPortHeight = canvas_height; + + Cursor = Cursors.IBeam; + } + #endregion // Internal Constructor + + #region Private and Internal Methods + internal string CaseAdjust (string s) + { + if (character_casing == CharacterCasing.Normal) + return s; + if (character_casing == CharacterCasing.Lower) + return s.ToLower(); + return s.ToUpper(); + } + + internal override Size GetPreferredSizeCore (Size proposedSize) + { + return new Size (Width, Height); + } + + internal override void HandleClick (int clicks, MouseEventArgs me) + { + // MS seems to fire the click event in spite of the styles they set + bool click_set = GetStyle (Widgetstyles.StandardClick); + bool doubleclick_set = GetStyle (Widgetstyles.StandardDoubleClick); + + // so explicitly set them to true first + SetStyle (Widgetstyles.StandardClick | Widgetstyles.StandardDoubleClick, true); + + base.HandleClick (clicks, me); + + // then revert to our previous state + if (!click_set) + SetStyle (Widgetstyles.StandardClick, false); + if (!doubleclick_set) + SetStyle (Widgetstyles.StandardDoubleClick, false); + } + + internal override void PaintWidgetBackground (PaintEventArgs pevent) + { + if (!ThemeEngine.Current.TextBoxBaseShouldPaintBackground (this)) + return; + base.PaintWidgetBackground (pevent); + } + #endregion // Private and Internal Methods + + #region Public Instance Properties + [DefaultValue(false)] + [MWFCategory("Behavior")] + public bool AcceptsTab { + get { + return accepts_tab; + } + + set { + if (value != accepts_tab) { + accepts_tab = value; + OnAcceptsTabChanged(EventArgs.Empty); + } + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + [DefaultValue(true)] + [Localizable(true)] + [RefreshProperties(RefreshProperties.Repaint)] + [MWFCategory("Behavior")] + public override bool AutoSize { + get { + return auto_size; + } + + set { + if (value != auto_size) { + auto_size = value; + if (auto_size) { + if (PreferredHeight != Height) { + Height = PreferredHeight; + } + } + } + } + } + + [DispId(-501)] + public override System.Drawing.Color BackColor { + get { + return base.BackColor; + } + set { + backcolor_set = true; + base.BackColor = ChangeBackColor (value); + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override System.Drawing.Image BackgroundImage { + get { + return base.BackgroundImage; + } + set { + base.BackgroundImage = value; + } + } + + [DefaultValue(BorderStyle.Fixed3D)] + [DispId(-504)] + [MWFCategory("Appearance")] + public BorderStyle BorderStyle { + get { return actual_border_style; } + set { + if (value == actual_border_style) + return; + + if (actual_border_style != BorderStyle.Fixed3D || value != BorderStyle.Fixed3D) + Invalidate (); + + actual_border_style = value; + document.UpdateMargins (); + + if (value != BorderStyle.Fixed3D) + value = BorderStyle.None; + + InternalBorderStyle = value; + OnBorderStyleChanged(EventArgs.Empty); + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool CanUndo { + get { + return document.undo.CanUndo; + } + } + + [DispId(-513)] + public override System.Drawing.Color ForeColor { + get { + return base.ForeColor; + } + set { + base.ForeColor = value; + } + } + + [DefaultValue(true)] + [MWFCategory("Behavior")] + public bool HideSelection { + get { + return hide_selection; + } + + set { + if (value != hide_selection) { + hide_selection = value; + OnHideSelectionChanged(EventArgs.Empty); + } + document.selection_visible = !hide_selection; + document.InvalidateSelectionArea(); + } + } + + [MergableProperty (false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + //[Editor("ShiftUI.Design.StringArrayEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))] + [Localizable(true)] + [MWFCategory("Appearance")] + public string[] Lines { + get { + int count; + ArrayList lines; + + count = document.Lines; + + // Handle empty document + if ((count == 1) && (document.GetLine (1).text.Length == 0)) { + return new string [0]; + } + + lines = new ArrayList (); + + int i = 1; + while (i <= count) { + Line line; + StringBuilder lt = new StringBuilder (); + + do { + line = document.GetLine (i++); + lt.Append (line.TextWithoutEnding ()); + } while (line.ending == LineEnding.Wrap && i <= count); + + lines.Add (lt.ToString ()); + } + + return (string []) lines.ToArray (typeof (string)); + } + + set { + StringBuilder sb = new StringBuilder (); + + for (int i = 0; i < value.Length; i++) { + // Don't add the last line if it is just an empty line feed + // the line feed is reflected in the previous line's ending + if (i == value.Length - 1 && value[i].Length == 0) + break; + + sb.Append (value[i] + Environment.NewLine); + } + + int newline_length = Environment.NewLine.Length; + + // We want to remove the final new line character + if (sb.Length >= newline_length) + sb.Remove (sb.Length - newline_length, newline_length); + + Text = sb.ToString (); + } + } + + [DefaultValue(32767)] + [Localizable(true)] + [MWFCategory("Behavior")] + public virtual int MaxLength { + get { + if (max_length == (int.MaxValue - 1)) { // We don't distinguish between single and multi-line limits + return 0; + } + return max_length; + } + + set { + if (value != max_length) { + if (value == 0) + value = int.MaxValue - 1; + + max_length = value; + } + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool Modified { + get { + return modified; + } + + set { + if (value != modified) { + modified = value; + OnModifiedChanged(EventArgs.Empty); + } + } + } + + [DefaultValue(false)] + [Localizable(true)] + [RefreshProperties(RefreshProperties.All)] + [MWFCategory("Behavior")] + public virtual bool Multiline { + get { + return document.multiline; + } + + set { + if (value != document.multiline) { + document.multiline = value; + + if (this is TextBox) + SetStyle (Widgetstyles.FixedHeight, !value); + + // SetBoundsCore overrides the Height for multiline if it needs to, + // so we don't need to worry about it here. + SetBoundsCore (Left, Top, Width, ExplicitBounds.Height, BoundsSpecified.None); + + if (Parent != null) + Parent.PerformLayout (); + + OnMultilineChanged(EventArgs.Empty); + } + + if (document.multiline) { + document.Wrap = word_wrap; + document.PasswordChar = ""; + + } else { + document.Wrap = false; + if (this.password_char != '\0') { + if (this is TextBox) + document.PasswordChar = (this as TextBox).PasswordChar.ToString (); + } else { + document.PasswordChar = ""; + } + } + + if (IsHandleCreated) + CalculateDocument (); + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + //[EditorBrowsable(EditorBrowsableState.Advanced)] + // This returns the preferred outer height, not the client height. + public int PreferredHeight { + get { + int clientDelta = Height - ClientSize.Height; + if (BorderStyle != BorderStyle.None) + return Font.Height + 7 + clientDelta; + + // usually in borderless mode the top margin is 0, but + // try to access it, in case it was set manually, as ToolStrip* Widgets do + return Font.Height + TopMargin + clientDelta; + } + } + + [RefreshProperties (RefreshProperties.Repaint)] + [DefaultValue(false)] + [MWFCategory("Behavior")] + public bool ReadOnly { + get { + return read_only; + } + + set { + if (value != read_only) { + read_only = value; + if (!backcolor_set) { + if (read_only) + background_color = SystemColors.Control; + else + background_color = SystemColors.Window; + } + OnReadOnlyChanged(EventArgs.Empty); + Invalidate (); + } + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public virtual string SelectedText { + get { + string retval = document.GetSelection (); + + return retval; + } + + set { + if (value == null) + value = String.Empty; + + document.ReplaceSelection(CaseAdjust(value), false); + + ScrollToCaret(); + OnTextChanged(EventArgs.Empty); + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public virtual int SelectionLength { + get { + int res = document.SelectionLength (); + + return res; + } + + set { + if (value < 0) { + string msg = String.Format ("'{0}' is not a valid value for 'SelectionLength'", value); + throw new ArgumentOutOfRangeException ("SelectionLength", msg); + } + + document.InvalidateSelectionArea (); + if (value != 0) { + int start; + Line line; + LineTag tag; + int pos; + + selection_length = value; + start = document.LineTagToCharIndex (document.selection_start.line, document.selection_start.pos); + document.CharIndexToLineTag (start + value, out line, out tag, out pos); + document.SetSelectionEnd (line, pos, true); + document.PositionCaret (line, pos); + } else { + selection_length = -1; + document.SetSelectionEnd (document.selection_start.line, document.selection_start.pos, true); + document.PositionCaret (document.selection_start.line, document.selection_start.pos); + } + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int SelectionStart { + get { + return document.LineTagToCharIndex(document.selection_start.line, + document.selection_start.pos); + } + + set { + if (value < 0) { + string msg = String.Format ("'{0}' is not a valid value for 'SelectionStart'", value); + throw new ArgumentOutOfRangeException ("SelectionStart", msg); + } + + // If SelectionStart has been used, we don't highlight on focus + has_been_focused = true; + + document.InvalidateSelectionArea (); + document.SetSelectionStart (value, false); + if (selection_length > -1) + document.SetSelectionEnd (value + selection_length, true); + else + document.SetSelectionEnd (value, true); + document.PositionCaret (document.selection_start.line, document.selection_start.pos); + ScrollToCaret (); + } + } + + [DefaultValue (true)] + public virtual bool ShortcutsEnabled { + get { return shortcuts_enabled; } + set { shortcuts_enabled = value; } + } + + //[Editor ("System.ComponentModel.Design.MultilineStringEditor, " + Consts.AssemblySystem_Design, + //"System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)] + [Localizable(true)] + public override string Text { + get { + if (document == null || document.Root == null || document.Root.text == null) + return string.Empty; + + StringBuilder sb = new StringBuilder(); + + Line line = null; + for (int i = 1; i <= document.Lines; i++) { + line = document.GetLine (i); + sb.Append(line.text.ToString ()); + } + + return sb.ToString(); + } + + set { + // reset to force a select all next time the box gets focus + has_been_focused = false; + + if (value == Text) + return; + + document.Empty (); + if ((value != null) && (value != "")) { + document.Insert (document.GetLine (1), 0, false, value); + } else { + if (IsHandleCreated) { + document.SetSelectionToCaret (true); + CalculateDocument (); + } + } + + document.PositionCaret (document.GetLine (1), 0); + document.SetSelectionToCaret (true); + + ScrollToCaret (); + + OnTextChanged(EventArgs.Empty); + } + } + + [Browsable(false)] + public virtual int TextLength { + get { + if (document == null || document.Root == null || document.Root.text == null) + return 0; + return Text.Length; + } + } + + [DefaultValue(true)] + [Localizable(true)] + [MWFCategory("Behavior")] + public bool WordWrap { + get { + return word_wrap; + } + + set { + if (value != word_wrap) { + if (document.multiline) { + word_wrap = value; + document.Wrap = value; + } + CalculateDocument (); + } + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Padding Padding { + get { return base.Padding; } + set { base.Padding = value; } + } + + protected override Cursor DefaultCursor { + get { return Cursors.IBeam; } + } + #endregion // Public Instance Properties + + #region Protected Instance Properties + protected override bool CanEnableIme { + get { + if (ReadOnly || password_char != '\0') + return false; + + return true; + } + } + + protected override CreateParams CreateParams { + get { + return base.CreateParams; + } + } + + protected override System.Drawing.Size DefaultSize { + get { + return new Size(100, 20); + } + } + + // Currently our double buffering breaks our scrolling, so don't let people enable this + //[EditorBrowsable (EditorBrowsableState.Never)] + protected override bool DoubleBuffered { + get { return false; } + set { } + } + + #endregion // Protected Instance Properties + + #region Public Instance Methods + public void AppendText (string text) + { + // Save some cycles and only check the Text if we are one line + bool is_empty = document.Lines == 1 && Text == String.Empty; + + // make sure the caret begins at the end + if (document.caret.line.line_no != document.Lines || + (document.caret.pos) != document.caret.line.TextLengthWithoutEnding ()) { + document.MoveCaret (CaretDirection.CtrlEnd); + } + document.Insert (document.caret.line, document.caret.pos, false, text, document.CaretTag); + document.MoveCaret (CaretDirection.CtrlEnd); + document.SetSelectionToCaret (true); + + if (!is_empty) + ScrollToCaret (); + + // + // Avoid the initial focus selecting all when append text is used + // + has_been_focused = true; + + Modified = false; + OnTextChanged(EventArgs.Empty); + } + + public void Clear () + { + Modified = false; + Text = string.Empty; + } + + public void ClearUndo () + { + document.undo.Clear(); + } + + public void Copy () + { + DataObject o; + + o = new DataObject(DataFormats.Text, SelectedText); + if (this is RichTextBox) + o.SetData(DataFormats.Rtf, ((RichTextBox)this).SelectedRtf); + Clipboard.SetDataObject(o); + } + + public void Cut () + { + DataObject o; + + o = new DataObject(DataFormats.Text, SelectedText); + if (this is RichTextBox) + o.SetData(DataFormats.Rtf, ((RichTextBox)this).SelectedRtf); + Clipboard.SetDataObject (o); + + document.undo.BeginUserAction (String.Format ("Cut")); + document.ReplaceSelection (String.Empty, false); + document.undo.EndUserAction (); + + Modified = true; + OnTextChanged (EventArgs.Empty); + } + + public void Paste () + { + Paste (Clipboard.GetDataObject(), null, false); + } + + public void ScrollToCaret () + { + if (IsHandleCreated) + CaretMoved (this, EventArgs.Empty); + } + + public void Select(int start, int length) + { + SelectionStart = start; + SelectionLength = length; + } + + public void SelectAll () + { + Line last; + + last = document.GetLine(document.Lines); + document.SetSelectionStart(document.GetLine(1), 0, false); + document.SetSelectionEnd(last, last.text.Length, true); + document.PositionCaret (document.selection_end.line, document.selection_end.pos); + selection_length = -1; + + CaretMoved (this, null); + + document.DisplayCaret (); + } + + internal void SelectAllNoScroll () + { + Line last; + + last = document.GetLine(document.Lines); + document.SetSelectionStart(document.GetLine(1), 0, false); + document.SetSelectionEnd(last, last.text.Length, false); + document.PositionCaret (document.selection_end.line, document.selection_end.pos); + selection_length = -1; + + document.DisplayCaret (); + } + + public override string ToString () + { + return String.Concat (base.ToString (), ", Text: ", Text); + } + + [MonoInternalNote ("Deleting is classed as Typing, instead of its own Undo event")] + public void Undo () + { + if (document.undo.Undo ()) { + Modified = true; + OnTextChanged (EventArgs.Empty); + } + } + + public void DeselectAll () + { + SelectionLength = 0; + } + + public virtual char GetCharFromPosition (Point pt) + { + return GetCharFromPositionInternal (pt); + } + + internal virtual char GetCharFromPositionInternal (Point p) + { + int index; + LineTag tag = document.FindCursor (p.X, p.Y, out index); + if (tag == null) + return (char) 0; // Shouldn't happen + + if (index >= tag.Line.text.Length) { + + if (tag.Line.ending == LineEnding.Wrap) { + // If we have wrapped text, we return the first char of the next line + Line line = document.GetLine (tag.Line.line_no + 1); + if (line != null) + return line.text [0]; + + } + + if (tag.Line.line_no == document.Lines) { + // Last line returns the last char + return tag.Line.text [tag.Line.text.Length - 1]; + } + + // This really shouldn't happen + return (char) 0; + } + return tag.Line.text [index]; + } + + public virtual int GetCharIndexFromPosition (Point pt) + { + int line_index; + LineTag tag = document.FindCursor (pt.X, pt.Y, out line_index); + if (tag == null) + return 0; + + if (line_index >= tag.Line.text.Length) { + + if (tag.Line.ending == LineEnding.Wrap) { + // If we have wrapped text, we return the first char of the next line + Line line = document.GetLine (tag.Line.line_no + 1); + if (line != null) + return document.LineTagToCharIndex (line, 0); + } + + if (tag.Line.line_no == document.Lines) { + // Last line returns the last char + return document.LineTagToCharIndex (tag.Line, tag.Line.text.Length - 1); + } + + return 0; + } + + return document.LineTagToCharIndex (tag.Line, line_index); + } + + public virtual Point GetPositionFromCharIndex (int index) + { + int pos; + Line line; + LineTag tag; + + document.CharIndexToLineTag (index, out line, out tag, out pos); + + return new Point ((int) (line.widths [pos] + + line.X + document.viewport_x), + line.Y + document.viewport_y + tag.Shift); + } + + public int GetFirstCharIndexFromLine (int lineNumber) + { + Line line = document.GetLine (lineNumber + 1); + if (line == null) + return -1; + + return document.LineTagToCharIndex (line, 0); + } + + public int GetFirstCharIndexOfCurrentLine () + { + return document.LineTagToCharIndex (document.caret.line, 0); + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + protected override void CreateHandle () + { + CalculateDocument (); + base.CreateHandle (); + document.AlignCaret(); + ScrollToCaret(); + } + + internal virtual void HandleLinkClicked (LinkRectangle link_clicked) + { + } + + protected override bool IsInputKey (Keys keyData) + { + if ((keyData & Keys.Alt) != 0) + return base.IsInputKey(keyData); + + switch (keyData & Keys.KeyCode) { + case Keys.Enter: { + return (accepts_return && document.multiline); + } + + case Keys.Tab: { + if (accepts_tab && document.multiline) + if ((keyData & Keys.Widget) == 0) + return true; + return false; + } + + case Keys.Left: + case Keys.Right: + case Keys.Up: + case Keys.Down: + case Keys.PageUp: + case Keys.PageDown: + case Keys.Home: + case Keys.End: { + return true; + } + } + return false; + } + + protected virtual void OnAcceptsTabChanged(EventArgs e) + { + EventHandler eh = (EventHandler)(Events [AcceptsTabChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnBorderStyleChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [BorderStyleChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnFontChanged (EventArgs e) + { + base.OnFontChanged (e); + + if (auto_size && !document.multiline) { + if (PreferredHeight != Height) { + Height = PreferredHeight; + } + } + } + + protected override void OnHandleCreated (EventArgs e) + { + base.OnHandleCreated (e); + FixupHeight (); + } + + protected override void OnHandleDestroyed (EventArgs e) + { + base.OnHandleDestroyed (e); + } + + protected virtual void OnHideSelectionChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [HideSelectionChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnModifiedChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [ModifiedChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnMultilineChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [MultilineChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnPaddingChanged (EventArgs e) + { + base.OnPaddingChanged (e); + } + + protected virtual void OnReadOnlyChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [ReadOnlyChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected override bool ProcessCmdKey (ref Message msg, Keys keyData) + { + return base.ProcessCmdKey (ref msg, keyData); + } + protected override bool ProcessDialogKey (Keys keyData) + { + // The user can use Ctrl-Tab or Ctrl-Shift-Tab to move Widget focus + // instead of inserting a Tab. However, the focus-moving-tab-stuffs + // doesn't work if Ctrl is pushed, so we remove it before sending it. + if (accepts_tab && (keyData & (Keys.Widget | Keys.Tab)) == (Keys.Widget | Keys.Tab)) + keyData ^= Keys.Widget; + + return base.ProcessDialogKey(keyData); + } + + private bool ProcessKey (Keys keyData) + { + bool control; + bool shift; + + control = (Widget.ModifierKeys & Keys.Widget) != 0; + shift = (Widget.ModifierKeys & Keys.Shift) != 0; + + if (shortcuts_enabled) { + switch (keyData & Keys.KeyCode) { + case Keys.X: + if (control && read_only == false) { + Cut(); + return true; + } + return false; + + case Keys.C: + if (control) { + Copy(); + return true; + } + return false; + + case Keys.V: + if (control && read_only == false) { + return Paste(Clipboard.GetDataObject(), null, true); + } + return false; + + case Keys.Z: + if (control && read_only == false) { + Undo (); + return true; + } + return false; + + case Keys.A: + if (control) { + SelectAll(); + return true; + } + return false; + + case Keys.Insert: + + if (read_only == false) { + if (shift) { + Paste (Clipboard.GetDataObject (), null, true); + return true; + } + + if (control) { + Copy (); + return true; + } + } + + return false; + + case Keys.Delete: + + if (read_only) + break; + + if (shift && read_only == false) { + Cut (); + return true; + } + + if (document.selection_visible) { + document.ReplaceSelection("", false); + } else { + // DeleteChar only deletes on the line, doesn't do the combine + if (document.CaretPosition >= document.CaretLine.TextLengthWithoutEnding ()) { + if (document.CaretLine.LineNo < document.Lines) { + Line line; + + line = document.GetLine(document.CaretLine.LineNo + 1); + + // this line needs to be invalidated before it is combined + // because once it is combined, all it's coordinates will + // have changed + document.Invalidate (line, 0, line, line.text.Length); + document.Combine(document.CaretLine, line); + + document.UpdateView(document.CaretLine, + document.Lines, 0); + + } + } else { + if (!control) { + document.DeleteChar(document.CaretTag.Line, document.CaretPosition, true); + } else { + int end_pos; + + end_pos = document.CaretPosition; + + while ((end_pos < document.CaretLine.Text.Length) && !Document.IsWordSeparator(document.CaretLine.Text[end_pos])) { + end_pos++; + } + + if (end_pos < document.CaretLine.Text.Length) { + end_pos++; + } + document.DeleteChars(document.CaretTag.Line, document.CaretPosition, end_pos - document.CaretPosition); + } + } + } + + document.AlignCaret(); + document.UpdateCaret(); + CaretMoved(this, null); + + Modified = true; + OnTextChanged (EventArgs.Empty); + + return true; + } + } + + switch (keyData & Keys.KeyCode) { + case Keys.Left: { + if (control) { + document.MoveCaret(CaretDirection.WordBack); + } else { + if (!document.selection_visible || shift) { + document.MoveCaret(CaretDirection.CharBack); + } else { + document.MoveCaret(CaretDirection.SelectionStart); + } + } + + if (!shift) { + document.SetSelectionToCaret(true); + } else { + document.SetSelectionToCaret(false); + } + + CaretMoved(this, null); + return true; + } + + case Keys.Right: { + if (control) { + document.MoveCaret(CaretDirection.WordForward); + } else { + if (!document.selection_visible || shift) { + document.MoveCaret(CaretDirection.CharForward); + } else { + document.MoveCaret(CaretDirection.SelectionEnd); + } + } + if (!shift) { + document.SetSelectionToCaret(true); + } else { + document.SetSelectionToCaret(false); + } + + CaretMoved(this, null); + return true; + } + + case Keys.Up: { + if (control) { + if (document.CaretPosition == 0) { + document.MoveCaret(CaretDirection.LineUp); + } else { + document.MoveCaret(CaretDirection.Home); + } + } else { + document.MoveCaret(CaretDirection.LineUp); + } + + if ((Widget.ModifierKeys & Keys.Shift) == 0) { + document.SetSelectionToCaret(true); + } else { + document.SetSelectionToCaret(false); + } + + CaretMoved(this, null); + return true; + } + + case Keys.Down: { + if (control) { + if (document.CaretPosition == document.CaretLine.Text.Length) { + document.MoveCaret(CaretDirection.LineDown); + } else { + document.MoveCaret(CaretDirection.End); + } + } else { + document.MoveCaret(CaretDirection.LineDown); + } + + if ((Widget.ModifierKeys & Keys.Shift) == 0) { + document.SetSelectionToCaret(true); + } else { + document.SetSelectionToCaret(false); + } + + CaretMoved(this, null); + return true; + } + + case Keys.Home: { + if ((Widget.ModifierKeys & Keys.Widget) != 0) { + document.MoveCaret(CaretDirection.CtrlHome); + } else { + document.MoveCaret(CaretDirection.Home); + } + + if ((Widget.ModifierKeys & Keys.Shift) == 0) { + document.SetSelectionToCaret(true); + } else { + document.SetSelectionToCaret(false); + } + + CaretMoved(this, null); + return true; + } + + case Keys.End: { + if ((Widget.ModifierKeys & Keys.Widget) != 0) { + document.MoveCaret(CaretDirection.CtrlEnd); + } else { + document.MoveCaret(CaretDirection.End); + } + + if ((Widget.ModifierKeys & Keys.Shift) == 0) { + document.SetSelectionToCaret(true); + } else { + document.SetSelectionToCaret(false); + } + + CaretMoved(this, null); + return true; + } + + //case Keys.Enter: { + // // ignoring accepts_return, fixes bug #76355 + // if (!read_only && document.multiline && (accepts_return || (FindForm() != null && FindForm().AcceptButton == null) || ((Widget.ModifierKeys & Keys.Widget) != 0))) { + // Line line; + + // if (document.selection_visible) { + // document.ReplaceSelection("\n", false); + // } + + // line = document.CaretLine; + + // document.Split (document.CaretLine, document.CaretTag, document.CaretPosition); + // line.ending = LineEnding.Rich; + // document.InsertString (line, line.text.Length, + // document.LineEndingToString (line.ending)); + // OnTextChanged(EventArgs.Empty); + + // document.UpdateView (line, document.Lines - line.line_no, 0); + // CaretMoved(this, null); + // return true; + // } + // break; + //} + + case Keys.Tab: { + if (!read_only && accepts_tab && document.multiline) { + document.InsertCharAtCaret ('\t', true); + + CaretMoved(this, null); + Modified = true; + OnTextChanged (EventArgs.Empty); + + return true; + } + break; + } + + case Keys.PageUp: { + if ((Widget.ModifierKeys & Keys.Widget) != 0) { + document.MoveCaret(CaretDirection.CtrlPgUp); + } else { + document.MoveCaret(CaretDirection.PgUp); + } + document.DisplayCaret (); + return true; + } + + case Keys.PageDown: { + if ((Widget.ModifierKeys & Keys.Widget) != 0) { + document.MoveCaret(CaretDirection.CtrlPgDn); + } else { + document.MoveCaret(CaretDirection.PgDn); + } + document.DisplayCaret (); + return true; + } + } + + return false; + } + + internal virtual void RaiseSelectionChanged () + { + // Do nothing, overridden in RTB + } + + private void HandleBackspace (bool Widget) + { + bool fire_changed; + + fire_changed = false; + + // delete only deletes on the line, doesn't do the combine + if (document.selection_visible) { + document.undo.BeginUserAction (String.Format ("Delete")); + document.ReplaceSelection("", false); + document.undo.EndUserAction (); + fire_changed = true; + document.SetSelectionToCaret (true); + } else { + document.SetSelectionToCaret (true); + + if (document.CaretPosition == 0) { + if (document.CaretLine.LineNo > 1) { + Line line; + int new_caret_pos; + + line = document.GetLine(document.CaretLine.LineNo - 1); + new_caret_pos = line.TextLengthWithoutEnding (); + + // Invalidate the old line position before we do the combine + document.Invalidate (line, 0, line, line.text.Length); + document.Combine(line, document.CaretLine); + + document.UpdateView(line, document.Lines - line.LineNo, 0); + document.PositionCaret(line, new_caret_pos); + document.SetSelectionToCaret (true); + document.UpdateCaret(); + fire_changed = true; + } + } else { + if (!Widget || document.CaretPosition == 0) { + + // Move before we delete because the delete will change positions around + // if we cross a wrap border + LineTag tag = document.CaretTag; + int pos = document.CaretPosition; + document.MoveCaret (CaretDirection.CharBack); + document.DeleteChar (tag.Line, pos, false); + document.SetSelectionToCaret (true); + } else { + int start_pos; + + + start_pos = document.CaretPosition - 1; + while ((start_pos > 0) && !Document.IsWordSeparator(document.CaretLine.Text[start_pos - 1])) { + start_pos--; + } + + document.undo.BeginUserAction (String.Format ("Delete")); + document.DeleteChars(document.CaretTag.Line, start_pos, document.CaretPosition - start_pos); + document.undo.EndUserAction (); + document.PositionCaret(document.CaretLine, start_pos); + document.SetSelectionToCaret (true); + } + document.UpdateCaret(); + fire_changed = true; + } + } + + CaretMoved (this, null); + + if (fire_changed) { + Modified = true; + OnTextChanged(EventArgs.Empty); + } + } + + private void HandleEnter () + { + // ignoring accepts_return, fixes bug #76355 + if (!read_only && document.multiline && (accepts_return || (FindForm() != null && FindForm().AcceptButton == null) || ((Widget.ModifierKeys & Keys.Widget) != 0))) { + Line line; + + if (document.selection_visible) + document.ReplaceSelection ("", false); + + line = document.CaretLine; + + document.Split (document.CaretLine, document.CaretTag, document.CaretPosition); + line.ending = document.StringToLineEnding (Environment.NewLine); + document.InsertString (line, line.text.Length, document.LineEndingToString (line.ending)); + + document.UpdateView (line, document.Lines - line.line_no, 0); + CaretMoved (this, null); + Modified = true; + OnTextChanged (EventArgs.Empty); + } + } + + protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified) + { + // Make sure we don't get sized bigger than we want to be + + if (!richtext) { + if (!document.multiline) { + if (height != PreferredHeight) { + // If the specified has Height, we need to store that in the + // ExplicitBounds because we are going to override it + if ((specified & BoundsSpecified.Height) != 0) { + Rectangle r = ExplicitBounds; + r.Height = height; + ExplicitBounds = r; + specified &= ~BoundsSpecified.Height; + } + + height = PreferredHeight; + } + } + } + + base.SetBoundsCore (x, y, width, height, specified); + } + + protected override void WndProc (ref Message m) + { + switch ((Msg)m.Msg) { + case Msg.WM_KEYDOWN: { + if (ProcessKeyMessage(ref m) || ProcessKey((Keys)m.WParam.ToInt32() | XplatUI.State.ModifierKeys)) { + m.Result = IntPtr.Zero; + return; + } + DefWndProc (ref m); + return; + } + + case Msg.WM_CHAR: { + int ch; + + if (ProcessKeyMessage(ref m)) { + m.Result = IntPtr.Zero; + return; + } + + if (read_only) { + return; + } + + m.Result = IntPtr.Zero; + + ch = m.WParam.ToInt32(); + + if (ch == 127) { + HandleBackspace(true); + } else if (ch >= 32) { + if (document.selection_visible) { + document.ReplaceSelection("", false); + } + + char c = (char)m.WParam; + switch (character_casing) { + case CharacterCasing.Upper: + c = Char.ToUpper((char) m.WParam); + break; + case CharacterCasing.Lower: + c = Char.ToLower((char) m.WParam); + break; + } + + if (document.Length < max_length) { + document.InsertCharAtCaret(c, true); + OnTextUpdate (); + CaretMoved (this, null); + Modified = true; + OnTextChanged(EventArgs.Empty); + + } else { + XplatUI.AudibleAlert(AlertType.Default); + } + return; + } else if (ch == 8) { + HandleBackspace(false); + } else if (ch == 13) + HandleEnter (); + + return; + } + + case Msg.WM_SETFOCUS: + base.WndProc(ref m); + document.CaretHasFocus (); + break; + + case Msg.WM_KILLFOCUS: + base.WndProc(ref m); + document.CaretLostFocus (); + break; + + case Msg.WM_NCPAINT: + if (!ThemeEngine.Current.TextBoxBaseHandleWmNcPaint (this, ref m)) + base.WndProc(ref m); + break; + + default: + base.WndProc(ref m); + return; + } + } + + #endregion // Protected Instance Methods + + #region Events + static object AcceptsTabChangedEvent = new object (); + static object AutoSizeChangedEvent = new object (); + static object BorderStyleChangedEvent = new object (); + static object HideSelectionChangedEvent = new object (); + static object ModifiedChangedEvent = new object (); + static object MultilineChangedEvent = new object (); + static object ReadOnlyChangedEvent = new object (); + static object HScrolledEvent = new object (); + static object VScrolledEvent = new object (); + + public event EventHandler AcceptsTabChanged { + add { Events.AddHandler (AcceptsTabChangedEvent, value); } + remove { Events.RemoveHandler (AcceptsTabChangedEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler AutoSizeChanged { + add { Events.AddHandler (AutoSizeChangedEvent, value); } + remove { Events.RemoveHandler (AutoSizeChangedEvent, value); } + } + + public event EventHandler BorderStyleChanged { + add { Events.AddHandler (BorderStyleChangedEvent, value); } + remove { Events.RemoveHandler (BorderStyleChangedEvent, value); } + } + + public event EventHandler HideSelectionChanged { + add { Events.AddHandler (HideSelectionChangedEvent, value); } + remove { Events.RemoveHandler (HideSelectionChangedEvent, value); } + } + + public event EventHandler ModifiedChanged { + add { Events.AddHandler (ModifiedChangedEvent, value); } + remove { Events.RemoveHandler (ModifiedChangedEvent, value); } + } + + public event EventHandler MultilineChanged { + add { Events.AddHandler (MultilineChangedEvent, value); } + remove { Events.RemoveHandler (MultilineChangedEvent, value); } + } + + public event EventHandler ReadOnlyChanged { + add { Events.AddHandler (ReadOnlyChangedEvent, value); } + remove { Events.RemoveHandler (ReadOnlyChangedEvent, value); } + } + + internal event EventHandler HScrolled { + add { Events.AddHandler (HScrolledEvent, value); } + remove { Events.RemoveHandler (HScrolledEvent, value); } + } + + internal event EventHandler VScrolled { + add { Events.AddHandler (VScrolledEvent, value); } + remove { Events.RemoveHandler (VScrolledEvent, value); } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageChanged { + add { base.BackgroundImageChanged += value; } + remove { base.BackgroundImageChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageLayoutChanged { + add { base.BackgroundImageLayoutChanged += value; } + remove { base.BackgroundImageLayoutChanged -= value; } + } + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event MouseEventHandler MouseClick { + add { base.MouseClick += value; } + remove { base.MouseClick -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new event EventHandler PaddingChanged { + add { base.PaddingChanged += value; } + remove { base.PaddingChanged -= value; } + } + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler Click { + add { base.Click += value; } + remove { base.Click -= value; } + } + + // XXX should this not manipulate base.Paint? +#pragma warning disable 0067 + [MonoTODO] + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public new event PaintEventHandler Paint; +#pragma warning restore 0067 + + #endregion // Events + + #region Private Methods + internal Document Document { + get { + return document; + } + + set { + document = value; + } + } + + internal bool EnableLinks { + get { return enable_links; } + set { + enable_links = value; + + document.EnableLinks = value; + } + } + + internal override bool ScaleChildrenInternal { + get { return false; } + } + + internal bool ShowSelection { + get { + if (show_selection || !hide_selection) { + return true; + } + + return has_focus; + } + + set { + if (show_selection == value) + return; + + show_selection = value; + // Currently InvalidateSelectionArea is commented out so do a full invalidate + document.InvalidateSelectionArea(); + } + } + + internal int TopMargin { + get { + return document.top_margin; + } + set { + document.top_margin = value; + } + } + + #region UIA Framework Properties + + internal ScrollBar UIAHScrollBar { + get { return hscroll; } + } + + internal ScrollBar UIAVScrollBar { + get { return vscroll; } + } + + #endregion UIA Framework Properties + + internal Graphics CreateGraphicsInternal () + { + if (IsHandleCreated) + return base.CreateGraphics(); + + return DeviceContext; + } + + internal override void OnPaintInternal (PaintEventArgs pevent) + { + Draw (pevent.Graphics, pevent.ClipRectangle); + + // + // OnPaint does not get raised on MS (see bug #80639) + // + pevent.Handled = true; + } + + internal void Draw (Graphics g, Rectangle clippingArea) + { + ThemeEngine.Current.TextBoxBaseFillBackground (this, g, clippingArea); + + // Draw the viewable document + document.Draw(g, clippingArea); + } + + private void FixupHeight () + { + if (!richtext) { + if (!document.multiline) { + if (PreferredHeight != Height) { + Height = PreferredHeight; + } + } + } + } + + private bool IsDoubleClick (MouseEventArgs e) + { + TimeSpan interval = DateTime.Now - click_last; + if (interval.TotalMilliseconds > SystemInformation.DoubleClickTime) + return false; + Size dcs = SystemInformation.DoubleClickSize; + if (e.X < click_point_x - dcs.Width / 2 || e.X > click_point_x + dcs.Width / 2) + return false; + if (e.Y < click_point_y - dcs.Height / 2 || e.Y > click_point_y + dcs.Height / 2) + return false; + return true; + } + + private void TextBoxBase_MouseDown (object sender, MouseEventArgs e) + { + bool dbliclick = false; + + if (e.Button == MouseButtons.Left) { + + // Special case when shift key is pressed and + // left mouse is clicked.. set selection from + // current cursor to mouse + if ((Widget.ModifierKeys & Keys.Shift) > 0) { + document.PositionCaret (e.X + document.ViewPortX, e.Y + document.ViewPortY); + document.SetSelectionToCaret (false); + document.DisplayCaret (); + return; + } + + dbliclick = IsDoubleClick (e); + + if (current_link != null) { + HandleLinkClicked (current_link); + return; + } + + //ensure nothing is selected anymore BEFORE we + //position the caret, so the caret is recreated + //(caret is only visible when nothing is selected) + if (document.selection_visible && dbliclick == false) { + document.SetSelectionToCaret (true); + click_mode = CaretSelection.Position; + } + + document.PositionCaret(e.X + document.ViewPortX, e.Y + document.ViewPortY); + + if (dbliclick) { + switch (click_mode) { + case CaretSelection.Position: + SelectWord (); + click_mode = CaretSelection.Word; + break; + case CaretSelection.Word: + + if (this is TextBox) { + document.SetSelectionToCaret (true); + click_mode = CaretSelection.Position; + break; + } + + document.ExpandSelection (CaretSelection.Line, false); + click_mode = CaretSelection.Line; + break; + case CaretSelection.Line: + + // Gotta do this first because Exanding to a word + // from a line doesn't really work + document.SetSelectionToCaret (true); + + SelectWord (); + click_mode = CaretSelection.Word; + break; + } + } else { + document.SetSelectionToCaret (true); + click_mode = CaretSelection.Position; + } + + click_point_x = e.X; + click_point_y = e.Y; + click_last = DateTime.Now; + } + + if ((e.Button == MouseButtons.Middle) && XplatUI.RunningOnUnix) { + Document.Marker marker; + + marker.tag = document.FindCursor(e.X + document.ViewPortX, e.Y + document.ViewPortY, out marker.pos); + marker.line = marker.tag.Line; + marker.height = marker.tag.Height; + + document.SetSelection(marker.line, marker.pos, marker.line, marker.pos); + Paste (Clipboard.GetDataObject (true), null, true); + } + } + + private void TextBoxBase_MouseUp (object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) { + if (click_mode == CaretSelection.Position) { + document.SetSelectionToCaret(false); + document.DisplayCaret(); + + // Only raise if there is text. + if (Text.Length > 0) + RaiseSelectionChanged (); + } + + if (scroll_timer != null) { + scroll_timer.Enabled = false; + } + return; + } + } + + private void SizeWidgets () + { + if (hscroll.Visible) { + //vscroll.Maximum += hscroll.Height; + canvas_height = ClientSize.Height - hscroll.Height; + } else { + canvas_height = ClientSize.Height; + } + + if (vscroll.Visible) { + //hscroll.Maximum += vscroll.Width; + canvas_width = ClientSize.Width - vscroll.Width; + + if (GetInheritedRtoL () == RightToLeft.Yes) { + document.OffsetX = vscroll.Width; + } else { + document.OffsetX = 0; + } + + } else { + canvas_width = ClientSize.Width; + document.OffsetX = 0; + } + + document.ViewPortWidth = canvas_width; + document.ViewPortHeight = canvas_height; + } + + private void PositionWidgets () + { + if (canvas_height < 1 || canvas_width < 1) + return; + + int hmod = vscroll.Visible ? vscroll.Width : 0; + int vmod = hscroll.Visible ? hscroll.Height : 0; + + if (GetInheritedRtoL () == RightToLeft.Yes) { + hscroll.Bounds = new Rectangle (ClientRectangle.Left + hmod, + Math.Max(0, ClientRectangle.Height - hscroll.Height), + ClientSize.Width, + hscroll.Height); + + vscroll.Bounds = new Rectangle (ClientRectangle.Left, + ClientRectangle.Top, + vscroll.Width, + Math.Max(0, ClientSize.Height - (vmod))); + } else { + hscroll.Bounds = new Rectangle (ClientRectangle.Left, + Math.Max(0, ClientRectangle.Height - hscroll.Height), + Math.Max(0, ClientSize.Width - hmod), + hscroll.Height); + + vscroll.Bounds = new Rectangle ( + Math.Max(0, ClientRectangle.Right - vscroll.Width), + ClientRectangle.Top, + vscroll.Width, + Math.Max(0, ClientSize.Height - vmod)); + } + } + + internal RightToLeft GetInheritedRtoL () + { + for (Widget c = this; c != null; c = c.Parent) + if (c.RightToLeft != RightToLeft.Inherit) + return c.RightToLeft; + return RightToLeft.No; + } + + private void TextBoxBase_SizeChanged (object sender, EventArgs e) + { + if (IsHandleCreated) + CalculateDocument (); + } + + private void TextBoxBase_RightToLeftChanged (object o, EventArgs e) + { + if (IsHandleCreated) + CalculateDocument (); + } + + private void TextBoxBase_MouseWheel (object sender, MouseEventArgs e) + { + if (!vscroll.Enabled) + return; + + if (e.Delta < 0) + vscroll.Value = Math.Min (vscroll.Value + SystemInformation.MouseWheelScrollLines * 5, + Math.Max (0, vscroll.Maximum - document.ViewPortHeight + 1)); + else + vscroll.Value = Math.Max (0, vscroll.Value - SystemInformation.MouseWheelScrollLines * 5); + } + + internal virtual void SelectWord () + { + StringBuilder s = document.caret.line.text; + int start = document.caret.pos; + int end = document.caret.pos; + + if (s.Length < 1) { + if (document.caret.line.line_no >= document.Lines) + return; + Line line = document.GetLine (document.caret.line.line_no + 1); + document.PositionCaret (line, 0); + return; + } + + if (start > 0) { + start--; + end--; + } + + // skip whitespace until we hit a word + while (start > 0 && s [start] == ' ') + start--; + if (start > 0) { + while (start > 0 && (s [start] != ' ')) + start--; + if (s [start] == ' ') + start++; + } + + if (s [end] == ' ') { + while (end < s.Length && s [end] == ' ') + end++; + } else { + while (end < s.Length && s [end] != ' ') + end++; + while (end < s.Length && s [end] == ' ') + end++; + } + + document.SetSelection (document.caret.line, start, document.caret.line, end); + document.PositionCaret (document.selection_end.line, document.selection_end.pos); + document.DisplayCaret(); + } + + internal void CalculateDocument() + { + CalculateScrollBars (); + document.RecalculateDocument (CreateGraphicsInternal ()); + + + if (document.caret.line != null && document.caret.line.Y < document.ViewPortHeight) { + // The window has probably been resized, making the entire thing visible, so + // we need to set the scroll position back to zero. + vscroll.Value = 0; + } + + Invalidate(); + } + + internal void CalculateScrollBars () + { + // FIXME - need separate calculations for center and right alignment + SizeWidgets (); + + if (document.Width >= document.ViewPortWidth) { + hscroll.SetValues (0, Math.Max (1, document.Width), -1, + document.ViewPortWidth < 0 ? 0 : document.ViewPortWidth); + if (document.multiline) + hscroll.Enabled = true; + } else { + hscroll.Enabled = false; + hscroll.Maximum = document.ViewPortWidth; + } + + if (document.Height >= document.ViewPortHeight) { + vscroll.SetValues (0, Math.Max (1, document.Height), -1, + document.ViewPortHeight < 0 ? 0 : document.ViewPortHeight); + if (document.multiline) + vscroll.Enabled = true; + } else { + vscroll.Enabled = false; + vscroll.Maximum = document.ViewPortHeight; + } + + if (!WordWrap) { + switch (scrollbars) { + case RichTextBoxScrollBars.Both: + case RichTextBoxScrollBars.Horizontal: + if (richtext) + hscroll.Visible = hscroll.Enabled; + else + hscroll.Visible = this.Multiline; + break; + case RichTextBoxScrollBars.ForcedBoth: + case RichTextBoxScrollBars.ForcedHorizontal: + hscroll.Visible = true; + break; + default: + hscroll.Visible = false; + break; + } + } else { + hscroll.Visible = false; + } + + switch (scrollbars) { + case RichTextBoxScrollBars.Both: + case RichTextBoxScrollBars.Vertical: + if (richtext) + vscroll.Visible = vscroll.Enabled; + else + vscroll.Visible = this.Multiline; + break; + case RichTextBoxScrollBars.ForcedBoth: + case RichTextBoxScrollBars.ForcedVertical: + vscroll.Visible = true; + break; + default: + vscroll.Visible = false; + break; + } + + PositionWidgets (); + + SizeWidgets (); //Update sizings now we've decided whats visible + } + + private void document_WidthChanged (object sender, EventArgs e) + { + CalculateScrollBars(); + } + + private void document_HeightChanged (object sender, EventArgs e) + { + CalculateScrollBars(); + } + + private void ScrollLinks (int xChange, int yChange) + { + foreach (LinkRectangle link in list_links) + link.Scroll (xChange, yChange); + } + + private void hscroll_ValueChanged (object sender, EventArgs e) + { + int old_viewport_x; + + old_viewport_x = document.ViewPortX; + document.ViewPortX = this.hscroll.Value; + + // + // Before scrolling we want to destroy the caret, then draw a new one after the scroll + // the reason for this is that scrolling changes the coordinates of the caret, and we + // will get tracers if we don't + // + if (Focused) + document.CaretLostFocus (); + + if (vscroll.Visible) { + if (GetInheritedRtoL () == RightToLeft.Yes) { + XplatUI.ScrollWindow (this.Handle, new Rectangle (vscroll.Width, 0, ClientSize.Width - vscroll.Width, ClientSize.Height), old_viewport_x - this.hscroll.Value, 0, false); + } else { + XplatUI.ScrollWindow (this.Handle, new Rectangle (0, 0, ClientSize.Width - vscroll.Width, ClientSize.Height), old_viewport_x - this.hscroll.Value, 0, false); + } + } else { + XplatUI.ScrollWindow(this.Handle, ClientRectangle, old_viewport_x - this.hscroll.Value, 0, false); + } + + ScrollLinks (old_viewport_x - this.hscroll.Value, 0); + + if (Focused) + document.CaretHasFocus (); + + EventHandler eh = (EventHandler)(Events [HScrolledEvent]); + if (eh != null) + eh (this, EventArgs.Empty); + } + + private void vscroll_ValueChanged (object sender, EventArgs e) + { + int old_viewport_y; + + old_viewport_y = document.ViewPortY; + document.ViewPortY = this.vscroll.Value; + + // + // Before scrolling we want to destroy the caret, then draw a new one after the scroll + // the reason for this is that scrolling changes the coordinates of the caret, and we + // will get tracers if we don't + // + if (Focused) + document.CaretLostFocus (); + + if (hscroll.Visible) { + XplatUI.ScrollWindow(this.Handle, new Rectangle(0, 0, ClientSize.Width, ClientSize.Height - hscroll.Height), 0, old_viewport_y - this.vscroll.Value, false); + } else { + XplatUI.ScrollWindow(this.Handle, ClientRectangle, 0, old_viewport_y - this.vscroll.Value, false); + } + + ScrollLinks (0, old_viewport_y - this.vscroll.Value); + + if (Focused) + document.CaretHasFocus (); + + EventHandler eh = (EventHandler)(Events [VScrolledEvent]); + if (eh != null) + eh (this, EventArgs.Empty); + } + + private void TextBoxBase_MouseMove (object sender, MouseEventArgs e) + { + // FIXME - handle auto-scrolling if mouse is to the right/left of the window + if (e.Button == MouseButtons.Left && Capture) { + if (!ClientRectangle.Contains (e.X, e.Y)) { + if (scroll_timer == null) { + scroll_timer = new Timer (); + scroll_timer.Interval = 100; + scroll_timer.Tick += new EventHandler (ScrollTimerTickHandler); + } + + if (!scroll_timer.Enabled) { + scroll_timer.Start (); + + // Force the first tick + ScrollTimerTickHandler (null, EventArgs.Empty); + } + } + + document.PositionCaret(e.X + document.ViewPortX, e.Y + document.ViewPortY); + if (click_mode == CaretSelection.Position) { + document.SetSelectionToCaret(false); + document.DisplayCaret(); + } + } + + //search through link boxes to see if the mouse is over one of them + + bool found_link = false; + foreach (LinkRectangle link in list_links) { + if (link.LinkAreaRectangle.Contains (e.X, e.Y)) { + XplatUI.SetCursor (window.Handle, Cursors.Hand.handle); + + found_link = true; + current_link = link; + break; + } + } + + if (found_link == false) { + XplatUI.SetCursor (window.Handle, DefaultCursor.handle); + current_link = null; + } + } + + private void TextBoxBase_FontOrColorChanged (object sender, EventArgs e) + { + Line line; + + document.SuspendRecalc (); + // Font changes apply to the whole document + for (int i = 1; i <= document.Lines; i++) { + line = document.GetLine(i); + if (LineTag.FormatText(line, 1, line.text.Length, Font, ForeColor, + Color.Empty, FormatSpecified.Font | FormatSpecified.Color)) + document.RecalculateDocument (CreateGraphicsInternal (), line.LineNo, line.LineNo, false); + } + document.ResumeRecalc (false); + + // Make sure the caret height is matching the new font height + document.AlignCaret(); + } + + private void ScrollTimerTickHandler (object sender, EventArgs e) + { + Point pt = Cursor.Position; + + pt = PointToClient (pt); + + if (pt.X < ClientRectangle.Left) { + document.MoveCaret(CaretDirection.CharBackNoWrap); + document.SetSelectionToCaret(false); + + CaretMoved(this, null); + } else if (pt.X > ClientRectangle.Right) { + document.MoveCaret(CaretDirection.CharForwardNoWrap); + document.SetSelectionToCaret(false); + + CaretMoved(this, null); + } else if (pt.Y > ClientRectangle.Bottom) { + document.MoveCaret(CaretDirection.LineDown); + document.SetSelectionToCaret(false); + + CaretMoved(this, null); + } else if (pt.Y < ClientRectangle.Top) { + document.MoveCaret(CaretDirection.LineUp); + document.SetSelectionToCaret(false); + + CaretMoved(this, null); + } + } + + /// Ensure the caret is always visible + internal void CaretMoved (object sender, EventArgs e) + { + Point pos; + int height; + + if (!IsHandleCreated || canvas_width < 1 || canvas_height < 1) + return; + + document.MoveCaretToTextTag (); + pos = document.Caret; + + //Console.WriteLine("Caret now at {0} (Thumb: {1}x{2}, Canvas: {3}x{4}, Document {5}x{6})", pos, hscroll.Value, vscroll.Value, canvas_width, canvas_height, document.Width, document.Height); + + + // Horizontal scrolling: + // If the caret moves to the left outside the visible area, we jump the document into view, not just one + // character, but 1/3 of the width of the document + // If the caret moves to the right outside the visible area, we scroll just enough to keep the caret visible + + // Handle horizontal scrolling + if (document.CaretLine.alignment == HorizontalAlignment.Left) { + // Check if we moved out of view to the left + if (pos.X < (document.ViewPortX)) { + do { + if ((hscroll.Value - document.ViewPortWidth / 3) >= hscroll.Minimum) { + hscroll.SafeValueSet (hscroll.Value - document.ViewPortWidth / 3); + } else { + hscroll.Value = hscroll.Minimum; + } + } while (hscroll.Value > pos.X); + } + + // Check if we moved out of view to the right + if ((pos.X >= (document.ViewPortWidth + document.ViewPortX)) && (hscroll.Value != hscroll.Maximum)) { + if ((pos.X - document.ViewPortWidth + 1) <= hscroll.Maximum) { + if (pos.X - document.ViewPortWidth >= 0) { + hscroll.SafeValueSet (pos.X - document.ViewPortWidth + 1); + } else { + hscroll.Value = 0; + } + } else { + hscroll.Value = hscroll.Maximum; + } + } + } else if (document.CaretLine.alignment == HorizontalAlignment.Right) { +// hscroll.Value = pos.X; + +// if ((pos.X > (this.canvas_width + document.ViewPortX)) && (hscroll.Enabled && (hscroll.Value != hscroll.Maximum))) { +// hscroll.Value = hscroll.Maximum; +// } + } else { + // FIXME - implement center cursor alignment + } + + if (Text.Length > 0) + RaiseSelectionChanged (); + + if (!document.multiline) + return; + + // Handle vertical scrolling + height = document.CaretLine.Height + 1; + + if (pos.Y < document.ViewPortY) + vscroll.SafeValueSet (pos.Y); + if ((pos.Y + height) > (document.ViewPortY + canvas_height)) + vscroll.Value = Math.Min (vscroll.Maximum, pos.Y - canvas_height + height); + } + + internal bool Paste (IDataObject clip, DataFormats.Format format, bool obey_length) + { + string s; + + if (clip == null) + return false; + + if (format == null) { + if ((this is RichTextBox) && clip.GetDataPresent(DataFormats.Rtf)) { + format = DataFormats.GetFormat(DataFormats.Rtf); + } else if ((this is RichTextBox) && clip.GetDataPresent (DataFormats.Bitmap)) { + format = DataFormats.GetFormat (DataFormats.Bitmap); + } else if (clip.GetDataPresent(DataFormats.UnicodeText)) { + format = DataFormats.GetFormat(DataFormats.UnicodeText); + } else if (clip.GetDataPresent(DataFormats.Text)) { + format = DataFormats.GetFormat(DataFormats.Text); + } else { + return false; + } + } else { + if ((format.Name == DataFormats.Rtf) && !(this is RichTextBox)) { + return false; + } + + if (!clip.GetDataPresent(format.Name)) { + return false; + } + } + + if (format.Name == DataFormats.Rtf) { + document.undo.BeginUserAction (String.Format ("Paste")); + ((RichTextBox)this).SelectedRtf = (string)clip.GetData(DataFormats.Rtf); + document.undo.EndUserAction (); + Modified = true; + return true; + } else if (format.Name == DataFormats.Bitmap) { + document.undo.BeginUserAction (String.Format ("Paste")); + // document.InsertImage (document.caret.line, document.caret.pos, (Image) clip.GetData (DataFormats.Bitmap)); + document.MoveCaret (CaretDirection.CharForward); + document.undo.EndUserAction (); + return true; + } else if (format.Name == DataFormats.UnicodeText) { + s = (string)clip.GetData(DataFormats.UnicodeText); + } else if (format.Name == DataFormats.Text) { + s = (string)clip.GetData(DataFormats.Text); + } else { + return false; + } + + if (!obey_length) { + document.undo.BeginUserAction (String.Format ("Paste")); + this.SelectedText = s; + document.undo.EndUserAction (); + } else { + if ((s.Length + (document.Length - SelectedText.Length)) < max_length) { + document.undo.BeginUserAction (String.Format ("Paste")); + this.SelectedText = s; + document.undo.EndUserAction (); + } else if ((document.Length - SelectedText.Length) < max_length) { + document.undo.BeginUserAction (String.Format ("Paste")); + this.SelectedText = s.Substring (0, max_length - (document.Length - SelectedText.Length)); + document.undo.EndUserAction (); + } + } + + Modified = true; + return true; + } + + internal virtual Color ChangeBackColor (Color backColor) + { + return backColor; + } + + internal override bool IsInputCharInternal (char charCode) + { + return true; + } + #endregion // Private Methods + + #region Private Classes + internal class LinkRectangle { + private Rectangle link_area_rectangle; + private LineTag link_tag; + + public LinkRectangle (Rectangle rect) + { + link_tag = null; + link_area_rectangle = rect; + } + + public Rectangle LinkAreaRectangle { + get { return link_area_rectangle; } + set { link_area_rectangle = value; } + } + + public LineTag LinkTag { + get { return link_tag; } + set { link_tag = value; } + } + + public void Scroll (int x_change, int y_change) + { + link_area_rectangle.X += x_change; + link_area_rectangle.Y += y_change; + } + } + #endregion + + // This is called just before OnTextChanged is called. + internal virtual void OnTextUpdate () + { + } + + protected override void OnTextChanged (EventArgs e) + { + base.OnTextChanged (e); + } + + public virtual int GetLineFromCharIndex (int index) + { + Line line_out; + LineTag tag_out; + int pos; + + document.CharIndexToLineTag (index, out line_out, out tag_out, out pos); + + return line_out.LineNo; + } + + protected override void OnMouseUp (MouseEventArgs mevent) + { + base.OnMouseUp (mevent); + } + } +} diff --git a/source/ShiftUI/Widgets/TrackBar.cs b/source/ShiftUI/Widgets/TrackBar.cs new file mode 100644 index 0000000..a0952a8 --- /dev/null +++ b/source/ShiftUI/Widgets/TrackBar.cs @@ -0,0 +1,907 @@ +// +// ShiftUI.TrackBar.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Copyright (c) 2004-2006 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, jordi@ximian.com +// Rolf Bjarne Kvinge, RKvinge@novell.com +// +// TODO: +// - The AutoSize functionality seems quite broken for vertical Widgets in .Net 1.1. Not +// sure if we are implementing it the right way. +// + +// NOT COMPLETE + +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Drawing.Imaging; +using System.Drawing.Drawing2D; +using System.Timers; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI +{ + [DefaultBindingProperty ("Value")] + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + //[Designer("ShiftUI.Design.TrackBarDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [DefaultEvent ("Scroll")] + [DefaultProperty("Value")] + [ToolboxWidget] + public class TrackBar : Widget, ISupportInitialize + { + private int minimum; + private int maximum; + internal int tickFrequency; + private bool autosize; + private int position; + private int smallChange; + private int largeChange; + private Orientation orientation; + private TickStyle tickStyle; + private Rectangle thumb_pos = new Rectangle (); /* Current position and size of the thumb */ + private Rectangle thumb_area = new Rectangle (); /* Area where the thumb can scroll */ + internal bool thumb_pressed = false; + private System.Timers.Timer holdclick_timer = new System.Timers.Timer (); + internal int thumb_mouseclick; + private bool mouse_clickmove; + private bool is_moving_right; // which way the thumb should move when mouse is down (right=up, left=down) + internal int mouse_down_x_offset; // how far from left side of thumb was the mouse clicked. + internal bool mouse_moved; // has the mouse moved since it was clicked? + private const int size_of_autosize = 45; + private bool right_to_left_layout; + bool thumb_entered; + + #region events + //[EditorBrowsable (EditorBrowsableState.Always)] + [Browsable (true)] + public new event EventHandler AutoSizeChanged { + add {base.AutoSizeChanged += value;} + remove {base.AutoSizeChanged -= value;} + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageChanged { + add { base.BackgroundImageChanged += value; } + remove { base.BackgroundImageChanged -= value; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public new event EventHandler BackgroundImageLayoutChanged + { + add { base.BackgroundImageLayoutChanged += value; } + remove { base.BackgroundImageLayoutChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler Click { + add { base.Click += value; } + remove { base.Click -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler DoubleClick { + add { base.DoubleClick += value; } + remove { base.DoubleClick -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler FontChanged { + add { base.FontChanged += value; } + remove { base.FontChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler ForeColorChanged { + add { base.ForeColorChanged += value; } + remove { base.ForeColorChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler ImeModeChanged { + add { base.ImeModeChanged += value; } + remove { base.ImeModeChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event MouseEventHandler MouseClick { + add {base.MouseClick += value;} + remove {base.MouseClick -= value;} + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event MouseEventHandler MouseDoubleClick + { + add { base.MouseDoubleClick += value; } + remove { base.MouseDoubleClick -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler PaddingChanged + { + add { base.PaddingChanged += value; } + remove { base.PaddingChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event PaintEventHandler Paint { + add { base.Paint += value; } + remove { base.Paint -= value; } + } + + public event EventHandler RightToLeftLayoutChanged { + add {Events.AddHandler (RightToLeftLayoutChangedEvent, value);} + remove {Events.RemoveHandler (RightToLeftLayoutChangedEvent, value);} + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + + static object RightToLeftLayoutChangedEvent = new object (); + static object ScrollEvent = new object (); + static object ValueChangedEvent = new object (); + + public event EventHandler Scroll { + add { Events.AddHandler (ScrollEvent, value); } + remove { Events.RemoveHandler (ScrollEvent, value); } + } + + public event EventHandler ValueChanged { + add { Events.AddHandler (ValueChangedEvent, value); } + remove { Events.RemoveHandler (ValueChangedEvent, value); } + } + + #endregion // Events + + #region UIA FrameWork Events + static object UIAValueParamChangedEvent = new object (); + + internal event EventHandler UIAValueParamChanged { + add { Events.AddHandler (UIAValueParamChangedEvent, value); } + remove { Events.RemoveHandler (UIAValueParamChangedEvent, value); } + } + + internal void OnUIAValueParamChanged () + { + EventHandler eh = (EventHandler) Events [UIAValueParamChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + #endregion + + public TrackBar () + { + orientation = Orientation.Horizontal; + minimum = 0; + maximum = 10; + tickFrequency = 1; + autosize = true; + position = 0; + tickStyle = TickStyle.BottomRight; + smallChange = 1; + largeChange = 5; + mouse_clickmove = false; + MouseDown += new MouseEventHandler (OnMouseDownTB); + MouseUp += new MouseEventHandler (OnMouseUpTB); + MouseMove += new MouseEventHandler (OnMouseMoveTB); + MouseLeave += new EventHandler (OnMouseLeave); + KeyDown += new KeyEventHandler (OnKeyDownTB); + LostFocus += new EventHandler (OnLostFocusTB); + GotFocus += new EventHandler (OnGotFocusTB); + holdclick_timer.Elapsed += new ElapsedEventHandler (OnFirstClickTimer); + + SetStyle (Widgetstyles.UserPaint | Widgetstyles.Opaque | Widgetstyles.UseTextForAccessibility, false); + } + + #region Private & Internal Properties + internal Rectangle ThumbPos { + get { + return thumb_pos; + } + + set { + thumb_pos = value; + } + } + + internal Rectangle ThumbArea { + get { + return thumb_area; + } + + set { + thumb_area = value; + } + } + + internal bool ThumbEntered { + get { return thumb_entered; } + set { + if (thumb_entered == value) + return; + thumb_entered = value; + if (ThemeEngine.Current.TrackBarHasHotThumbStyle) + Invalidate (GetRealThumbRectangle ()); + } + } + #endregion // Private & Internal Properties + + #region Public Properties + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)] + [DefaultValue (true)] + public override bool AutoSize { + get { return autosize; } + set { autosize = value;} + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public override Image BackgroundImage { + get { return base.BackgroundImage; } + set { base.BackgroundImage = value; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public override ImageLayout BackgroundImageLayout { + get { + return base.BackgroundImageLayout; + } + set { + base.BackgroundImageLayout = value; + } + } + + protected override CreateParams CreateParams { + get { + return base.CreateParams; + } + } + + protected override ImeMode DefaultImeMode { + get {return ImeMode.Disable; } + } + + protected override Size DefaultSize { + get { return ThemeEngine.Current.TrackBarDefaultSize; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + protected override bool DoubleBuffered { + get { + return base.DoubleBuffered; + } + set { + base.DoubleBuffered = value; + } + } + + [Browsable(false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override Font Font { + get { return base.Font; } + set { base.Font = value; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public override Color ForeColor { + get { return base.ForeColor; } + set { base.ForeColor = value; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public new ImeMode ImeMode { + get { return base.ImeMode; } + set { base.ImeMode = value; } + } + + [DefaultValue (5)] + public int LargeChange + { + get { return largeChange; } + set { + if (value < 0) + throw new ArgumentOutOfRangeException (string.Format ("Value '{0}' must be greater than or equal to 0.", value)); + + largeChange = value; + + OnUIAValueParamChanged (); + } + } + + [DefaultValue (10)] + [RefreshProperties (RefreshProperties.All)] + public int Maximum { + get { return maximum; } + set { + if (maximum != value) { + maximum = value; + + if (maximum < minimum) + minimum = maximum; + + Refresh (); + + OnUIAValueParamChanged (); + } + } + } + + [DefaultValue (0)] + [RefreshProperties (RefreshProperties.All)] + public int Minimum { + get { return minimum; } + set { + + if (Minimum != value) { + minimum = value; + + if (minimum > maximum) + maximum = minimum; + + Refresh (); + + OnUIAValueParamChanged (); + } + } + } + + [DefaultValue (Orientation.Horizontal)] + [Localizable (true)] + public Orientation Orientation { + get { return orientation; } + set { + if (!Enum.IsDefined (typeof (Orientation), value)) + throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for Orientation", value)); + + /* Orientation can be changed once the control has been created */ + if (orientation != value) { + orientation = value; + + if (this.IsHandleCreated) { + Size = new Size (Height, Width); + Refresh (); + } + } + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new Padding Padding { + get { + return base.Padding; + } + set { + base.Padding = value; + } + } + + [Localizable (true)] + [DefaultValue (false)] + public virtual bool RightToLeftLayout { + get { + return right_to_left_layout; + } + set { + if (value != right_to_left_layout) { + right_to_left_layout = value; + OnRightToLeftLayoutChanged (EventArgs.Empty); + } + } + } + + [DefaultValue (1)] + public int SmallChange { + get { return smallChange;} + set { + if (value < 0) + throw new ArgumentOutOfRangeException (string.Format ("Value '{0}' must be greater than or equal to 0.", value)); + + if (smallChange != value) { + smallChange = value; + + OnUIAValueParamChanged (); + } + } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Bindable (false)] + [Browsable (false)] + public override string Text { + get { return base.Text; } + set { base.Text = value; } + } + + [DefaultValue (1)] + public int TickFrequency { + get { return tickFrequency; } + set { + if ( value > 0 ) { + tickFrequency = value; + Refresh (); + } + } + } + + [DefaultValue (TickStyle.BottomRight)] + public TickStyle TickStyle { + get { return tickStyle; } + set { + if (!Enum.IsDefined (typeof (TickStyle), value)) + throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for TickStyle", value)); + + if (tickStyle != value) { + tickStyle = value; + Refresh (); + } + } + } + + [DefaultValue (0)] + [Bindable (true)] + public int Value { + get { return position; } + set { + SetValue (value, false); + } + } + + void SetValue (int value, bool fire_onscroll) + { + if (value < Minimum || value > Maximum) + throw new ArgumentException( + String.Format ("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value)); + + if (position == value) + return; + + position = value; + + // OnScroll goes before OnValueChanged + if (fire_onscroll) + OnScroll (EventArgs.Empty); + + // XXX any reason we don't call OnValueChanged here? + EventHandler eh = (EventHandler)(Events [ValueChangedEvent]); + if (eh != null) + eh (this, EventArgs.Empty); + + Invalidate (thumb_area); + } + + #endregion //Public Properties + + #region Public Methods + + public void BeginInit () + { + + } + + protected override void CreateHandle () + { + base.CreateHandle (); + } + + protected override void SetBoundsCore (int x, int y,int width, int height, BoundsSpecified specified) + { + if (AutoSize) { + if (orientation == Orientation.Vertical) { + width = size_of_autosize; + } else { + height = size_of_autosize; + } + } + base.SetBoundsCore (x, y, width, height, specified); + } + + public void EndInit () + { + + } + + protected override bool IsInputKey (Keys keyData) + { + if ((keyData & Keys.Alt) == 0) { + switch (keyData & Keys.KeyCode) { + case Keys.Down: + case Keys.Right: + case Keys.Up: + case Keys.Left: + case Keys.PageUp: + case Keys.PageDown: + case Keys.Home: + case Keys.End: + return true; + } + } + return base.IsInputKey (keyData); + } + + protected override void OnBackColorChanged (EventArgs e) + { + base.OnBackColorChanged (e); + } + + protected override void OnHandleCreated (EventArgs e) + { + base.OnHandleCreated (e); + + if (AutoSize) + if (Orientation == Orientation.Horizontal) + Size = new Size (Width, 40); + else + Size = new Size (50, Height); + + UpdatePos (Value, true); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void OnMouseWheel (MouseEventArgs e) + { + base.OnMouseWheel (e); + + if (!Enabled) return; + + if (e.Delta > 0) + SmallDecrement (); + else + SmallIncrement (); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnRightToLeftLayoutChanged (EventArgs e) + { + EventHandler eh = (EventHandler)Events [RightToLeftLayoutChangedEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnScroll (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [ScrollEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnSystemColorsChanged (EventArgs e) + { + base.OnSystemColorsChanged (e); + Invalidate (); + } + + protected virtual void OnValueChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [ValueChangedEvent]); + if (eh != null) + eh (this, e); + } + + public void SetRange (int minValue, int maxValue) + { + Minimum = minValue; + Maximum = maxValue; + } + + public override string ToString() + { + return string.Format("ShiftUI.TrackBar, Minimum: {0}, Maximum: {1}, Value: {2}", + Minimum, Maximum, Value); + } + + + protected override void WndProc (ref Message m) + { + base.WndProc (ref m); + + // Basically we want Widgetstyles.ResizeRedraw but + // tests say we can't set that flag + if ((Msg)m.Msg == Msg.WM_WINDOWPOSCHANGED && Visible) + Invalidate (); + } + + #endregion Public Methods + + #region Private Methods + + private void UpdatePos (int newPos, bool update_trumbpos) + { + if (newPos < minimum){ + SetValue (minimum, true); + } + else { + if (newPos > maximum) { + SetValue (maximum, true); + } + else { + SetValue (newPos, true); + } + } + } + + // Used by UIA implementation, so making internal + internal void LargeIncrement () + { + UpdatePos (position + LargeChange, true); + Invalidate (thumb_area); + } + + // Used by UIA implementation, so making internal + internal void LargeDecrement () + { + UpdatePos (position - LargeChange, true); + Invalidate (thumb_area); + } + + private void SmallIncrement () + { + UpdatePos (position + SmallChange, true); + Invalidate (thumb_area); + } + + private void SmallDecrement () + { + UpdatePos (position - SmallChange, true); + Invalidate (thumb_area); + } + + private void OnMouseUpTB (object sender, MouseEventArgs e) + { + if (!Enabled) return; + + if (thumb_pressed == true || mouse_clickmove == true) { + thumb_pressed = false; + holdclick_timer.Enabled = false; + this.Capture = false; + Invalidate (thumb_area); + } + } + + private void OnMouseDownTB (object sender, MouseEventArgs e) + { + if (!Enabled) return; + + mouse_moved = false; + + bool fire_timer = false; + + Point point = new Point (e.X, e.Y); + + if (orientation == Orientation.Horizontal) { + + if (thumb_pos.Contains (point)) { + this.Capture = true; + thumb_pressed = true; + thumb_mouseclick = e.X; + mouse_down_x_offset = e.X - thumb_pos.X; + Invalidate (thumb_area); + } + else { + if (thumb_area.Contains (point)) { + is_moving_right = e.X > thumb_pos.X + thumb_pos.Width; + if (is_moving_right) + LargeIncrement (); + else + LargeDecrement (); + + Invalidate (thumb_area); + fire_timer = true; + mouse_clickmove = true; + } + } + } + else { + Rectangle vertical_thumb_pos = thumb_pos; + vertical_thumb_pos.Width = thumb_pos.Height; + vertical_thumb_pos.Height = thumb_pos.Width; + if (vertical_thumb_pos.Contains (point)) { + this.Capture = true; + thumb_pressed = true; + thumb_mouseclick = e.Y; + mouse_down_x_offset = e.Y - thumb_pos.Y; + Invalidate (thumb_area); + } + else { + if (thumb_area.Contains (point)) { + is_moving_right = e.Y > thumb_pos.Y + thumb_pos.Width; + if (is_moving_right) + LargeDecrement (); + else + LargeIncrement (); + + Invalidate (thumb_area); + fire_timer = true; + mouse_clickmove = true; + } + } + } + + if (fire_timer) { + holdclick_timer.Interval = 300; + holdclick_timer.Enabled = true; + } + } + + private void OnMouseMoveTB (object sender, MouseEventArgs e) + { + if (!Enabled) return; + + mouse_moved = true; + + /* Moving the thumb */ + if (thumb_pressed) + SetValue (ThemeEngine.Current.TrackBarValueFromMousePosition (e.X, e.Y, this), true); + + ThumbEntered = GetRealThumbRectangle ().Contains (e.Location); + } + + Rectangle GetRealThumbRectangle () + { + Rectangle result = thumb_pos; + if (Orientation == Orientation.Vertical) { + result.Width = thumb_pos.Height; + result.Height = thumb_pos.Width; + } + return result; + } + + internal override void OnPaintInternal (PaintEventArgs pevent) + { + ThemeEngine.Current.DrawTrackBar (pevent.Graphics, pevent.ClipRectangle, this); + } + + private void OnLostFocusTB (object sender, EventArgs e) + { + Invalidate(); + } + + private void OnGotFocusTB (object sender, EventArgs e) + { + Invalidate(); + } + private void OnKeyDownTB (object sender, KeyEventArgs e) + { + bool horiz = Orientation == Orientation.Horizontal; + switch (e.KeyCode) { + + case Keys.Down: + case Keys.Right: + if(horiz) + SmallIncrement(); + else + SmallDecrement (); + break; + + case Keys.Up: + case Keys.Left: + if (horiz) + SmallDecrement(); + else + SmallIncrement(); + break; + + case Keys.PageUp: + if (horiz) + LargeDecrement(); + else + LargeIncrement(); + break; + + case Keys.PageDown: + if (horiz) + LargeIncrement(); + else + LargeDecrement(); + break; + + case Keys.Home: + if (horiz) + SetValue (Minimum, true); + else + SetValue (Maximum, true); + break; + + case Keys.End: + if (horiz) + SetValue (Maximum, true); + else + SetValue (Minimum, true); + break; + + default: + break; + } + } + + private void OnFirstClickTimer (Object source, ElapsedEventArgs e) + { + Point pnt; + pnt = PointToClient (MousePosition); + /* + On Win32 the thumb only moves in one direction after a click, + if the thumb passes the clicked point it will never go in the + other way unless the mouse is released and clicked again. This + is also true if the mouse moves while beeing hold down. + */ + + if (thumb_area.Contains (pnt)) { + bool invalidate = false; + if (orientation == Orientation.Horizontal) { + if (pnt.X > thumb_pos.X + thumb_pos.Width && is_moving_right) { + LargeIncrement (); + invalidate = true; + } else if (pnt.X < thumb_pos.X && !is_moving_right) { + LargeDecrement (); + invalidate = true; + } + } else { + if (pnt.Y > thumb_pos.Y + thumb_pos.Width && is_moving_right) { + LargeDecrement (); + invalidate = true; + } else if (pnt.Y < thumb_pos.Y && !is_moving_right) { + LargeIncrement (); + invalidate = true; + } + } + if (invalidate) + // A Refresh is necessary because the mouse is down and if we just invalidate + // we'll only get paint events once in a while. + Refresh(); + } + } + + void OnMouseLeave (object sender, EventArgs e) + { + ThumbEntered = false; + } + #endregion // Private Methods + } +} + diff --git a/source/ShiftUI/Widgets/TreeNode.cs b/source/ShiftUI/Widgets/TreeNode.cs new file mode 100644 index 0000000..0a4a13b --- /dev/null +++ b/source/ShiftUI/Widgets/TreeNode.cs @@ -0,0 +1,1087 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// Kazuki Oikawa (kazuki@panicode.com) + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Runtime.Serialization; +using System.Text; + +namespace ShiftUI +{ + [DefaultProperty ("Text")] + [TypeConverter(typeof(TreeNodeConverter))] + [Serializable] + public class TreeNode : MarshalByRefObject, ICloneable, ISerializable + { + #region Fields + private TreeView tree_view; + internal TreeNode parent; + + private string text; + private int image_index = -1; + private int selected_image_index = -1; + private ContextMenuStrip context_menu_strip; + private string image_key = String.Empty; + private string selected_image_key = String.Empty; + private int state_image_index = -1; + private string state_image_key = String.Empty; + private string tool_tip_text = String.Empty; + internal TreeNodeCollection nodes; + internal TreeViewAction check_reason = TreeViewAction.Unknown; + + internal int visible_order = 0; + internal int width = -1; + + internal bool is_expanded = false; + private bool check; + internal OwnerDrawPropertyBag prop_bag; + + private object tag; + + internal IntPtr handle; + + private string name = string.Empty; + #endregion // Fields + + #region Internal Constructors + internal TreeNode (TreeView tree_view) : this () + { + this.tree_view = tree_view; + is_expanded = true; + } + + protected TreeNode (SerializationInfo serializationInfo, StreamingContext context) : this () + { + SerializationInfoEnumerator en; + SerializationEntry e; + int children; + + en = serializationInfo.GetEnumerator(); + children = 0; + while (en.MoveNext()) { + e = en.Current; + switch(e.Name) { + case "Text": Text = (string)e.Value; break; + case "PropBag": prop_bag = (OwnerDrawPropertyBag)e.Value; break; + case "ImageIndex": image_index = (int)e.Value; break; + case "SelectedImageIndex": selected_image_index = (int)e.Value; break; + case "Tag": tag = e.Value; break; + case "IsChecked": check = (bool)e.Value; break; + case "ChildCount": children = (int)e.Value; break; + } + } + if (children > 0) { + for (int i = 0; i < children; i++) { + TreeNode node = (TreeNode) serializationInfo.GetValue ("children" + i, typeof (TreeNode)); + Nodes.Add (node); + } + } + } + #endregion // Internal Constructors + + #region Public Constructors + public TreeNode () + { + nodes = new TreeNodeCollection (this); + } + + public TreeNode (string text) : this () + { + Text = text; + } + + public TreeNode (string text, TreeNode [] children) : this (text) + { + Nodes.AddRange (children); + } + + public TreeNode (string text, int imageIndex, int selectedImageIndex) : this (text) + { + this.image_index = imageIndex; + this.selected_image_index = selectedImageIndex; + } + + public TreeNode (string text, int imageIndex, int selectedImageIndex, + TreeNode[] children) + : this (text, imageIndex, selectedImageIndex) + { + Nodes.AddRange (children); + } + + #endregion // Public Constructors + + #region ICloneable Members + public virtual object Clone () + { + TreeNode tn = (TreeNode)Activator.CreateInstance (GetType ()); + tn.name = name; + tn.text = text; + tn.image_key = image_key; + tn.image_index = image_index; + tn.selected_image_index = selected_image_index; + tn.selected_image_key = selected_image_key; + tn.state_image_index = state_image_index; + tn.state_image_key = state_image_key; + tn.tag = tag; + tn.check = check; + tn.tool_tip_text = tool_tip_text; + tn.context_menu_strip = context_menu_strip; + if (nodes != null) { + foreach (TreeNode child in nodes) + tn.nodes.Add ((TreeNode)child.Clone ()); + } + if (prop_bag != null) + tn.prop_bag = OwnerDrawPropertyBag.Copy (prop_bag); + return tn; + } + + #endregion // ICloneable Members + + #region ISerializable Members + void ISerializable.GetObjectData (SerializationInfo si, StreamingContext context) + { + si.AddValue ("Text", Text); + si.AddValue ("prop_bag", prop_bag, typeof (OwnerDrawPropertyBag)); + si.AddValue ("ImageIndex", ImageIndex); + si.AddValue ("SelectedImageIndex", SelectedImageIndex); + si.AddValue ("Tag", Tag); + si.AddValue ("Checked", Checked); + + si.AddValue ("NumberOfChildren", Nodes.Count); + for (int i = 0; i < Nodes.Count; i++) + si.AddValue ("Child-" + i, Nodes [i], typeof (TreeNode)); + } + + protected virtual void Deserialize (SerializationInfo serializationInfo, StreamingContext context) + { + Text = serializationInfo.GetString ("Text"); + prop_bag = (OwnerDrawPropertyBag)serializationInfo.GetValue ("prop_bag", typeof (OwnerDrawPropertyBag)); + ImageIndex = serializationInfo.GetInt32 ("ImageIndex"); + SelectedImageIndex = serializationInfo.GetInt32 ("SelectedImageIndex"); + Tag = serializationInfo.GetValue ("Tag", typeof (Object)); + Checked = serializationInfo.GetBoolean ("Checked"); + + int count = serializationInfo.GetInt32 ("NumberOfChildren"); + + for (int i = 0; i < count; i++) + Nodes.Add ((TreeNode)serializationInfo.GetValue ("Child-" + i, typeof (TreeNode))); + } + + protected virtual void Serialize (SerializationInfo si, StreamingContext context) + { + si.AddValue ("Text", Text); + si.AddValue ("prop_bag", prop_bag, typeof (OwnerDrawPropertyBag)); + si.AddValue ("ImageIndex", ImageIndex); + si.AddValue ("SelectedImageIndex", SelectedImageIndex); + si.AddValue ("Tag", Tag); + si.AddValue ("Checked", Checked); + + si.AddValue ("NumberOfChildren", Nodes.Count); + for (int i = 0; i < Nodes.Count; i++) + si.AddValue ("Child-" + i, Nodes[i], typeof (TreeNode)); + } + #endregion // ISerializable Members + + #region Public Instance Properties + public Color BackColor { + get { + if (prop_bag != null) + return prop_bag.BackColor; + return Color.Empty; + } + set { + if (prop_bag == null) + prop_bag = new OwnerDrawPropertyBag (); + prop_bag.BackColor = value; + + TreeView tree_view = TreeView; + if (tree_view != null) + tree_view.UpdateNode (this); + } + } + + [Browsable (false)] + public Rectangle Bounds { + get { + if (TreeView == null) + return Rectangle.Empty; + + int x = GetX (); + int y = GetY (); + + if (width == -1) + width = TreeView.GetNodeWidth (this); + + Rectangle res = new Rectangle (x, y, width, TreeView.ActualItemHeight); + return res; + } + } + + internal int GetY () + { + if (TreeView == null) + return 0; + return (visible_order - 1) * TreeView.ActualItemHeight - (TreeView.skipped_nodes * TreeView.ActualItemHeight); + } + + internal int GetX () + { + if (TreeView == null) + return 0; + int indent_level = IndentLevel; + int roots = (TreeView.ShowRootLines ? 1 : 0); + int cb = (TreeView.CheckBoxes ? 19 : 0); + if (!TreeView.CheckBoxes && StateImage != null) + cb = 19; + int imgs = (TreeView.ImageList != null ? TreeView.ImageList.ImageSize.Width + 3 : 0); + return ((indent_level + roots) * TreeView.Indent) + cb + imgs - TreeView.hbar_offset; + } + + internal int GetLinesX () + { + int roots = (TreeView.ShowRootLines ? 1 : 0); + return (IndentLevel + roots) * TreeView.Indent - TreeView.hbar_offset; + } + + internal int GetImageX () + { + return GetLinesX () + (TreeView.CheckBoxes || StateImage != null ? 19 : 0); + } + + // In theory we should be able to track this instead of computing + // every single time we need it, however for now I am going to + // do it this way to reduce bugs in my new bounds computing code + internal int IndentLevel { + get { + TreeNode walk = this; + int res = 0; + while (walk.Parent != null) { + walk = walk.Parent; + res++; + } + + return res; + } + } + + [DefaultValue (false)] + public bool Checked { + get { return check; } + set { + if (check == value) + return; + TreeViewCancelEventArgs args = new TreeViewCancelEventArgs (this, false, check_reason); + if (TreeView != null) + TreeView.OnBeforeCheck (args); + if (!args.Cancel) { + check = value; + + // TreeView can become null after OnAfterCheck, this the double null check + if (TreeView != null) + TreeView.OnAfterCheck (new TreeViewEventArgs (this, check_reason)); + if (TreeView != null) + TreeView.UpdateNode (this); + } + check_reason = TreeViewAction.Unknown; + } + } + + [DefaultValue (null)] + public virtual ContextMenuStrip ContextMenuStrip { + get { return context_menu_strip; } + set { context_menu_strip = value; } + } + + [Browsable (false)] + public TreeNode FirstNode { + get { + if (nodes.Count > 0) + return nodes [0]; + return null; + } + } + + public Color ForeColor { + get { + if (prop_bag != null) + return prop_bag.ForeColor; + if (TreeView != null) + return TreeView.ForeColor; + return Color.Empty; + } + set { + if (prop_bag == null) + prop_bag = new OwnerDrawPropertyBag (); + prop_bag.ForeColor = value; + + TreeView tree_view = TreeView; + if (tree_view != null) + tree_view.UpdateNode (this); + } + } + + [Browsable (false)] + public string FullPath { + get { + if (TreeView == null) + throw new InvalidOperationException ("No TreeView associated"); + + StringBuilder builder = new StringBuilder (); + BuildFullPath (builder); + return builder.ToString (); + } + } + + [DefaultValue (-1)] + [RelatedImageList ("TreeView.ImageList")] + [TypeConverter (typeof (TreeViewImageIndexConverter))] + [RefreshProperties (RefreshProperties.Repaint)] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + [Localizable(true)] + public int ImageIndex { + get { return image_index; } + set { + if (image_index == value) + return; + image_index = value; + image_key = string.Empty; + TreeView tree = TreeView; + if (tree != null) + tree.UpdateNode (this); + } + } + + [Localizable(true)] + [DefaultValue ("")] + [RelatedImageList ("TreeView.ImageList")] + [TypeConverter (typeof (TreeViewImageKeyConverter))] + [RefreshProperties (RefreshProperties.Repaint)] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + public string ImageKey { + get { return image_key; } + set { + if (image_key == value) + return; + image_key = value; + image_index = -1; + + TreeView tree = TreeView; + if (tree != null) + tree.UpdateNode(this); + } + } + + [Browsable (false)] + public bool IsEditing { + get { + TreeView tv = TreeView; + if (tv == null) + return false; + return tv.edit_node == this; + } + } + + [Browsable (false)] + public bool IsExpanded { + get { + TreeView tv = TreeView; + + if (tv != null && tv.IsHandleCreated) { + // This is ridiculous + bool found = false; + foreach (TreeNode walk in TreeView.Nodes) { + if (walk.Nodes.Count > 0) + found = true; + } + + if (!found) + return false; + } + + return is_expanded; + } + } + + [Browsable (false)] + public bool IsSelected { + get { + if (TreeView == null || !TreeView.IsHandleCreated) + return false; + return TreeView.SelectedNode == this; + } + } + + [Browsable (false)] + public bool IsVisible { + get { + if (TreeView == null || !TreeView.IsHandleCreated || !TreeView.Visible) + return false; + + if (visible_order <= TreeView.skipped_nodes || visible_order - TreeView.skipped_nodes > TreeView.VisibleCount) + return false; + + return ArePreviousNodesExpanded; + } + } + + [Browsable (false)] + public TreeNode LastNode { + get { + return (nodes == null || nodes.Count == 0) ? null : nodes [nodes.Count - 1]; + } + } + + [Browsable (false)] + public int Level { + get { return IndentLevel; } + } + + public string Name + { + get { return this.name; } + set { + // Value should never be null as per spec + this.name = (value == null) ? string.Empty : value; + } + } + + [Browsable (false)] + public TreeNode NextNode { + get { + if (parent == null) + return null; + int index = Index; + if (parent.Nodes.Count > index + 1) + return parent.Nodes [index + 1]; + return null; + } + } + + [Browsable (false)] + public TreeNode NextVisibleNode { + get { + OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this); + o.MoveNext (); // move to the node itself + + if (!o.MoveNext ()) + return null; + TreeNode c = o.CurrentNode; + if (!c.IsInClippingRect) + return null; + return c; + } + } + + [DefaultValue (null)] + [Localizable (true)] + public Font NodeFont { + get { + if (prop_bag != null) + return prop_bag.Font; + if (TreeView != null) + return TreeView.Font; + return null; + } + set { + if (prop_bag == null) + prop_bag = new OwnerDrawPropertyBag (); + prop_bag.Font = value; + Invalidate (); + } + } + + [Browsable (false)] + [ListBindable (false)] + public TreeNodeCollection Nodes { + get { + if (nodes == null) + nodes = new TreeNodeCollection (this); + return nodes; + } + } + + [Browsable (false)] + public TreeNode Parent { + get { + TreeView tree_view = TreeView; + if (tree_view != null && tree_view.root_node == parent) + return null; + return parent; + } + } + + [Browsable (false)] + public TreeNode PrevNode { + get { + if (parent == null) + return null; + int index = Index; + if (index <= 0 || index > parent.Nodes.Count) + return null; + return parent.Nodes [index - 1]; + } + } + + [Browsable (false)] + public TreeNode PrevVisibleNode { + get { + OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this); + o.MovePrevious (); // move to the node itself + + if (!o.MovePrevious ()) + return null; + TreeNode c = o.CurrentNode; + if (!c.IsInClippingRect) + return null; + return c; + } + } + + [DefaultValue (-1)] + [RelatedImageList ("TreeView.ImageList")] + [TypeConverter (typeof (TreeViewImageIndexConverter))] + [RefreshProperties (RefreshProperties.Repaint)] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + [Localizable (true)] + public int SelectedImageIndex { + get { return selected_image_index; } + set { selected_image_index = value; } + } + + [Localizable (true)] + [DefaultValue ("")] + [RelatedImageList ("TreeView.ImageList")] + [TypeConverter (typeof (TreeViewImageKeyConverter))] + [RefreshProperties (RefreshProperties.Repaint)] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + public string SelectedImageKey { + get { return selected_image_key; } + set { selected_image_key = value; } + } + + [Localizable (true)] + [DefaultValue (-1)] + [RelatedImageList ("TreeView.StateImageList")] + [TypeConverter (typeof (NoneExcludedImageIndexConverter))] + [RefreshProperties (RefreshProperties.Repaint)] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + public int StateImageIndex { + get { return state_image_index; } + set { + if (state_image_index != value) { + state_image_index = value; + state_image_key = string.Empty; + Invalidate (); + } + } + } + + [Localizable (true)] + [DefaultValue ("")] + [RelatedImageList ("TreeView.StateImageList")] + [TypeConverter (typeof (ImageKeyConverter))] + [RefreshProperties (RefreshProperties.Repaint)] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + public string StateImageKey { + get { return state_image_key; } + set { + if (state_image_key != value) { + state_image_key = value; + state_image_index = -1; + Invalidate (); + } + } + } + + [Bindable(true)] + [Localizable(false)] + [TypeConverter(typeof(System.ComponentModel.StringConverter))] + [DefaultValue(null)] + public object Tag { + get { return tag; } + set { tag = value; } + } + + [Localizable(true)] + public string Text { + get { + if (text == null) + return String.Empty; + return text; + } + set { + if (text == value) + return; + text = value; + Invalidate (); + // UIA Framework Event: Text Changed + TreeView view = TreeView; + if (view != null) + view.OnUIANodeTextChanged (new TreeViewEventArgs (this)); + } + } + + [DefaultValue ("")] + [Localizable (false)] + public string ToolTipText { + get { return tool_tip_text; } + set { tool_tip_text = value; } + } + + [Browsable (false)] + public TreeView TreeView { + get { + if (tree_view != null) + return tree_view; + TreeNode walk = parent; + while (walk != null) { + if (walk.TreeView != null) + break; + walk = walk.parent; + } + if (walk == null) + return null; + return walk.TreeView; + } + } + + [Browsable (false)] + public IntPtr Handle { + get { + // MS throws a NullReferenceException if the TreeView isn't set... + if (handle == IntPtr.Zero && TreeView != null) + handle = TreeView.CreateNodeHandle (); + return handle; + } + } + + #endregion // Public Instance Properties + + + public static TreeNode FromHandle (TreeView tree, IntPtr handle) + { + if (handle == IntPtr.Zero) + return null; + // No arg checking on MS it just throws a NullRef if treeview is null + return tree.NodeFromHandle (handle); + } + + #region Public Instance Methods + public void BeginEdit () + { + TreeView tv = TreeView; + if (tv != null) + tv.BeginEdit (this); + } + + public void Collapse () + { + CollapseInternal (false); + } + + public void Collapse (bool ignoreChildren) + { + if (ignoreChildren) + Collapse (); + else + CollapseRecursive (this); + } + + public void EndEdit (bool cancel) + { + TreeView tv = TreeView; + if (!cancel && tv != null) + tv.EndEdit (this); + else if (cancel && tv != null) + tv.CancelEdit (this); + } + + public void Expand () + { + Expand (false); + } + + public void ExpandAll () + { + ExpandRecursive (this); + if(TreeView != null) + TreeView.UpdateNode (TreeView.root_node); + } + + public void EnsureVisible () + { + if (TreeView == null) + return; + + if (this.Parent != null) + ExpandParentRecursive (this.Parent); + + Rectangle bounds = Bounds; + if (bounds.Y < 0) { + TreeView.SetTop (this); + } else if (bounds.Bottom > TreeView.ViewportRectangle.Bottom) { + TreeView.SetBottom (this); + } + } + + public int GetNodeCount (bool includeSubTrees) + { + if (!includeSubTrees) + return Nodes.Count; + + int count = 0; + GetNodeCountRecursive (this, ref count); + + return count; + } + + public void Remove () + { + if (parent == null) + return; + int index = Index; + parent.Nodes.RemoveAt (index); + } + + public void Toggle () + { + if (is_expanded) + Collapse (); + else + Expand (); + } + + public override String ToString () + { + return String.Concat ("TreeNode: ", Text); + } + + #endregion // Public Instance Methods + + #region Internal & Private Methods and Properties + + internal bool ArePreviousNodesExpanded { + get { + TreeNode parent = Parent; + while (parent != null) { + if (!parent.is_expanded) + return false; + parent = parent.Parent; + } + + return true; + } + } + + internal bool IsRoot { + get { + TreeView tree_view = TreeView; + if (tree_view == null) + return false; + if (tree_view.root_node == this) + return true; + return false; + } + } + + bool BuildFullPath (StringBuilder path) + { + if (parent == null) + return false; + + if (parent.BuildFullPath (path)) + path.Append (TreeView.PathSeparator); + + path.Append (text); + return true; + } + + public int Index { + get { + if (parent == null) + return 0; + return parent.Nodes.IndexOf (this); + } + } + + private void Expand (bool byInternal) + { + if (is_expanded || nodes.Count < 1) { + is_expanded = true; + return; + } + + bool cancel = false; + TreeView tree_view = TreeView; + if (tree_view != null) { + TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Expand); + tree_view.OnBeforeExpand (e); + cancel = e.Cancel; + } + + if (!cancel) { + is_expanded = true; + int count_to_next = CountToNext (); + + if (tree_view != null) { + tree_view.OnAfterExpand (new TreeViewEventArgs (this)); + + tree_view.RecalculateVisibleOrder (this); + tree_view.UpdateScrollBars (false); + + // ExpandBelow if we affect the visible area + if (visible_order < tree_view.skipped_nodes + tree_view.VisibleCount + 1 && ArePreviousNodesExpanded) + tree_view.ExpandBelow (this, count_to_next); + } + } + } + + private void CollapseInternal (bool byInternal) + { + if (!is_expanded || nodes.Count < 1) + return; + + if (IsRoot) + return; + + bool cancel = false; + TreeView tree_view = TreeView; + if (tree_view != null) { + TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Collapse); + tree_view.OnBeforeCollapse (e); + cancel = e.Cancel; + } + + if (!cancel) { + int count_to_next = CountToNext (); + + is_expanded = false; + + if (tree_view != null) { + tree_view.OnAfterCollapse (new TreeViewEventArgs (this)); + + bool hbar_visible = tree_view.hbar.Visible; + bool vbar_visible = tree_view.vbar.Visible; + + tree_view.RecalculateVisibleOrder (this); + tree_view.UpdateScrollBars (false); + + // CollapseBelow if we affect the visible area + if (visible_order < tree_view.skipped_nodes + tree_view.VisibleCount + 1 && ArePreviousNodesExpanded) + tree_view.CollapseBelow (this, count_to_next); + if(!byInternal && HasFocusInChildren ()) + tree_view.SelectedNode = this; + + // If one or both of our scrollbars disappeared, + // invalidate everything + if ((hbar_visible & !tree_view.hbar.Visible) || (vbar_visible & !tree_view.vbar.Visible)) + tree_view.Invalidate (); + } + } + } + + private int CountToNext () + { + bool expanded = is_expanded; + is_expanded = false; + OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (this); + + TreeNode next= null; + if (walk.MoveNext () && walk.MoveNext ()) + next = walk.CurrentNode; + + is_expanded = expanded; + walk.Reset (); + walk.MoveNext (); + + int count = 0; + while (walk.MoveNext () && walk.CurrentNode != next) + count++; + + return count; + } + + private bool HasFocusInChildren() + { + if (TreeView == null) + return false; + foreach (TreeNode node in nodes) { + if(node == TreeView.SelectedNode) + return true; + if(node.HasFocusInChildren ()) + return true; + } + return false; + } + + private void ExpandRecursive (TreeNode node) + { + node.Expand (true); + foreach (TreeNode child in node.Nodes) + ExpandRecursive (child); + } + + private void ExpandParentRecursive (TreeNode node) + { + node.Expand (true); + if (node.Parent != null) + ExpandParentRecursive (node.Parent); + } + + internal void CollapseAll () + { + CollapseRecursive (this); + } + + internal void CollapseAllUncheck () + { + CollapseUncheckRecursive (this); + } + + private void CollapseRecursive (TreeNode node) + { + node.Collapse (); + foreach (TreeNode child in node.Nodes) + CollapseRecursive (child); + } + + private void CollapseUncheckRecursive (TreeNode node) + { + node.Collapse (); + node.Checked = false; + foreach (TreeNode child in node.Nodes) + CollapseUncheckRecursive (child); + } + + internal void SetNodes (TreeNodeCollection nodes) + { + this.nodes = nodes; + } + + private void GetNodeCountRecursive (TreeNode node, ref int count) + { + count += node.Nodes.Count; + foreach (TreeNode child in node.Nodes) + GetNodeCountRecursive (child, ref count); + } + + internal bool NeedsWidth { + get { return width == -1; } + } + + internal void Invalidate () + { + // invalidate width first so Bounds retrieves + // the updated value (we don't use it here however) + width = -1; + + TreeView tv = TreeView; + if (tv == null) + return; + + tv.UpdateNode (this); + } + + internal void InvalidateWidth () + { + // bounds.Width = 0; + width = -1; + } + + internal void SetWidth (int width) + { + this.width = width; + } + + internal void SetParent (TreeNode parent) + { + this.parent = parent; + } + + private bool IsInClippingRect { + get { + if (TreeView == null) + return false; + Rectangle bounds = Bounds; + if (bounds.Y < 0 && bounds.Y > TreeView.ClientRectangle.Height) + return false; + return true; + } + } + + internal Image StateImage { + get { + if (TreeView != null) { + if (TreeView.StateImageList == null) + return null; + if (state_image_index >= 0) + return TreeView.StateImageList.Images[state_image_index]; + if (state_image_key != string.Empty) + return TreeView.StateImageList.Images[state_image_key]; + } + + return null; + } + } + + // Order of operation: + // 1) Node.Image[Key|Index] + // 2) TreeView.Image[Key|Index] + // 3) First image in TreeView.ImageList + internal int Image { + get { + if (TreeView == null || TreeView.ImageList == null) + return -1; + + if (IsSelected) { + if (selected_image_index >= 0) + return selected_image_index; + if (!string.IsNullOrEmpty (selected_image_key)) + return TreeView.ImageList.Images.IndexOfKey (selected_image_key); + if (!string.IsNullOrEmpty (TreeView.SelectedImageKey)) + return TreeView.ImageList.Images.IndexOfKey (TreeView.SelectedImageKey); + if (TreeView.SelectedImageIndex >= 0) + return TreeView.SelectedImageIndex; + } else { + if (image_index >= 0) + return image_index; + if (!string.IsNullOrEmpty (image_key)) + return TreeView.ImageList.Images.IndexOfKey (image_key); + if (!string.IsNullOrEmpty (TreeView.ImageKey)) + return TreeView.ImageList.Images.IndexOfKey (TreeView.ImageKey); + if (TreeView.ImageIndex >= 0) + return TreeView.ImageIndex; + } + + if (TreeView.ImageList.Images.Count > 0) + return 0; + + return -1; + } + } + #endregion // Internal & Private Methods and Properties + } +} diff --git a/source/ShiftUI/Widgets/TreeView.cs b/source/ShiftUI/Widgets/TreeView.cs new file mode 100644 index 0000000..0e08ece --- /dev/null +++ b/source/ShiftUI/Widgets/TreeView.cs @@ -0,0 +1,2438 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Jackson Harper (jackson@ximian.com) +// Kazuki Oikawa (kazuki@panicode.com) + +using System; +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Runtime.InteropServices; + +namespace ShiftUI { + [ComVisible (true)] + [Docking (DockingBehavior.Ask)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [DefaultProperty("Nodes")] + [DefaultEvent("AfterSelect")] + //[Designer("ShiftUI.Design.TreeViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [ToolboxWidget] + public class TreeView : Widget { + #region Fields + private string path_separator = "\\"; + private int item_height = -1; + internal bool sorted; + internal TreeNode root_node; + internal bool nodes_added; + private TreeNodeCollection nodes; + + private TreeViewAction selection_action; + internal TreeNode selected_node; + private TreeNode pre_selected_node; + private TreeNode focused_node; + internal TreeNode highlighted_node; + private Rectangle mouse_rect; + private bool select_mmove; + + private ImageList image_list; + private int image_index = -1; + private int selected_image_index = -1; + + private string image_key; + private bool is_hovering; + private TreeNode mouse_click_node; + private bool right_to_left_layout; + private string selected_image_key; + private bool show_node_tool_tips; + private ImageList state_image_list; + private TreeNode tooltip_currently_showing; + private ToolTip tooltip_window; + private bool full_row_select; + private bool hot_tracking; + private int indent = 19; + + private NodeLabelEditEventArgs edit_args; + private LabelEditTextBox edit_text_box; + internal TreeNode edit_node; + + private bool checkboxes; + private bool label_edit; + private bool scrollable = true; + private bool show_lines = true; + private bool show_root_lines = true; + private bool show_plus_minus = true; + private bool hide_selection = true; + + private int max_visible_order = -1; + internal VScrollBar vbar; + internal HScrollBar hbar; + private bool vbar_bounds_set; + private bool hbar_bounds_set; + internal int skipped_nodes; + internal int hbar_offset; + + private int update_stack; + private bool update_needed; + + private Pen dash; + private Color line_color; + private StringFormat string_format; + + private int drag_begin_x = -1; + private int drag_begin_y = -1; + private long handle_count = 1; + + private TreeViewDrawMode draw_mode; + + IComparer tree_view_node_sorter; + #endregion // Fields + + #region Public Constructors + public TreeView () + { + vbar = new ImplicitVScrollBar (); + hbar = new ImplicitHScrollBar (); + + InternalBorderStyle = BorderStyle.Fixed3D; + base.background_color = ThemeEngine.Current.ColorWindow; + base.foreground_color = ThemeEngine.Current.ColorWindowText; + draw_mode = TreeViewDrawMode.Normal; + + root_node = new TreeNode (this); + root_node.Text = "ROOT NODE"; + nodes = new TreeNodeCollection (root_node); + root_node.SetNodes (nodes); + + MouseDown += new MouseEventHandler (MouseDownHandler); + MouseUp += new MouseEventHandler(MouseUpHandler); + MouseMove += new MouseEventHandler(MouseMoveHandler); + SizeChanged += new EventHandler (SizeChangedHandler); + FontChanged += new EventHandler (FontChangedHandler); + LostFocus += new EventHandler (LostFocusHandler); + GotFocus += new EventHandler (GotFocusHandler); + MouseWheel += new MouseEventHandler(MouseWheelHandler); + VisibleChanged += new EventHandler (VisibleChangedHandler); + + SetStyle (Widgetstyles.UserPaint | Widgetstyles.StandardClick | Widgetstyles.UseTextForAccessibility, false); + + string_format = new StringFormat (); + string_format.LineAlignment = StringAlignment.Center; + string_format.Alignment = StringAlignment.Center; + + vbar.Visible = false; + hbar.Visible = false; + vbar.ValueChanged += new EventHandler (VScrollBarValueChanged); + hbar.ValueChanged += new EventHandler (HScrollBarValueChanged); + + SuspendLayout (); + Widgets.AddImplicit (vbar); + Widgets.AddImplicit (hbar); + ResumeLayout (); + } + #endregion // Public Constructors + + #region Public Instance Properties + public override Color BackColor { + get { return base.BackColor;} + set { + base.BackColor = value; + + CreateDashPen (); + Invalidate (); + } + } + + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + public override Image BackgroundImage { + get { return base.BackgroundImage; } + set { base.BackgroundImage = value; } + } + + [DefaultValue(BorderStyle.Fixed3D)] + [DispId(-504)] + public BorderStyle BorderStyle { + get { return InternalBorderStyle; } + set { InternalBorderStyle = value; } + } + + [DefaultValue(false)] + public bool CheckBoxes { + get { return checkboxes; } + set { + if (value == checkboxes) + return; + checkboxes = value; + + // Match a "bug" in the MS implementation where disabling checkboxes + // collapses the entire tree, but enabling them does not affect the + // state of the tree. + if (!checkboxes) + root_node.CollapseAllUncheck (); + + Invalidate (); + + // UIA Framework Event: CheckBoxes Changed + OnUIACheckBoxesChanged (EventArgs.Empty); + } + } + + public override Color ForeColor { + get { return base.ForeColor; } + set { base.ForeColor = value; } + } + [DefaultValue(false)] + public bool FullRowSelect { + get { return full_row_select; } + set { + if (value == full_row_select) + return; + full_row_select = value; + Invalidate (); + } + } + [DefaultValue(true)] + public bool HideSelection { + get { return hide_selection; } + set { + if (hide_selection == value) + return; + hide_selection = value; + Invalidate (); + } + } + + [DefaultValue(false)] + public bool HotTracking { + get { return hot_tracking; } + set { hot_tracking = value; } + } + + [DefaultValue (-1)] + [RelatedImageList ("ImageList")] + [RefreshProperties (RefreshProperties.Repaint)] + [TypeConverter (typeof (NoneExcludedImageIndexConverter))] + //[Editor("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))] + [Localizable(true)] + public int ImageIndex { + get { return image_index; } + set { + if (value < -1) { + throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " + + "'value' must be greater than or equal to 0."); + } + if (image_index == value) + return; + image_index = value; + Invalidate (); + } + } + + [RefreshProperties (RefreshProperties.Repaint)] + [DefaultValue(null)] + public ImageList ImageList { + get { return image_list; } + set { + image_list = value; + Invalidate (); + } + } + + [Localizable(true)] + public int Indent { + get { return indent; } + set { + if (indent == value) + return; + if (value > 32000) { + throw new ArgumentException ("'" + value + "' is not a valid value for 'Indent'. " + + "'Indent' must be less than or equal to 32000"); + } + if (value < 0) { + throw new ArgumentException ("'" + value + "' is not a valid value for 'Indent'. " + + "'Indent' must be greater than or equal to 0."); + } + indent = value; + Invalidate (); + } + } + + public int ItemHeight { + get { + if (item_height == -1) + return FontHeight + 3; + return item_height; + } + set { + if (value == item_height) + return; + item_height = value; + Invalidate (); + } + } + + internal int ActualItemHeight { + get { + int res = ItemHeight; + if (ImageList != null && ImageList.ImageSize.Height > res) + res = ImageList.ImageSize.Height; + return res; + } + } + + [DefaultValue(false)] + public bool LabelEdit { + get { return label_edit; } + set { + label_edit = value; + + // UIA Framework Event: LabelEdit Changed + OnUIALabelEditChanged (EventArgs.Empty); + } + } + + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + [MergableProperty(false)] + [Localizable(true)] + public TreeNodeCollection Nodes { + get { return nodes; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public new Padding Padding { + get { return base.Padding; } + set { base.Padding = value; } + } + + [DefaultValue("\\")] + public string PathSeparator { + get { return path_separator; } + set { path_separator = value; } + } + + [Localizable (true)] + [DefaultValue (false)] + public virtual bool RightToLeftLayout { + get { return right_to_left_layout; } + set { + if (right_to_left_layout != value) { + right_to_left_layout = value; + OnRightToLeftLayoutChanged (EventArgs.Empty); + } + } + } + + [DefaultValue(true)] + public bool Scrollable { + get { return scrollable; } + set { + if (scrollable == value) + return; + scrollable = value; + UpdateScrollBars (false); + } + } + + [DefaultValue (-1)] + [RelatedImageList ("ImageList")] + [TypeConverter (typeof (NoneExcludedImageIndexConverter))] + //[Editor("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))] + [Localizable(true)] + public int SelectedImageIndex { + get { return selected_image_index; } + set { + if (value < -1) { + throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " + + "'value' must be greater than or equal to 0."); + } + UpdateNode (SelectedNode); + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public TreeNode SelectedNode { + get { + if (!IsHandleCreated) + return pre_selected_node; + return selected_node; + } + set { + if (!IsHandleCreated) { + pre_selected_node = value; + return; + } + + if (selected_node == value) { + selection_action = TreeViewAction.Unknown; + return; + } + + if (value != null) { + TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (value, false, selection_action); + OnBeforeSelect (e); + + if (e.Cancel) + return; + } + + Rectangle invalid = Rectangle.Empty; + + if (selected_node != null) { + invalid = Bloat (selected_node.Bounds); + } + if (focused_node != null) { + invalid = Rectangle.Union (invalid, + Bloat (focused_node.Bounds)); + } + + if (value != null) + invalid = Rectangle.Union (invalid, Bloat (value.Bounds)); + + highlighted_node = value; + selected_node = value; + focused_node = value; + + if (full_row_select || draw_mode != TreeViewDrawMode.Normal) { + invalid.X = 0; + invalid.Width = ViewportRectangle.Width; + } + + if (invalid != Rectangle.Empty) + Invalidate (invalid); + + // We ensure its visible after we update because + // scrolling is used for insure visible + if (selected_node != null) + selected_node.EnsureVisible (); + + if (value != null) { + OnAfterSelect (new TreeViewEventArgs (value, TreeViewAction.Unknown)); + } + selection_action = TreeViewAction.Unknown; + } + } + + private Rectangle Bloat (Rectangle rect) + { + rect.Y--; + rect.X--; + rect.Height += 2; + rect.Width += 2; + return rect; + } + + [DefaultValue(true)] + public bool ShowLines { + get { return show_lines; } + set { + if (show_lines == value) + return; + show_lines = value; + Invalidate (); + } + } + + [DefaultValue (false)] + public bool ShowNodeToolTips { + get { return show_node_tool_tips; } + set { show_node_tool_tips = value; } + } + + [DefaultValue(true)] + public bool ShowPlusMinus { + get { return show_plus_minus; } + set { + if (show_plus_minus == value) + return; + show_plus_minus = value; + Invalidate (); + } + } + + [DefaultValue(true)] + public bool ShowRootLines { + get { return show_root_lines; } + set { + if (show_root_lines == value) + return; + show_root_lines = value; + Invalidate (); + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + [DefaultValue(false)] + public bool Sorted { + get { return sorted; } + set { + if (sorted == value) + return; + sorted = value; + //LAMESPEC: The documentation says that setting this to true should sort alphabetically if TreeViewNodeSorter is set. + // There seems to be a bug in the Microsoft implementation. + if (sorted && tree_view_node_sorter == null) { + Sort (null); + } + } + } + + [DefaultValue (null)] + public ImageList StateImageList { + get { return state_image_list; } + set { + state_image_list = value; + Invalidate (); + } + } + + [Browsable(false)] + //[EditorBrowsable(EditorBrowsableState.Never)] + [Bindable(false)] + public override string Text { + get { return base.Text; } + set { base.Text = value; } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public TreeNode TopNode { + get { + if (root_node.FirstNode == null) + return null; + OpenTreeNodeEnumerator one = new OpenTreeNodeEnumerator (root_node.FirstNode); + one.MoveNext (); + for (int i = 0; i < skipped_nodes; i++) + one.MoveNext (); + return one.CurrentNode; + } + set { + SetTop (value); + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public IComparer TreeViewNodeSorter { + get { + return tree_view_node_sorter; + } + set { + tree_view_node_sorter = value; + if (tree_view_node_sorter != null) { + Sort(); + //LAMESPEC: The documentation says that setting this should set Sorted to false. + // There seems to be a bug in the Microsoft implementation. + sorted = true; + } + } + } + + [Browsable(false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int VisibleCount { + get { + return ViewportRectangle.Height / ActualItemHeight; + } + } + + /// According to MSDN this property has no effect on the treeview + //[EditorBrowsable (EditorBrowsableState.Never)] + protected override bool DoubleBuffered { + get { return base.DoubleBuffered; } + set { base.DoubleBuffered = value; } + } + + [DefaultValue ("Color [Black]")] + public Color LineColor { + get { + if (line_color == Color.Empty) { + Color res = WidgetPaint.Dark (BackColor); + if (res == BackColor) + res = WidgetPaint.Light (BackColor); + return res; + } + return line_color; + } + set { + line_color = value; + if (show_lines) { + CreateDashPen (); + Invalidate (); + } + } + } + + [Localizable (true)] + [DefaultValue ("")] + [RelatedImageList ("ImageList")] + [RefreshProperties (RefreshProperties.Repaint)] + [TypeConverter (typeof (ImageKeyConverter))] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + public string ImageKey { + get { return image_key; } + set { + if (image_key == value) + return; + image_index = -1; + image_key = value; + Invalidate (); + } + } + + [Localizable (true)] + [DefaultValue ("")] + [RelatedImageList ("ImageList")] + [RefreshProperties (RefreshProperties.Repaint)] + [TypeConverter (typeof (ImageKeyConverter))] + //[Editor ("ShiftUI.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] + public string SelectedImageKey { + get { return selected_image_key; } + set { + if (selected_image_key == value) + return; + selected_image_index = -1; + selected_image_key = value; + UpdateNode (SelectedNode); + } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override ImageLayout BackgroundImageLayout { + get { return base.BackgroundImageLayout; } + set { base.BackgroundImageLayout = value; } + } + + [DefaultValue (TreeViewDrawMode.Normal)] + public TreeViewDrawMode DrawMode { + get { return draw_mode; } + set { draw_mode = value; } + } + #endregion // Public Instance Properties + + #region UIA Framework Properties + internal ScrollBar UIAHScrollBar { + get { return hbar; } + } + + internal ScrollBar UIAVScrollBar { + get { return vbar; } + } + #endregion // UIA Framework Properties + + #region Protected Instance Properties + protected override CreateParams CreateParams { + get { + CreateParams cp = base.CreateParams; + return cp; + } + } + + protected override Size DefaultSize { + get { return new Size (121, 97); } + } + + #endregion // Protected Instance Properties + + #region Public Instance Methods + public void BeginUpdate () + { + update_stack++; + } + + public void EndUpdate () + { + if (update_stack > 1) { + update_stack--; + } else { + update_stack = 0; + if (update_needed) { + RecalculateVisibleOrder (root_node); + UpdateScrollBars (false); + // if (SelectedNode != null) + // SelectedNode.EnsureVisible (); + Invalidate (ViewportRectangle); + update_needed = false; + } + } + } + + public void Sort () + { + Sort (tree_view_node_sorter); + } + + void Sort (IComparer sorter) + { + sorted = true; + Nodes.Sort (sorter); + RecalculateVisibleOrder (root_node); + UpdateScrollBars (false); + Invalidate (); + } + + void SetVScrollValue (int value) + { + if (value > vbar.Maximum) + value = vbar.Maximum; + else if (value < vbar.Minimum) + value = vbar.Minimum; + + vbar.Value = value; + } + + public void ExpandAll () + { + BeginUpdate (); + root_node.ExpandAll (); + + EndUpdate (); + + /// + /// Everything below this is basically an emulation of a strange bug on MS + /// where they don't always scroll to the last node on ExpandAll + /// + if (!IsHandleCreated) + return; + + bool found = false; + foreach (TreeNode child in Nodes) { + if (child.Nodes.Count > 0) + found = true; + } + + if (!found) + return; + + if (IsHandleCreated && vbar.VisibleInternal) { + SetVScrollValue (vbar.Maximum - VisibleCount + 1); + } else { + RecalculateVisibleOrder (root_node); + UpdateScrollBars (true); + + // Only move the top node if we now have a scrollbar + if (vbar.VisibleInternal) { + SetTop (Nodes [Nodes.Count - 1]); + SelectedNode = Nodes [Nodes.Count - 1]; + } + } + } + + public void CollapseAll () + { + BeginUpdate (); + root_node.CollapseAll (); + EndUpdate (); + + if (vbar.VisibleInternal) + SetVScrollValue (vbar.Maximum - VisibleCount + 1); + } + + public TreeNode GetNodeAt (Point pt) { + return GetNodeAt (pt.Y); + } + + public TreeNode GetNodeAt (int x, int y) + { + return GetNodeAt (y); + } + + private TreeNode GetNodeAtUseX (int x, int y) { + TreeNode node = GetNodeAt (y); + if (node == null || !(IsTextArea (node, x) || full_row_select)) + return null; + return node; + + } + + public int GetNodeCount (bool includeSubTrees) { + return root_node.GetNodeCount (includeSubTrees); + } + + public TreeViewHitTestInfo HitTest (Point pt) + { + return HitTest (pt.X, pt.Y); + } + + public TreeViewHitTestInfo HitTest (int x, int y) + { + TreeNode n = GetNodeAt (y); + + if (n == null) + return new TreeViewHitTestInfo (null, TreeViewHitTestLocations.None); + + if (IsTextArea (n, x)) + return new TreeViewHitTestInfo (n, TreeViewHitTestLocations.Label); + else if (IsPlusMinusArea (n, x)) + return new TreeViewHitTestInfo (n, TreeViewHitTestLocations.PlusMinus); + else if ((checkboxes || n.StateImage != null) && IsCheckboxArea (n, x)) + return new TreeViewHitTestInfo (n, TreeViewHitTestLocations.StateImage); + else if (x > n.Bounds.Right) + return new TreeViewHitTestInfo (n, TreeViewHitTestLocations.RightOfLabel); + else if (IsImage (n, x)) + return new TreeViewHitTestInfo (n, TreeViewHitTestLocations.Image); + else + return new TreeViewHitTestInfo (null, TreeViewHitTestLocations.Indent); + } + + public override string ToString () { + int count = Nodes.Count; + if (count <= 0) + return String.Concat (base.ToString (), ", Nodes.Count: 0"); + return String.Concat (base.ToString (), ", Nodes.Count: ", count, ", Nodes[0]: ", Nodes [0]); + + } + #endregion // Public Instance Methods + + #region Protected Instance Methods + protected override void CreateHandle () { + base.CreateHandle (); + RecalculateVisibleOrder (root_node); + UpdateScrollBars (false); + + if (pre_selected_node != null) + SelectedNode = pre_selected_node; + } + + protected override void Dispose (bool disposing) { + if (disposing) + image_list = null; + + base.Dispose (disposing); + } + + protected OwnerDrawPropertyBag GetItemRenderStyles (TreeNode node, int state) { + return node.prop_bag; + } + + protected override bool IsInputKey (Keys keyData) + { + if (IsHandleCreated && (keyData & Keys.Alt) == 0) { + switch (keyData & Keys.KeyCode) { + case Keys.Left: + case Keys.Up: + case Keys.Right: + case Keys.Down: + return true; + case Keys.Enter: + case Keys.Escape: + case Keys.Prior: + case Keys.Next: + case Keys.End: + case Keys.Home: + if (edit_node != null) + return true; + + break; + } + } + return base.IsInputKey (keyData); + } + + protected override void OnKeyDown (KeyEventArgs e) + { + OpenTreeNodeEnumerator ne; + + switch (e.KeyData & Keys.KeyCode) { + case Keys.Add: + if (selected_node != null && selected_node.IsExpanded) + selected_node.Expand (); + break; + case Keys.Subtract: + if (selected_node != null && selected_node.IsExpanded) + selected_node.Collapse (); + break; + case Keys.Left: + if (selected_node != null) { + if (selected_node.IsExpanded && selected_node.Nodes.Count > 0) + selected_node.Collapse (); + else { + TreeNode parent = selected_node.Parent; + if (parent != null) { + selection_action = TreeViewAction.ByKeyboard; + SelectedNode = parent; + } + } + } + break; + case Keys.Right: + if (selected_node != null) { + if (!selected_node.IsExpanded) + selected_node.Expand (); + else { + TreeNode child = selected_node.FirstNode; + if (child != null) + SelectedNode = child; + } + } + break; + case Keys.Up: + if (selected_node != null) { + ne = new OpenTreeNodeEnumerator (selected_node); + if (ne.MovePrevious () && ne.MovePrevious ()) { + selection_action = TreeViewAction.ByKeyboard; + SelectedNode = ne.CurrentNode; + } + } + break; + case Keys.Down: + if (selected_node != null) { + ne = new OpenTreeNodeEnumerator (selected_node); + if (ne.MoveNext () && ne.MoveNext ()) { + selection_action = TreeViewAction.ByKeyboard; + SelectedNode = ne.CurrentNode; + } + } + break; + case Keys.Home: + if (root_node.Nodes.Count > 0) { + ne = new OpenTreeNodeEnumerator (root_node.Nodes [0]); + if (ne.MoveNext ()) { + selection_action = TreeViewAction.ByKeyboard; + SelectedNode = ne.CurrentNode; + } + } + break; + case Keys.End: + if (root_node.Nodes.Count > 0) { + ne = new OpenTreeNodeEnumerator (root_node.Nodes [0]); + while (ne.MoveNext ()) + { } + selection_action = TreeViewAction.ByKeyboard; + SelectedNode = ne.CurrentNode; + } + break; + case Keys.PageDown: + if (selected_node != null) { + ne = new OpenTreeNodeEnumerator (selected_node); + int move = VisibleCount; + for (int i = 0; i < move && ne.MoveNext (); i++) { + + } + selection_action = TreeViewAction.ByKeyboard; + SelectedNode = ne.CurrentNode; + } + break; + case Keys.PageUp: + if (selected_node != null) { + ne = new OpenTreeNodeEnumerator (selected_node); + int move = VisibleCount; + for (int i = 0; i < move && ne.MovePrevious (); i++) + { } + selection_action = TreeViewAction.ByKeyboard; + SelectedNode = ne.CurrentNode; + } + break; + case Keys.Multiply: + if (selected_node != null) + selected_node.ExpandAll (); + break; + } + base.OnKeyDown (e); + + if (!e.Handled && checkboxes && + selected_node != null && + (e.KeyData & Keys.KeyCode) == Keys.Space) { + selected_node.check_reason = TreeViewAction.ByKeyboard; + selected_node.Checked = !selected_node.Checked; + e.Handled = true; + } + } + + protected override void OnKeyPress (KeyPressEventArgs e) + { + base.OnKeyPress (e); + if (e.KeyChar == ' ') + e.Handled = true; + } + + protected override void OnKeyUp (KeyEventArgs e) + { + base.OnKeyUp (e); + if ((e.KeyData & Keys.KeyCode) == Keys.Space) + e.Handled = true; + } + + protected override void OnMouseHover (EventArgs e) + { + base.OnMouseHover (e); + + is_hovering = true; + + TreeNode tn = GetNodeAt (PointToClient (MousePosition)); + + if (tn != null) + MouseEnteredItem (tn); + } + + protected override void OnMouseLeave (EventArgs e) + { + base.OnMouseLeave (e); + + is_hovering = false; + + if (tooltip_currently_showing != null) + MouseLeftItem (tooltip_currently_showing); + } + + protected virtual void OnNodeMouseClick (TreeNodeMouseClickEventArgs e) + { + TreeNodeMouseClickEventHandler eh = (TreeNodeMouseClickEventHandler)(Events[NodeMouseClickEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnNodeMouseDoubleClick (TreeNodeMouseClickEventArgs e) + { + TreeNodeMouseClickEventHandler eh = (TreeNodeMouseClickEventHandler)(Events[NodeMouseDoubleClickEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnNodeMouseHover (TreeNodeMouseHoverEventArgs e) + { + TreeNodeMouseHoverEventHandler eh = (TreeNodeMouseHoverEventHandler)(Events[NodeMouseHoverEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnItemDrag (ItemDragEventArgs e) + { + ItemDragEventHandler eh = (ItemDragEventHandler)(Events [ItemDragEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnDrawNode(DrawTreeNodeEventArgs e) { + DrawTreeNodeEventHandler eh = (DrawTreeNodeEventHandler)(Events[DrawNodeEvent]); + if (eh != null) + eh(this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnRightToLeftLayoutChanged (EventArgs e) { + EventHandler eh = (EventHandler)(Events[RightToLeftLayoutChangedEvent]); + if (eh != null) + eh (this, e); + } + + protected internal virtual void OnAfterCheck (TreeViewEventArgs e) { + TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterCheckEvent]); + if (eh != null) + eh (this, e); + } + + protected internal virtual void OnAfterCollapse (TreeViewEventArgs e) { + TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterCollapseEvent]); + if (eh != null) + eh (this, e); + } + + protected internal virtual void OnAfterExpand (TreeViewEventArgs e) { + TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterExpandEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnAfterLabelEdit (NodeLabelEditEventArgs e) { + NodeLabelEditEventHandler eh = (NodeLabelEditEventHandler)(Events [AfterLabelEditEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnAfterSelect (TreeViewEventArgs e) { + TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterSelectEvent]); + if (eh != null) + eh (this, e); + } + + protected internal virtual void OnBeforeCheck (TreeViewCancelEventArgs e) { + TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeCheckEvent]); + if (eh != null) + eh (this, e); + } + + protected internal virtual void OnBeforeCollapse (TreeViewCancelEventArgs e) { + TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeCollapseEvent]); + if (eh != null) + eh (this, e); + } + + protected internal virtual void OnBeforeExpand (TreeViewCancelEventArgs e) { + TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeExpandEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnBeforeLabelEdit (NodeLabelEditEventArgs e) { + NodeLabelEditEventHandler eh = (NodeLabelEditEventHandler)(Events [BeforeLabelEditEvent]); + if (eh != null) + eh (this, e); + } + + protected virtual void OnBeforeSelect (TreeViewCancelEventArgs e) { + TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeSelectEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnHandleCreated (EventArgs e) { + base.OnHandleCreated (e); + } + + protected override void OnHandleDestroyed (EventArgs e) { + base.OnHandleDestroyed (e); + } + + protected override void WndProc(ref Message m) { + switch ((Msg) m.Msg) { + + case Msg.WM_LBUTTONDBLCLK: + int val = m.LParam.ToInt32(); + DoubleClickHandler (null, new + MouseEventArgs (MouseButtons.Left, + 2, val & 0xffff, + (val>>16) & 0xffff, 0)); + break; + case Msg.WM_CONTEXTMENU: + if (WmContextMenu (ref m)) + return; + + break; + } + base.WndProc (ref m); + } + + #endregion // Protected Instance Methods + + #region Internal & Private Methods and Properties + internal override bool ScaleChildrenInternal { + get { return false; } + } + + internal IntPtr CreateNodeHandle () + { + return (IntPtr) handle_count++; + } + + // According to MSDN docs, for these to be raised, + // the click must occur over a TreeNode + internal override void HandleClick (int clicks, MouseEventArgs me) + { + if (GetNodeAt (me.Location) != null) { + if ((clicks > 1) && GetStyle (Widgetstyles.StandardDoubleClick)) { + OnDoubleClick (me); + OnMouseDoubleClick (me); + } else { + OnClick (me); + OnMouseClick (me); + } + } + } + + internal override bool IsInputCharInternal (char charCode) + { + return true; + } + + internal TreeNode NodeFromHandle (IntPtr handle) + { + // This method is called rarely, so instead of maintaining a table + // we just walk the tree nodes to find the matching handle + return NodeFromHandleRecursive (root_node, handle); + } + + private TreeNode NodeFromHandleRecursive (TreeNode node, IntPtr handle) + { + if (node.handle == handle) + return node; + foreach (TreeNode child in node.Nodes) { + TreeNode match = NodeFromHandleRecursive (child, handle); + if (match != null) + return match; + } + return null; + } + + internal Rectangle ViewportRectangle { + get { + Rectangle res = ClientRectangle; + + if (vbar != null && vbar.Visible) + res.Width -= vbar.Width; + if (hbar != null && hbar.Visible) + res.Height -= hbar.Height; + return res; + } + } + + private TreeNode GetNodeAt (int y) + { + if (nodes.Count <= 0) + return null; + + OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (TopNode); + int move = y / ActualItemHeight; + for (int i = -1; i < move; i++) { + if (!o.MoveNext ()) + return null; + } + + return o.CurrentNode; + } + + private bool IsTextArea (TreeNode node, int x) + { + return node != null && node.Bounds.Left <= x && node.Bounds.Right >= x; + } + + private bool IsSelectableArea (TreeNode node, int x) + { + if (node == null) + return false; + int l = node.Bounds.Left; + if (ImageList != null) + l -= ImageList.ImageSize.Width; + return l <= x && node.Bounds.Right >= x; + + } + + private bool IsPlusMinusArea (TreeNode node, int x) + { + if (node.Nodes.Count == 0 || (node.parent == root_node && !show_root_lines)) + return false; + + int l = node.Bounds.Left + 5; + + if (show_root_lines || node.Parent != null) + l -= indent; + if (ImageList != null) + l -= ImageList.ImageSize.Width + 3; + if (checkboxes) + l -= 19; + // StateImage is basically a custom checkbox + else if (node.StateImage != null) + l -= 19; + return (x > l && x < l + 8); + } + + private bool IsCheckboxArea (TreeNode node, int x) + { + int l = CheckBoxLeft (node); + return (x > l && x < l + 10); + } + + private bool IsImage (TreeNode node, int x) + { + if (ImageList == null) + return false; + + int l = node.Bounds.Left; + + l -= ImageList.ImageSize.Width + 5; + + if (x >= l && x <= (l + ImageList.ImageSize.Width + 5)) + return true; + + return false; + } + + private int CheckBoxLeft (TreeNode node) + { + int l = node.Bounds.Left + 5; + + if (show_root_lines || node.Parent != null) + l -= indent; + + if (!show_root_lines && node.Parent == null) + l -= indent; + + if (ImageList != null) + l -= ImageList.ImageSize.Width + 3; + + return l; + } + + internal void RecalculateVisibleOrder (TreeNode start) + { + if (update_stack > 0) + return; + + int order; + if (start == null) { + start = root_node; + order = 0; + } else + order = start.visible_order; + + + + OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (start); + while (walk.MoveNext ()) { + walk.CurrentNode.visible_order = order; + order++; + } + + max_visible_order = order; + } + + internal void SetTop (TreeNode node) + { + int order = 0; + if (node != null) + order = Math.Max (0, node.visible_order - 1); + + if (!vbar.is_visible) { + skipped_nodes = order; + return; + } + + SetVScrollValue (Math.Min (order, vbar.Maximum - VisibleCount + 1)); + } + + internal void SetBottom (TreeNode node) + { + if (!vbar.is_visible) + return; + + OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (node); + + int bottom = ViewportRectangle.Bottom; + int offset = 0; + while (walk.MovePrevious ()) { + if (walk.CurrentNode.Bounds.Bottom <= bottom) + break; + offset++; + } + + int nv = vbar.Value + offset; + if (vbar.Value + offset < vbar.Maximum) { + SetVScrollValue (nv); + } else { +#if DEBUG + Console.Error.WriteLine ("setting bottom to value greater then maximum ({0}, {1})", + nv, vbar.Maximum); +#endif + } + + } + + internal void UpdateBelow (TreeNode node) + { + if (update_stack > 0) { + update_needed = true; + return; + } + + if (node == root_node) { + Invalidate (ViewportRectangle); + return; + } + + // We need to update the current node so the plus/minus block gets update too + int top = Math.Max (node.Bounds.Top - 1, 0); + Rectangle invalid = new Rectangle (0, top, + Width, Height - top); + Invalidate (invalid); + } + + internal void UpdateNode (TreeNode node) + { + if (node == null) + return; + + if (update_stack > 0) { + update_needed = true; + return; + } + + if (node == root_node) { + Invalidate (); + return; + } + + Rectangle invalid = new Rectangle (0, node.Bounds.Top - 1, Width, + node.Bounds.Height + 1); + Invalidate (invalid); + } + + internal void UpdateNodePlusMinus (TreeNode node) + { + if (update_stack > 0) { + update_needed = true; + return; + } + + int l = node.Bounds.Left + 5; + + if (show_root_lines || node.Parent != null) + l -= indent; + if (ImageList != null) + l -= ImageList.ImageSize.Width + 3; + if (checkboxes) + l -= 19; + + Invalidate (new Rectangle (l, node.Bounds.Top, 8, node.Bounds.Height)); + } + + internal override void OnPaintInternal (PaintEventArgs pe) + { + Draw (pe.ClipRectangle, pe.Graphics); + } + + internal void CreateDashPen () + { + dash = new Pen (LineColor, 1); + dash.DashStyle = DashStyle.Dot; + } + + private void Draw (Rectangle clip, Graphics dc) + { + dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), clip); + + if (dash == null) + CreateDashPen (); + + Rectangle viewport = ViewportRectangle; + Rectangle original_clip = clip; + if (clip.Bottom > viewport.Bottom) + clip.Height = viewport.Bottom - clip.Top; + + OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (TopNode); + while (walk.MoveNext ()) { + TreeNode current = walk.CurrentNode; + + // Haven't gotten to visible nodes yet + if (current.GetY () + ActualItemHeight < clip.Top) + continue; + + // Past the visible nodes + if (current.GetY () > clip.Bottom) + break; + + DrawTreeNode (current, dc, clip); + } + + if (hbar.Visible && vbar.Visible) { + Rectangle corner = new Rectangle (hbar.Right, vbar.Bottom, vbar.Width, hbar.Height); + if (original_clip.IntersectsWith (corner)) + dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorControl), + corner); + } + } + + private void DrawNodeState (TreeNode node, Graphics dc, int x, int y) + { + if (node.Checked) { + if (StateImageList.Images[1] != null) + dc.DrawImage (StateImageList.Images[1], new Rectangle (x, y, 16, 16)); + } else { + if (StateImageList.Images[0] != null) + dc.DrawImage (StateImageList.Images[0], new Rectangle (x, y, 16, 16)); + } + } + + private void DrawNodeCheckBox (TreeNode node, Graphics dc, int x, int middle) + { + Pen pen = ThemeEngine.Current.ResPool.GetSizedPen(Color.Black, 2); + dc.DrawRectangle (pen, x + 3, middle - 4, 11, 11); + + if (node.Checked) { + Pen check_pen = ThemeEngine.Current.ResPool.GetPen(Color.Black); + + int check_size = 5; + int lineWidth = 3; + + Rectangle rect = new Rectangle (x + 4, middle - 3, check_size, check_size); + + for (int i = 0; i < lineWidth; i++) { + dc.DrawLine (check_pen, rect.Left + 1, rect.Top + lineWidth + i, rect.Left + 3, rect.Top + 5 + i); + dc.DrawLine (check_pen, rect.Left + 3, rect.Top + 5 + i, rect.Left + 7, rect.Top + 1 + i); + } + } + } + + private void DrawNodeLines (TreeNode node, Graphics dc, Rectangle clip, Pen dash, int x, int y, int middle) + { + int ladjust = 9; + int radjust = 0; + + if (node.nodes.Count > 0 && show_plus_minus) + ladjust = 13; + if (checkboxes) + radjust = 3; + + if (show_root_lines || node.Parent != null) + dc.DrawLine (dash, x - indent + ladjust, middle, x + radjust, middle); + + if (node.PrevNode != null || node.Parent != null) { + ladjust = 9; + dc.DrawLine (dash, x - indent + ladjust, node.Bounds.Top, + x - indent + ladjust, middle - (show_plus_minus && node.Nodes.Count > 0 ? 4 : 0)); + } + + if (node.NextNode != null) { + ladjust = 9; + dc.DrawLine (dash, x - indent + ladjust, middle + (show_plus_minus && node.Nodes.Count > 0 ? 4 : 0), + x - indent + ladjust, node.Bounds.Bottom); + + } + + ladjust = 0; + if (show_plus_minus) + ladjust = 9; + TreeNode parent = node.Parent; + while (parent != null) { + if (parent.NextNode != null) { + int px = parent.GetLinesX () - indent + ladjust; + dc.DrawLine (dash, px, node.Bounds.Top, px, node.Bounds.Bottom); + } + parent = parent.Parent; + } + } + + private void DrawNodeImage (TreeNode node, Graphics dc, Rectangle clip, int x, int y) + { + if (!RectsIntersect (clip, x, y, ImageList.ImageSize.Width, ImageList.ImageSize.Height)) + return; + + int use_index = node.Image; + + if (use_index > -1 && use_index < ImageList.Images.Count) + ImageList.Draw (dc, x, y, ImageList.ImageSize.Width, ImageList.ImageSize.Height, use_index); + } + + private void LabelEditFinished (object sender, EventArgs e) + { + EndEdit (edit_node); + } + + internal void BeginEdit (TreeNode node) + { + if (edit_node != null) + EndEdit (edit_node); + + if (edit_text_box == null) { + edit_text_box = new LabelEditTextBox (); + edit_text_box.BorderStyle = BorderStyle.FixedSingle; + edit_text_box.Visible = false; + edit_text_box.EditingCancelled += new EventHandler (LabelEditCancelled); + edit_text_box.EditingFinished += new EventHandler (LabelEditFinished); + edit_text_box.TextChanged += new EventHandler (LabelTextChanged); + Widgets.Add (edit_text_box); + } + + node.EnsureVisible (); + + edit_text_box.Bounds = node.Bounds; + edit_text_box.Text = node.Text; + edit_text_box.Visible = true; + edit_text_box.Focus (); + edit_text_box.SelectAll (); + + edit_args = new NodeLabelEditEventArgs (node); + OnBeforeLabelEdit (edit_args); + + edit_node = node; + + if (edit_args.CancelEdit) { + edit_node = null; + EndEdit (node); + } + } + + private void LabelEditCancelled (object sender, EventArgs e) + { + edit_args.SetLabel (null); + EndEdit (edit_node); + } + + private void LabelTextChanged (object sender, EventArgs e) + { + int width = TextRenderer.MeasureTextInternal (edit_text_box.Text, edit_text_box.Font, false).Width + 4; + edit_text_box.Width = width; + + if (edit_args != null) + edit_args.SetLabel (edit_text_box.Text); + } + + internal void EndEdit (TreeNode node) + { + if (edit_text_box != null && edit_text_box.Visible) { + edit_text_box.Visible = false; + Focus (); + } + + // + // If we get a call to BeginEdit from any AfterLabelEdit handler, + // the focus seems to always remain in the TreeView. This call seems + // to synchronize the focus events - I don't like it but it works + // + Application.DoEvents (); + + if (edit_node != null && edit_node == node) { + edit_node = null; + + NodeLabelEditEventArgs e = new NodeLabelEditEventArgs (edit_args.Node, edit_args.Label); + + OnAfterLabelEdit (e); + + if (e.CancelEdit) + return; + + if (e.Label != null) + e.Node.Text = e.Label; + } + + // EndEdit ends editing even if not called on the editing node + edit_node = null; + UpdateNode (node); + } + + internal void CancelEdit (TreeNode node) + { + edit_args.SetLabel (null); + + if (edit_text_box != null && edit_text_box.Visible) { + edit_text_box.Visible = false; + Focus (); + } + + edit_node = null; + UpdateNode (node); + } + + internal int GetNodeWidth (TreeNode node) + { + Font font = node.NodeFont; + if (node.NodeFont == null) + font = Font; + return (int)TextRenderer.MeasureString (node.Text, font, 0, string_format).Width + 3; + } + + private void DrawSelectionAndFocus(TreeNode node, Graphics dc, Rectangle r) + { + if (Focused && focused_node == node && !full_row_select) { + WidgetPaint.DrawFocusRectangle (dc, r, ForeColor, BackColor); + } + if (draw_mode != TreeViewDrawMode.Normal) + return; + + r.Inflate (-1, -1); + + if (Focused && node == highlighted_node) { + // Use the node's BackColor if is not empty, and is not actually the selected one (yet) + Color back_color = node != selected_node && node.BackColor != Color.Empty ? node.BackColor : + ThemeEngine.Current.ColorHighlight; + dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (back_color), r); + + } else if (!hide_selection && node == highlighted_node) { + dc.FillRectangle (SystemBrushes.Control, r); + } else { + // If selected_node is not the current highlighted one, use the color of the TreeView + Color back_color = node == selected_node ? BackColor : node.BackColor; + dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (back_color), r); + } + } + + private void DrawStaticNode (TreeNode node, Graphics dc) + { + if (!full_row_select || show_lines) + DrawSelectionAndFocus(node, dc, node.Bounds); + + + Font font = node.NodeFont; + if (node.NodeFont == null) + font = Font; + Color text_color = (Focused && node == highlighted_node ? + ThemeEngine.Current.ColorHighlightText : node.ForeColor); + if (text_color.IsEmpty) + text_color = ForeColor; + dc.DrawString (node.Text, font, + ThemeEngine.Current.ResPool.GetSolidBrush (text_color), + node.Bounds, string_format); + } + + private void DrawTreeNode (TreeNode node, Graphics dc, Rectangle clip) + { + int child_count = node.nodes.Count; + int y = node.GetY (); + int middle = y + (ActualItemHeight / 2); + + if (full_row_select && !show_lines) { + Rectangle r = new Rectangle (1, y, ViewportRectangle.Width - 2, ActualItemHeight); + DrawSelectionAndFocus (node, dc, r); + } + + if (draw_mode == TreeViewDrawMode.Normal || draw_mode == TreeViewDrawMode.OwnerDrawText) { + if ((show_root_lines || node.Parent != null) && show_plus_minus && child_count > 0) + ThemeEngine.Current.TreeViewDrawNodePlusMinus (this, node, dc, node.GetLinesX () - Indent + 5, middle); + + if (checkboxes && state_image_list == null) + DrawNodeCheckBox (node, dc, CheckBoxLeft (node) - 3, middle); + + if (checkboxes && state_image_list != null) + DrawNodeState (node, dc, CheckBoxLeft (node) - 3, y); + + if (!checkboxes && node.StateImage != null) + dc.DrawImage (node.StateImage, new Rectangle (CheckBoxLeft (node) - 3, y, 16, 16)); + + if (show_lines) + DrawNodeLines (node, dc, clip, dash, node.GetLinesX (), y, middle); + + if (ImageList != null) + DrawNodeImage (node, dc, clip, node.GetImageX (), y); + } + + if (draw_mode != TreeViewDrawMode.Normal) { + dc.FillRectangle (Brushes.White, node.Bounds); + TreeNodeStates tree_node_state = TreeNodeStates.Default;; + if (node.IsSelected) + tree_node_state = TreeNodeStates.Selected; + if (node.Checked) + tree_node_state |= TreeNodeStates.Checked; + if (node == focused_node) + tree_node_state |= TreeNodeStates.Focused; + Rectangle node_bounds = node.Bounds; + if (draw_mode == TreeViewDrawMode.OwnerDrawText) { + node_bounds.X += 3; + node_bounds.Y += 1; + } else { + node_bounds.X = 0; + node_bounds.Width = Width; + } + + DrawTreeNodeEventArgs e = new DrawTreeNodeEventArgs (dc, node, node_bounds, tree_node_state); + + OnDrawNode (e); + if (!e.DrawDefault) + return; + } + + if (!node.IsEditing) + DrawStaticNode (node, dc); + } + + internal void UpdateScrollBars (bool force) + { + if (!force && (IsDisposed || update_stack > 0 || !IsHandleCreated || !Visible)) + return; + + bool vert = false; + bool horz = false; + int height = 0; + int width = -1; + + int item_height = ActualItemHeight; + if (scrollable) { + OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (root_node); + + while (walk.MoveNext ()) { + int r = walk.CurrentNode.Bounds.Right; + if (r > width) + width = r; + + height += item_height; + } + + height -= item_height; // root_node adjustment + width += hbar_offset; + + if (height > ClientRectangle.Height) { + vert = true; + + if (width > ClientRectangle.Width - SystemInformation.VerticalScrollBarWidth) + horz = true; + } else if (width > ClientRectangle.Width) { + horz = true; + } + + if (!vert && horz && height > ClientRectangle.Height - SystemInformation.HorizontalScrollBarHeight) + vert = true; + } + + if (vert) { + int visible_height = horz ? ClientRectangle.Height - hbar.Height : ClientRectangle.Height; + vbar.SetValues (Math.Max (0, max_visible_order - 2), visible_height / ActualItemHeight); + /* + vbar.Maximum = max_visible_order; + vbar.LargeChange = ClientRectangle.Height / ItemHeight; + */ + + if (!vbar_bounds_set) { + vbar.Bounds = new Rectangle (ClientRectangle.Width - vbar.Width, 0, vbar.Width, + ClientRectangle.Height - + (horz ? SystemInformation.VerticalScrollBarWidth : 0)); + vbar_bounds_set = true; + + // We need to recalc the hbar if the vbar is now visible + hbar_bounds_set = false; + } + + + vbar.Visible = true; + if (skipped_nodes > 0) { + int skip = Math.Min (skipped_nodes, vbar.Maximum - VisibleCount + 1); + skipped_nodes = 0; + vbar.SafeValueSet (skip); + skipped_nodes = skip; + } + } else { + skipped_nodes = 0; + RecalculateVisibleOrder (root_node); + vbar.Visible = false; + SetVScrollValue (0); + vbar_bounds_set = false; + } + + if (horz) { + hbar.SetValues (width + 1, ClientRectangle.Width - (vert ? SystemInformation.VerticalScrollBarWidth : 0)); + /* + hbar.LargeChange = ClientRectangle.Width; + hbar.Maximum = width + 1; + */ + + if (!hbar_bounds_set) { + hbar.Bounds = new Rectangle (0, ClientRectangle.Height - hbar.Height, + ClientRectangle.Width - (vert ? SystemInformation.VerticalScrollBarWidth : 0), + hbar.Height); + hbar_bounds_set = true; + } + hbar.Visible = true; + } else { + hbar_offset = 0; + hbar.Visible = false; + hbar_bounds_set = false; + } + } + + private void SizeChangedHandler (object sender, EventArgs e) + { + if (IsHandleCreated) { + if (max_visible_order == -1) + RecalculateVisibleOrder (root_node); + UpdateScrollBars (false); + } + + if (vbar.Visible) { + vbar.Bounds = new Rectangle (ClientRectangle.Width - vbar.Width, 0, vbar.Width, + ClientRectangle.Height - (hbar.Visible ? SystemInformation.HorizontalScrollBarHeight : 0)); + } + + if (hbar.Visible) { + hbar.Bounds = new Rectangle (0, ClientRectangle.Height - hbar.Height, + ClientRectangle.Width - (vbar.Visible ? SystemInformation.VerticalScrollBarWidth : 0), hbar.Height); + } + } + + private void VScrollBarValueChanged (object sender, EventArgs e) + { + if (edit_node != null) + EndEdit (edit_node); + + SetVScrollPos (vbar.Value, null); + } + + private void SetVScrollPos (int pos, TreeNode new_top) + { + if (!vbar.VisibleInternal) + return; + + if (pos < 0) + pos = 0; + + if (skipped_nodes == pos) + return; + + int diff = skipped_nodes - pos; + skipped_nodes = pos; + + if (!IsHandleCreated) + return; + + int y_move = diff * ActualItemHeight; + XplatUI.ScrollWindow (Handle, ViewportRectangle, 0, y_move, false); + } + + /*private void SetVScrollTop (TreeNode new_top) + { + vbar.Value = new_top.visible_order - VisibleCount; + }*/ + + private void HScrollBarValueChanged(object sender, EventArgs e) + { + if (edit_node != null) + EndEdit (edit_node); + + int old_offset = hbar_offset; + hbar_offset = hbar.Value; + + if (hbar_offset < 0) { + hbar_offset = 0; + } + + XplatUI.ScrollWindow (Handle, ViewportRectangle, old_offset - hbar_offset, 0, false); + } + + internal void ExpandBelow (TreeNode node, int count_to_next) + { + if (update_stack > 0) { + update_needed = true; + return; + } + + // If node Bottom is less than 0, the node is above and not visible, + // and we need to scroll the entire viewport + int node_bottom = node.Bounds.Bottom >= 0 ? node.Bounds.Bottom : 0; + Rectangle below = new Rectangle (0, node_bottom, ViewportRectangle.Width, + ViewportRectangle.Height - node_bottom); + + int amount = count_to_next * ActualItemHeight; + + if (amount > 0) + XplatUI.ScrollWindow (Handle, below, 0, amount, false); + + if (show_plus_minus) { + Invalidate (new Rectangle (0, node.GetY (), Width, ActualItemHeight)); + } + } + + internal void CollapseBelow (TreeNode node, int count_to_next) + { + if (update_stack > 0) { + update_needed = true; + return; + } + + Rectangle below = new Rectangle (0, node.Bounds.Bottom, ViewportRectangle.Width, + ViewportRectangle.Height - node.Bounds.Bottom); + + int amount = count_to_next * ActualItemHeight; + + if (amount > 0) + XplatUI.ScrollWindow (Handle, below, 0, -amount, false); + + if (show_plus_minus) { + Invalidate (new Rectangle (0, node.GetY (), Width, ActualItemHeight)); + } + } + + private void MouseWheelHandler(object sender, MouseEventArgs e) { + + if (vbar == null || !vbar.is_visible) { + return; + } + + if (e.Delta < 0) { + SetVScrollValue (Math.Min (vbar.Value + SystemInformation.MouseWheelScrollLines, vbar.Maximum - VisibleCount + 1)); + } else { + SetVScrollValue (Math.Max (0, vbar.Value - SystemInformation.MouseWheelScrollLines)); + } + } + + private void VisibleChangedHandler (object sender, EventArgs e) + { + if (Visible) { + UpdateScrollBars (false); + } + } + + private void FontChangedHandler (object sender, EventArgs e) + { + if (IsHandleCreated) { + TreeNode top = TopNode; + InvalidateNodeWidthRecursive (root_node); + + SetTop (top); + } + } + + private void InvalidateNodeWidthRecursive (TreeNode node) + { + node.InvalidateWidth (); + foreach (TreeNode child in node.Nodes) { + InvalidateNodeWidthRecursive (child); + } + } + + private void GotFocusHandler (object sender, EventArgs e) + { + if (selected_node == null) { + if (pre_selected_node != null) { + SelectedNode = pre_selected_node; + return; + } + + SelectedNode = TopNode; + + } else if (selected_node != null) + UpdateNode (selected_node); + } + + private void LostFocusHandler (object sender, EventArgs e) + { + UpdateNode (SelectedNode); + } + + private void MouseDownHandler (object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Right) + Focus (); + + TreeNode node = GetNodeAt (e.Y); + if (node == null) + return; + + mouse_click_node = node; + + if (show_plus_minus && IsPlusMinusArea (node, e.X) && e.Button == MouseButtons.Left) { + node.Toggle (); + return; + } else if (checkboxes && IsCheckboxArea (node, e.X) && e.Button == MouseButtons.Left) { + node.check_reason = TreeViewAction.ByMouse; + node.Checked = !node.Checked; + UpdateNode(node); + return; + } else if (IsSelectableArea (node, e.X) || full_row_select) { + TreeNode old_highlighted = highlighted_node; + highlighted_node = node; + if (label_edit && e.Clicks == 1 && highlighted_node == old_highlighted && e.Button == MouseButtons.Left) { + BeginEdit (node); + } else if (highlighted_node != focused_node) { + Size ds = SystemInformation.DragSize; + mouse_rect.X = e.X - ds.Width; + mouse_rect.Y = e.Y - ds.Height; + mouse_rect.Width = ds.Width * 2; + mouse_rect.Height = ds.Height * 2; + + select_mmove = true; + } + + Invalidate (highlighted_node.Bounds); + if (old_highlighted != null) + Invalidate (Bloat (old_highlighted.Bounds)); + + drag_begin_x = e.X; + drag_begin_y = e.Y; + } + } + + private void MouseUpHandler (object sender, MouseEventArgs e) { + TreeNode node = GetNodeAt (e.Y); + + if (node != null && node == mouse_click_node) { + if (e.Clicks == 2) + OnNodeMouseDoubleClick (new TreeNodeMouseClickEventArgs (node, e.Button, e.Clicks, e.X, e.Y)); + else + OnNodeMouseClick (new TreeNodeMouseClickEventArgs (node, e.Button, e.Clicks, e.X, e.Y)); + } + + mouse_click_node = null; + + drag_begin_x = -1; + drag_begin_y = -1; + + if (!select_mmove) + return; + + select_mmove = false; + + if (e.Button == MouseButtons.Right && selected_node != null) { + Invalidate (highlighted_node.Bounds); + highlighted_node = selected_node; + Invalidate (selected_node.Bounds); + return; + } + + TreeViewCancelEventArgs ce = new TreeViewCancelEventArgs (highlighted_node, false, TreeViewAction.ByMouse); + OnBeforeSelect (ce); + + Rectangle invalid; + if (!ce.Cancel) { + TreeNode prev_focused_node = focused_node; + TreeNode prev_highlighted_node = highlighted_node; + + selected_node = highlighted_node; + focused_node = highlighted_node; + OnAfterSelect (new TreeViewEventArgs (selected_node, TreeViewAction.ByMouse)); + + if (prev_highlighted_node != null) { + if (prev_focused_node != null) { + invalid = Rectangle.Union (Bloat (prev_focused_node.Bounds), + Bloat (prev_highlighted_node.Bounds)); + } else { + invalid = Bloat (prev_highlighted_node.Bounds); + } + + invalid.X = 0; + invalid.Width = ViewportRectangle.Width; + + Invalidate (invalid); + } + + } else { + if (highlighted_node != null) + Invalidate (highlighted_node.Bounds); + + highlighted_node = focused_node; + selected_node = focused_node; + if (selected_node != null) + Invalidate (selected_node.Bounds); + } + } + + private void MouseMoveHandler (object sender, MouseEventArgs e) { + // XXX - This should use HitTest and only fire when we are over + // the important parts of a node, not things like gridlines or + // whitespace + TreeNode tn = GetNodeAt (e.Location); + + if (tn != tooltip_currently_showing) + MouseLeftItem (tooltip_currently_showing); + + if (tn != null && tn != tooltip_currently_showing) + MouseEnteredItem (tn); + + if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Right) { + if (drag_begin_x != -1 && drag_begin_y != -1) { + double rise = Math.Pow (drag_begin_x - e.X, 2); + double run = Math.Pow (drag_begin_y - e.Y, 2); + double move = Math.Sqrt (rise + run); + if (move > 3) { + TreeNode drag = GetNodeAtUseX (e.X, e.Y); + + if (drag != null) { + OnItemDrag (new ItemDragEventArgs (e.Button, drag)); + } + drag_begin_x = -1; + drag_begin_y = -1; + } + } + + } + + // If there is enough movement before the mouse comes up, + // selection is reverted back to the originally selected node + if (!select_mmove || mouse_rect.Contains (e.X, e.Y)) + return; + + Invalidate (highlighted_node.Bounds); + if (selected_node != null) + Invalidate (selected_node.Bounds); + if (focused_node != null) + Invalidate (focused_node.Bounds); + + highlighted_node = selected_node; + focused_node = selected_node; + + select_mmove = false; + } + + private void DoubleClickHandler (object sender, MouseEventArgs e) { + TreeNode node = GetNodeAtUseX (e.X,e.Y); + if(node != null && node.Nodes.Count > 0) { + node.Toggle(); + } + } + + + private bool RectsIntersect (Rectangle r, int left, int top, int width, int height) + { + return !((r.Left > left + width) || (r.Right < left) || + (r.Top > top + height) || (r.Bottom < top)); + } + + // Return true if message was handled, false to send it to base + private bool WmContextMenu (ref Message m) + { + Point pt; + TreeNode tn; + + pt = new Point (LowOrder ((int)m.LParam.ToInt32 ()), HighOrder ((int)m.LParam.ToInt32 ())); + + // This means it's a keyboard menu request + if (pt.X == -1 || pt.Y == -1) { + tn = SelectedNode; + + if (tn == null) + return false; + + pt = new Point (tn.Bounds.Left, tn.Bounds.Top + (tn.Bounds.Height / 2)); + } else { + pt = PointToClient (pt); + + tn = GetNodeAt (pt); + + if (tn == null) + return false; + } + + if (tn.ContextMenuStrip != null) { + tn.ContextMenuStrip.Show (this, pt); + return true; + } + + // The node we found did not have its own menu, let the parent try to display its menu + return false; + } + + #region Stuff for ToolTips + private void MouseEnteredItem (TreeNode item) + { + tooltip_currently_showing = item; + + if (!is_hovering) + return; + + if (ShowNodeToolTips && !string.IsNullOrEmpty (tooltip_currently_showing.ToolTipText)) + ToolTipWindow.Present (this, tooltip_currently_showing.ToolTipText); + + OnNodeMouseHover (new TreeNodeMouseHoverEventArgs (tooltip_currently_showing)); + } + + private void MouseLeftItem (TreeNode item) + { + ToolTipWindow.Hide (this); + tooltip_currently_showing = null; + } + + private ToolTip ToolTipWindow { + get { + if (tooltip_window == null) + tooltip_window = new ToolTip (); + + return tooltip_window; + } + } + #endregion + + #endregion // Internal & Private Methods and Properties + + #region Events + static object ItemDragEvent = new object (); + static object AfterCheckEvent = new object (); + static object AfterCollapseEvent = new object (); + static object AfterExpandEvent = new object (); + static object AfterLabelEditEvent = new object (); + static object AfterSelectEvent = new object (); + static object BeforeCheckEvent = new object (); + static object BeforeCollapseEvent = new object (); + static object BeforeExpandEvent = new object (); + static object BeforeLabelEditEvent = new object (); + static object BeforeSelectEvent = new object (); + static object DrawNodeEvent = new object (); + static object NodeMouseClickEvent = new object (); + static object NodeMouseDoubleClickEvent = new object(); + static object NodeMouseHoverEvent = new object (); + static object RightToLeftLayoutChangedEvent = new object (); + + public event ItemDragEventHandler ItemDrag { + add { Events.AddHandler (ItemDragEvent, value); } + remove { Events.RemoveHandler (ItemDragEvent, value); } + } + + public event TreeViewEventHandler AfterCheck { + add { Events.AddHandler (AfterCheckEvent, value); } + remove { Events.RemoveHandler (AfterCheckEvent, value); } + } + + public event TreeViewEventHandler AfterCollapse { + add { Events.AddHandler (AfterCollapseEvent, value); } + remove { Events.RemoveHandler (AfterCollapseEvent, value); } + } + + public event TreeViewEventHandler AfterExpand { + add { Events.AddHandler (AfterExpandEvent, value); } + remove { Events.RemoveHandler (AfterExpandEvent, value); } + } + + public event NodeLabelEditEventHandler AfterLabelEdit { + add { Events.AddHandler (AfterLabelEditEvent, value); } + remove { Events.RemoveHandler (AfterLabelEditEvent, value); } + } + + public event TreeViewEventHandler AfterSelect { + add { Events.AddHandler (AfterSelectEvent, value); } + remove { Events.RemoveHandler (AfterSelectEvent, value); } + } + + public event TreeViewCancelEventHandler BeforeCheck { + add { Events.AddHandler (BeforeCheckEvent, value); } + remove { Events.RemoveHandler (BeforeCheckEvent, value); } + } + + public event TreeViewCancelEventHandler BeforeCollapse { + add { Events.AddHandler (BeforeCollapseEvent, value); } + remove { Events.RemoveHandler (BeforeCollapseEvent, value); } + } + + public event TreeViewCancelEventHandler BeforeExpand { + add { Events.AddHandler (BeforeExpandEvent, value); } + remove { Events.RemoveHandler (BeforeExpandEvent, value); } + } + + public event NodeLabelEditEventHandler BeforeLabelEdit { + add { Events.AddHandler (BeforeLabelEditEvent, value); } + remove { Events.RemoveHandler (BeforeLabelEditEvent, value); } + } + + public event TreeViewCancelEventHandler BeforeSelect { + add { Events.AddHandler (BeforeSelectEvent, value); } + remove { Events.RemoveHandler (BeforeSelectEvent, value); } + } + + public event DrawTreeNodeEventHandler DrawNode { + add { Events.AddHandler (DrawNodeEvent, value); } + remove { Events.RemoveHandler (DrawNodeEvent, value); } + } + + public event TreeNodeMouseClickEventHandler NodeMouseClick { + add { Events.AddHandler (NodeMouseClickEvent, value); } + remove { Events.RemoveHandler (NodeMouseClickEvent, value); } + } + + + public event TreeNodeMouseClickEventHandler NodeMouseDoubleClick { + add { Events.AddHandler (NodeMouseDoubleClickEvent, value); } + remove { Events.RemoveHandler (NodeMouseDoubleClickEvent, value); } + } + + public event TreeNodeMouseHoverEventHandler NodeMouseHover { + add { Events.AddHandler (NodeMouseHoverEvent, value); } + remove { Events.RemoveHandler (NodeMouseHoverEvent, value); } + } + + public event EventHandler RightToLeftLayoutChanged { + add { Events.AddHandler (RightToLeftLayoutChangedEvent, value); } + remove { Events.RemoveHandler (RightToLeftLayoutChangedEvent, value); } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageChanged { + add { base.BackgroundImageChanged += value; } + remove { base.BackgroundImageChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageLayoutChanged { + add { base.BackgroundImageLayoutChanged += value; } + remove { base.BackgroundImageLayoutChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler PaddingChanged { + add { base.PaddingChanged += value; } + remove { base.PaddingChanged -= value; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public new event PaintEventHandler Paint { + add { base.Paint += value; } + remove { base.Paint -= value; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + + #region UIA Framework Events + static object UIACheckBoxesChangedEvent = new object (); + + internal event EventHandler UIACheckBoxesChanged { + add { Events.AddHandler (UIACheckBoxesChangedEvent, value); } + remove { Events.RemoveHandler (UIACheckBoxesChangedEvent, value); } + } + + internal void OnUIACheckBoxesChanged (EventArgs e) + { + EventHandler eh = (EventHandler) Events [UIACheckBoxesChangedEvent]; + if (eh != null) + eh (this, e); + } + + static object UIALabelEditChangedEvent = new object (); + + internal event EventHandler UIALabelEditChanged { + add { Events.AddHandler (UIALabelEditChangedEvent, value); } + remove { Events.RemoveHandler (UIALabelEditChangedEvent, value); } + } + + internal void OnUIALabelEditChanged (EventArgs e) + { + EventHandler eh = (EventHandler) Events [UIALabelEditChangedEvent]; + if (eh != null) + eh (this, e); + } + + static object UIANodeTextChangedEvent = new object (); + + internal event TreeViewEventHandler UIANodeTextChanged { + add { Events.AddHandler (UIANodeTextChangedEvent, value); } + remove { Events.RemoveHandler (UIANodeTextChangedEvent, value); } + } + + internal void OnUIANodeTextChanged (TreeViewEventArgs e) + { + TreeViewEventHandler eh = + (TreeViewEventHandler) Events [UIANodeTextChangedEvent]; + if (eh != null) + eh (this, e); + } + + static object UIACollectionChangedEvent = new object (); + + internal event CollectionChangeEventHandler UIACollectionChanged { + add { Events.AddHandler (UIACollectionChangedEvent, value); } + remove { Events.RemoveHandler (UIACollectionChangedEvent, value); } + } + + internal void OnUIACollectionChanged (object sender, CollectionChangeEventArgs e) + { + CollectionChangeEventHandler eh = + (CollectionChangeEventHandler) Events [UIACollectionChangedEvent]; + if (eh != null) { + if (sender == root_node) + sender = this; + eh (sender, e); + } + } + #endregion // UIA Framework Events + #endregion // Events + } +} + + diff --git a/source/ShiftUI/Widgets/UserWidget.cs b/source/ShiftUI/Widgets/UserWidget.cs new file mode 100644 index 0000000..e0bb759 --- /dev/null +++ b/source/ShiftUI/Widgets/UserWidget.cs @@ -0,0 +1,236 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2005 Novell, Inc. +// +// Authors: +// Peter Bartok pbartok@novell.com +// + +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace ShiftUI { + [DefaultEvent("Load")] + [DesignerCategory("UserWidget")] + [Designer("ShiftUI.Design.WidgetDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [Designer("ShiftUI.Design.UserWidgetDocumentDesigner, " + Consts.AssemblySystem_Design, typeof(IRootDesigner))] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + public class UserWidget : ContainerWidget { + #region Public Constructors + public UserWidget() { + SetStyle (Widgetstyles.SupportsTransparentBackColor, true); + } + #endregion // Public Constructors + + #region Public Instance Properties + [Browsable (true)] + [EditorBrowsable (EditorBrowsableState.Always)] + [DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)] + public override bool AutoSize { + get { return base.AutoSize; } + set { base.AutoSize = value; } + } + + [Browsable (true)] + [LocalizableAttribute(true)] + [DefaultValue (AutoSizeMode.GrowOnly)] + public AutoSizeMode AutoSizeMode { + get { return base.GetAutoSizeMode (); } + set { + if (base.GetAutoSizeMode () != value) { + base.SetAutoSizeMode (value); + } + } + } + + [Browsable (true)] + [EditorBrowsable (EditorBrowsableState.Always)] + public override AutoValidate AutoValidate { + get { return base.AutoValidate; } + set { base.AutoValidate = value; } + } + + protected override Size DefaultSize { + get { + return new Size(150, 150); + } + } + + [Bindable(false)] + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override string Text { + get { + return base.Text; + } + + set { + base.Text = value; + } + } + #endregion // Public Instance Properties + + #region Public Instance Methods + [Browsable (true)] + [EditorBrowsable (EditorBrowsableState.Always)] + public override bool ValidateChildren () + { + return base.ValidateChildren (); + } + + [Browsable (true)] + [EditorBrowsable (EditorBrowsableState.Always)] + public override bool ValidateChildren (ValidationConstraints validationConstraints) + { + return base.ValidateChildren (validationConstraints); + } + #endregion + + #region Protected Instance Methods + [EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void OnCreateWidget() { + base.OnCreateWidget(); + + // The OnCreateWidget isn't neccessarily raised *before* it + // becomes first visible, but that's the best we've got + OnLoad(EventArgs.Empty); + } + + [EditorBrowsable(EditorBrowsableState.Advanced)] + protected virtual void OnLoad(EventArgs e) { + EventHandler eh = (EventHandler)(Events [LoadEvent]); + if (eh != null) + eh (this, e); + } + + [EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void OnMouseDown(MouseEventArgs e) { + base.OnMouseDown(e); + } + + [EditorBrowsable(EditorBrowsableState.Advanced)] + protected override void WndProc(ref Message m) { + switch ((Msg) m.Msg) { + case Msg.WM_SETFOCUS: + if (ActiveWidget == null) + SelectNextWidget (null, true, true, true, false); + base.WndProc (ref m); + break; + default: + base.WndProc (ref m); + break; + } + } + #endregion // Protected Instance Methods + + #region Protected Properties + protected override CreateParams CreateParams { + get { + CreateParams cp = base.CreateParams; + cp.Style |= (int)WindowStyles.WS_TABSTOP; + cp.ExStyle |= (int)WindowExStyles.WS_EX_WidgetPARENT; + return cp; + } + } + #endregion + + #region Events + static object LoadEvent = new object (); + + [Browsable (true)] + [EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler AutoSizeChanged { + add { base.AutoSizeChanged += value; } + remove { base.AutoSizeChanged -= value; } + } + + [Browsable (true)] + [EditorBrowsable (EditorBrowsableState.Always)] + public new event EventHandler AutoValidateChanged { + add { base.AutoValidateChanged += value; } + remove { base.AutoValidateChanged -= value; } + } + + public event EventHandler Load { + add { Events.AddHandler (LoadEvent, value); } + remove { Events.RemoveHandler (LoadEvent, value); } + } + + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + #endregion // Events + + protected override void OnResize (EventArgs e) + { + base.OnResize (e); + } + + [Browsable (true)] + [DefaultValue (BorderStyle.None)] + [EditorBrowsable (EditorBrowsableState.Always)] + public BorderStyle BorderStyle { + get { return InternalBorderStyle; } + set { InternalBorderStyle = value; } + } + + internal override Size GetPreferredSizeCore (Size proposedSize) + { + Size retsize = Size.Empty; + + // Add up the requested sizes for Docked controls + foreach (Widget child in Widgets) { + if (!child.is_visible) + continue; + + if (child.Dock == DockStyle.Left || child.Dock == DockStyle.Right) + retsize.Width += child.PreferredSize.Width; + else if (child.Dock == DockStyle.Top || child.Dock == DockStyle.Bottom) + retsize.Height += child.PreferredSize.Height; + } + + // See if any non-Docked control is positioned lower or more right than our size + foreach (Widget child in Widgets) { + if (!child.is_visible) + continue; + + if (child.Dock != DockStyle.None) + continue; + + // If its anchored to the bottom or right, that doesn't really count + if ((child.Anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom || (child.Anchor & AnchorStyles.Right) == AnchorStyles.Right) + continue; + + retsize.Width = Math.Max (retsize.Width, child.Bounds.Right + child.Margin.Right); + retsize.Height = Math.Max (retsize.Height, child.Bounds.Bottom + child.Margin.Bottom); + } + + return retsize; + } + } +} diff --git a/source/ShiftUI/Widgets/VScrollBar.cs b/source/ShiftUI/Widgets/VScrollBar.cs new file mode 100644 index 0000000..f458f66 --- /dev/null +++ b/source/ShiftUI/Widgets/VScrollBar.cs @@ -0,0 +1,79 @@ +// +// ShiftUI.HScrollBar.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (C) 2004-2005, Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez jordi@ximian.com +// + + +using System.Drawing; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI +{ + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ComVisible (true)] + public class VScrollBar : ScrollBar + { + #region events + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public new event EventHandler RightToLeftChanged { + add { base.RightToLeftChanged += value; } + remove { base.RightToLeftChanged -= value; } + } + + #endregion Events + + public VScrollBar() + { + vert = true; + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public override RightToLeft RightToLeft { + get { return base.RightToLeft; } + set { + if (RightToLeft == value) + return; + + base.RightToLeft = value; + + OnRightToLeftChanged (EventArgs.Empty); + } + } + + protected override Size DefaultSize { + get { return ThemeEngine.Current.VScrollBarDefaultSize; } + } + + protected override CreateParams CreateParams { + get { return base.CreateParams; } + } + } +} diff --git a/source/ShiftUI/keyboards.resources b/source/ShiftUI/keyboards.resources new file mode 100644 index 0000000..6f999ec Binary files /dev/null and b/source/ShiftUI/keyboards.resources differ diff --git a/source/WindowsFormsApplication1/Controls/WinFormsHost.cs b/source/WindowsFormsApplication1/Controls/WinFormsHost.cs new file mode 100644 index 0000000..e2be505 --- /dev/null +++ b/source/WindowsFormsApplication1/Controls/WinFormsHost.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ShiftUI; +using System.Reflection; +using System.Drawing; + +namespace ShiftOS.Controls +{ + class WinFormsHost : Widget + { + private System.Windows.Forms.Control guest = null; + + /// + /// Creates a new Windows Forms host that will host the given control. + /// + /// The control to use. + public WinFormsHost(System.Windows.Forms.Control ctrl) + { + guest = ctrl; + ScanProperties(); + } + + /// + /// Scan the guest for any properties that this widget contains, and set our properties to the ShiftUI equivalent. + /// + private void ScanProperties() + { + var guest_properties = guest.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); + var host_properties = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); + + var valid_types = new Type[] { typeof(string), typeof(int), typeof(Size), typeof(Point), typeof(Font), typeof(Color), typeof(bool) }; + + var guest_names = new Dictionary(); + var host_names = new Dictionary(); + + foreach(var property in guest_properties) + { + if (!property.CanWrite || !property.CanRead) + continue; //We want to be able to read and write from and to the property... + + if (!valid_types.Contains(property.PropertyType) || !property.PropertyType.IsEnum) + continue; //Need to be valid propertytype... + + guest_names.Add(property.Name, property); //Add to the guest dictionary for easy access. + } + + //Now let's do the same for our host. + foreach (var property in host_properties) + { + if (!property.CanWrite || !property.CanRead) + continue; //We want to be able to read and write from and to the property... + + if (!valid_types.Contains(property.PropertyType) || !property.PropertyType.IsEnum) + continue; //Need to be valid propertytype... + + host_names.Add(property.Name, property); //Add to the guest dictionary for easy access. + } + + //Cool. Properties scanned. Let's set our properties to the guest's! + foreach(var property in host_names) + { + if(guest_names.ContainsKey(property.Key)) + { + var p = guest_names[property.Key]; + if(p.PropertyType.IsEnum) + { + //If it's an enum, convert it to an integer value + //so that Reflection won't yell at us. + + var value = p.GetValue(guest); //Get the guest's value of this property + int value_int = (int)value; + property.Value.SetValue(this, value_int); + } + else + { + var value = p.GetValue(guest); + property.Value.SetValue(this, value); + } + } + } + } + } +} diff --git a/source/WindowsFormsApplication1/ShiftOS.csproj b/source/WindowsFormsApplication1/ShiftOS.csproj index 8e10ef6..3e2d172 100644 --- a/source/WindowsFormsApplication1/ShiftOS.csproj +++ b/source/WindowsFormsApplication1/ShiftOS.csproj @@ -109,6 +109,9 @@ Component + + Component + Form -- cgit v1.2.3